This project is the first winner on 2020 NXP Cup Electromaker Innovation Challenge contest.
This code should supply all functions to control all peripherals from main code and get all informations from all sensors.
Code:
#ifndef __TFC_H__
#define __TFC_H__
#include "fsl_ftm.h"
#include "fsl_i2c.h"
#include "fsl_adc16.h"
#include "fsl_pit.h"
#include "fsl_uart.h"
#include "fsl_dspi.h"
#define SERVO_MODULO 9375 // (ftmClock / pwmFreq_Hz) - 1
volatile unsigned int servoPos = 0; // access this variable to set servo pos
volatile unsigned int laserPos = 655;
void setupServo(int startupVal) {
servoPos = 700 + startupVal;
ftm_config_t ftmConfig;
FTM_GetDefaultConfig(&ftmConfig);
ftmConfig.prescale = kFTM_Prescale_Divide_128;
FTM_Init(FTM0, &ftmConfig);
FTM0->SC &= ~FTM_SC_CPWMS_MASK;
FTM0->MOD = SERVO_MODULO;
/* Clear the current mode and edge level bits */
uint32_t reg = FTM0->CONTROLS[1].CnSC;
reg &= ~(FTM_CnSC_MSA_MASK | FTM_CnSC_MSB_MASK | FTM_CnSC_ELSA_MASK | FTM_CnSC_ELSB_MASK);
/* Setup the active level */
reg |= (uint32_t)kFTM_HighTrue << FTM_CnSC_ELSA_SHIFT;
/* Edge-aligned mode needs MSB to be 1, don't care for Center-aligned mode */
reg |= FTM_CnSC_MSB(1U);
/* Update the mode and edge level */
FTM0->CONTROLS[1].CnSC = reg;
FTM0->CONTROLS[1].CnV = servoPos;
/* Clear the current mode and edge level bits */
reg = FTM0->CONTROLS[2].CnSC;
reg &= ~(FTM_CnSC_MSA_MASK | FTM_CnSC_MSB_MASK | FTM_CnSC_ELSA_MASK | FTM_CnSC_ELSB_MASK);
/* Setup the active level */
reg |= (uint32_t)kFTM_HighTrue << FTM_CnSC_ELSA_SHIFT;
/* Edge-aligned mode needs MSB to be 1, don't care for Center-aligned mode */
reg |= FTM_CnSC_MSB(1U);
/* Update the mode and edge level */
FTM0->CONTROLS[2].CnSC = reg;
FTM0->CONTROLS[2].CnV = servoPos;
FTM0->SC |= FTM_SC_TOIE_MASK; // enable FTM0 overflow iterrupt
PORTC->PCR[2] = PORT_PCR_MUX(4);
PORTC->PCR[3] = PORT_PCR_MUX(4);
FTM_StartTimer(FTM0, kFTM_SystemClock);
NVIC_EnableIRQ(FTM0_IRQn);
FTM_EnableInterrupts(FTM0, kFTM_TimeOverflowInterruptEnable);
}
char getLaserState() {
// TODO
return 0;
}
void setServoPos(int pos) {
servoPos = 700 + pos;
}
void setLaserPos(unsigned int pos) {
laserPos = pos;
}
/*extern */volatile short noSee;
char isLaserDecreasing = 0;
char isLaserSearching = 0;
volatile char isObstacleUpdated = 0;
volatile int obstaclePos = 0;
volatile int endObstaclePos = 0;
volatile int obstacleSize = 0;
volatile char isObtacleHere = 0;
char __laserColisonStarted = 0;
int __laserColisionBegin = 0;
extern "C" {
void FTM0_IRQHandler(void) {
if(!(FTM0->SC&FTM_SC_TOF_MASK)) return;
FTM0->SC &= ~(FTM_SC_TOF_MASK);
FTM0->CONTROLS[1].CnV = servoPos;
if(isLaserSearching) {
char currentLaserState = getLaserState();
if(!__laserColisonStarted && currentLaserState) {
__laserColisonStarted = 1;
__laserColisionBegin = laserPos;
isObtacleHere = 1;
} else if(__laserColisonStarted && !currentLaserState) {
__laserColisonStarted = 0;
isLaserDecreasing = !isLaserDecreasing;
isObstacleUpdated = 1;
isObtacleHere = 1;
obstacleSize = __laserColisionBegin - laserPos;
if(obstacleSize<0) {
obstacleSize = -obstacleSize;
}
obstacleSize >>= 1;
//obstaclePos = __laserColisionBegin + laserPos;
int middleDistanceOld = __laserColisionBegin - 543;
int middleDistanceNew = laserPos - 543;
if(middleDistanceOld<0) middleDistanceOld = -middleDistanceOld;
if(middleDistanceNew<0) middleDistanceNew = -middleDistanceNew;
if(middleDistanceOld<middleDistanceNew) {
obstaclePos = __laserColisionBegin<<1;
endObstaclePos = laserPos;
} else {
obstaclePos = laserPos<<1;
endObstaclePos = __laserColisionBegin;
}
obstaclePos >>= 1;
obstaclePos -= 543; // based on servo middle
obstaclePos = -obstaclePos;
endObstaclePos -= 543; // based on servo middle
endObstaclePos = -obstaclePos;
}
if(!isLaserDecreasing) {
if(__laserColisonStarted) {
laserPos += 20;
} else {
laserPos += 3; //30;
}
} else {
if(__laserColisonStarted) {
laserPos -= 20;
} else {
laserPos -= 3; //30;
}
}
// https://servodatabase.com/servo/towerpro/sg90
// 0,5ms to 2,5ms
if(laserPos<=187) { // 187
isLaserDecreasing = 0;
if(__laserColisonStarted) {
__laserColisonStarted = 0;
isObstacleUpdated = 1;
isObtacleHere = 1;
obstacleSize = __laserColisionBegin - laserPos;
if(obstacleSize<0) {
obstacleSize = -obstacleSize;
}
obstacleSize >>= 1;
//obstaclePos = __laserColisionBegin + laserPos;
int middleDistanceOld = __laserColisionBegin - 543;
int middleDistanceNew = laserPos - 543;
if(middleDistanceOld<0) middleDistanceOld = -middleDistanceOld;
if(middleDistanceNew<0) middleDistanceNew = -middleDistanceNew;
if(middleDistanceOld<middleDistanceNew) {
obstaclePos = __laserColisionBegin<<1;
endObstaclePos = laserPos;
} else {
obstaclePos = laserPos<<1;
endObstaclePos = __laserColisionBegin;
}
obstaclePos >>= 1;
obstaclePos -= 543; // based on servo middle
obstaclePos = -obstaclePos;
endObstaclePos -= 543; // based on servo middle
endObstaclePos = -obstaclePos;
} else {
isObtacleHere = 0;
obstacleSize = 0;
obstaclePos = 0;
endObstaclePos = 0;
}
} else if(laserPos>=900) { // 938
isLaserDecreasing = 1;
if(__laserColisonStarted) {
__laserColisonStarted = 0;
isObstacleUpdated = 1;
isObtacleHere = 1;
obstacleSize = __laserColisionBegin - laserPos;
if(obstacleSize<0) {
obstacleSize = -obstacleSize;
}
obstacleSize>>=1;
//obstaclePos = __laserColisionBegin + laserPos;
int middleDistanceOld = __laserColisionBegin - 543;
int middleDistanceNew = laserPos - 543;
if(middleDistanceOld<0) middleDistanceOld = -middleDistanceOld;
if(middleDistanceNew<0) middleDistanceNew = -middleDistanceNew;
if(middleDistanceOld<middleDistanceNew) {
obstaclePos = __laserColisionBegin<<1;
endObstaclePos = laserPos;
} else {
obstaclePos = laserPos<<1;
endObstaclePos = __laserColisionBegin;
}
obstaclePos >>= 1;
obstaclePos -= 543; // based on servo middle
obstaclePos = -obstaclePos;
endObstaclePos -= 543; // based on servo middle
endObstaclePos = -obstaclePos;
} else {
isObtacleHere = 0;
obstacleSize = 0;
obstaclePos = 0;
endObstaclePos = 0;
}
}
}
FTM0->CONTROLS[2].CnV = laserPos; // we set servo at right time to prevent bad output
FTM0->SYNC |= 1 << 7; // trigger SW sync
noSee++;
}
}
namespace Motor {
const unsigned int MOTOR_MODULO = 1000;
volatile int rMotorSpeed = 0;
volatile int lMotorSpeed = 0;
void initMotorChannel(int channel) {
/* Clear the current mode and edge level bits */
uint32_t reg = FTM3->CONTROLS[channel].CnSC;
reg &= ~(FTM_CnSC_MSA_MASK | FTM_CnSC_MSB_MASK | FTM_CnSC_ELSA_MASK | FTM_CnSC_ELSB_MASK);
/* Setup the active level */
reg |= (uint32_t)(kFTM_HighTrue << FTM_CnSC_ELSA_SHIFT);
/* Edge-aligned mode needs MSB to be 1, don't care for Center-aligned mode */
reg |= FTM_CnSC_MSB(1U);
/* Update the mode and edge level */
FTM3->CONTROLS[channel].CnSC = reg;
}
void setup() {
ftm_config_t ftmConfig;
FTM_GetDefaultConfig(&ftmConfig);
ftmConfig.prescale = kFTM_Prescale_Divide_64;
FTM_Init(FTM3, &ftmConfig);
FTM3->SC &= ~FTM_SC_CPWMS_MASK;
FTM3->MOD = MOTOR_MODULO;
// MOTOR R: ch4, ch5
// MOTOR L: ch1, ch0
initMotorChannel(0);
initMotorChannel(1);
initMotorChannel(4);
initMotorChannel(5);
ftm_chnl_pwm_signal_param_t pwmPar;
pwmPar.chnlNumber = kFTM_Chnl_0;
pwmPar.dutyCyclePercent = 0;
pwmPar.enableDeadtime = false;
pwmPar.firstEdgeDelayPercent = 0;
pwmPar.level = kFTM_HighTrue;
FTM_SetupPwm(FTM3, &pwmPar, 1, kFTM_EdgeAlignedPwm, 1000, 60000000);
//int startupVal = MOTOR_MODULO >> 1; // MOTOR_MODULO / 2 for ability of back riding; 0 for forward only; MOTOR_MODULO for backward only
FTM3->CONTROLS[1].CnV = 0;
FTM3->CONTROLS[0].CnV = 0;
FTM3->CONTROLS[4].CnV = 0;
FTM3->CONTROLS[5].CnV = 0;
FTM_StartTimer(FTM3, kFTM_SystemClock);
PORTD->PCR[0] = PORT_PCR_MUX(4);
PORTD->PCR[1] = PORT_PCR_MUX(4);
PORTC->PCR[8] = PORT_PCR_MUX(3);
PORTC->PCR[9] = PORT_PCR_MUX(3);
FTM_StartTimer(FTM3, kFTM_SystemClock);
NVIC_EnableIRQ(FTM3_IRQn);
FTM_EnableInterrupts(FTM3, kFTM_TimeOverflowInterruptEnable);
}
inline void setLMotorSpeed(int speed) {
lMotorSpeed = speed;
}
inline void setRMotorSpeed(int speed) {
rMotorSpeed = speed;
}
};
extern "C" {
void FTM3_IRQHandler() { // we need FTM3 interrupt, to update CnV to fix double update
if(!(FTM3->SC&FTM_SC_TOF_MASK)) return;
FTM3->SC &= ~(FTM_SC_TOF_MASK);
int lSpeed = Motor::lMotorSpeed;
if(lSpeed >= 0) {
FTM3->CONTROLS[1].CnV = lSpeed;
FTM3->CONTROLS[0].CnV = 0;
} else {
FTM3->CONTROLS[1].CnV = 0;
FTM3->CONTROLS[0].CnV = -lSpeed;
}
int rSpeed = Motor::rMotorSpeed;
if(rSpeed >= 0) {
FTM3->CONTROLS[4].CnV = rSpeed;
FTM3->CONTROLS[5].CnV = 0;
} else {
FTM3->CONTROLS[4].CnV = 0;
FTM3->CONTROLS[5].CnV = -rSpeed;
}
FTM3->SYNC |= 1 << 7; // trigger SW sync
}
}
void init_ADC16(void){
adc16_config_t config;
ADC16_GetDefaultConfig(&config);
config.resolution = kADC16_ResolutionSE10Bit;
config.enableHighSpeed = true;
ADC16_Init(ADC0, &config);
ADC16_DoAutoCalibration(ADC0);
}
volatile unsigned char cameraPulseState = 0;
volatile unsigned char generateSI = 0;
volatile unsigned int cameraScanTime = 50000;
volatile unsigned char currentCameraSwapBuffer = 0;
volatile unsigned short cameraData[2][128]; // 2 swap buffers
volatile unsigned char isCameraBufferReady[2] = {0};
volatile char isCameraPeriodReady = 0;
volatile unsigned char cameraPeriodWriteCount[2];
inline void enablePIT(pit_chnl_t channel, uint32_t count) {
PIT_StopTimer(PIT, channel);
PIT_DisableInterrupts(PIT, channel, kPIT_TimerInterruptEnable);
PIT_SetTimerPeriod(PIT, channel, count);
PIT_StartTimer(PIT, channel);
PIT_EnableInterrupts(PIT, channel, kPIT_TimerInterruptEnable);
EnableIRQ(PIT0_IRQn);
EnableIRQ(PIT1_IRQn);
EnableIRQ(PIT2_IRQn);
EnableIRQ(PIT3_IRQn);
}
void setupCamera() {
init_ADC16();
PORTB->PCR[2] = PORT_PCR_MUX(0); // Camera ADC
PORTC->PCR[7] = PORT_PCR_MUX(1); // Camera CLK
PORTC->PCR[0] = PORT_PCR_MUX(1); // Camera SI
PORTB->PCR[3] = PORT_PCR_MUX(1);// (0) // Camera ADC2 // it will work as switch for stepper detector
PORTB->PCR[3] = PORT_PCR_MUX(1) | (1 << 24); // GPIO
GPIOB->PDDR &= ~(1 << 3);
PORTD->PCR[3] = PORT_PCR_MUX(1); // Camera CLK2
PORTC->PCR[12] = PORT_PCR_MUX(1); // Camera SI2
GPIOC->PCOR |= 1 << 7;
GPIOC->PCOR |= 1 << 0;
GPIOD->PCOR |= 1 << 3;
GPIOC->PCOR |= 1 << 12;
GPIOC->PDDR |= 1 << 7;
GPIOC->PDDR |= 1 << 0;
GPIOD->PDDR |= 1 << 3;
GPIOC->PDDR |= 1 << 12;
pit_config_t pitConfig;
pitConfig.enableRunInDebug = false;
PIT_Init(PIT, &pitConfig);
enablePIT(kPIT_Chnl_1, cameraScanTime);
enablePIT(kPIT_Chnl_0, 600000); // 100x per second
}
volatile unsigned int time = 0;
char antiFlickerSyncType = 0;
extern "C" {
void PIT_CHANNEL_0_IRQHANDLER(void) {
if(PIT->CHANNEL[0].TFLG & PIT_TFLG_TIF_MASK) {
PIT->CHANNEL[0].TFLG = PIT_TFLG_TIF_MASK;
for(int i=0; i<14; i++) {
if(((cameraScanTime+8000)>>i)<600000) { // 26
if(antiFlickerSyncType != i) {
antiFlickerSyncType = i;
enablePIT(kPIT_Chnl_0, 600000<<i);
}
break;
}
}
time += 1<<antiFlickerSyncType;
isCameraPeriodReady = 1;
GPIOC->PSOR |= 1 << 0; // set SI high
GPIOC->PSOR |= 1 << 12; // set SI2 high
for(int j=8; j!=0; --j) __asm("NOP"); // 4*3 clocks
GPIOC->PSOR |= 1 << 7; // set clock high
GPIOD->PSOR |= 1 << 3; // set clock2 high
for(int j=8; j!=0; --j) __asm("NOP"); // 4*3 clocks
GPIOC->PCOR |= 1 << 0; // set SI low
GPIOC->PCOR |= 1 << 12; // set SI2 low
for(int j=8; j!=0; --j) __asm("NOP"); // 4*3 clocks
for(int i=0; i<18; ++i) {
GPIOC->PCOR |= 1 << 7; // set clock low
GPIOD->PCOR |= 1 << 3; // set clock2 low
for(int j=8; j!=0; --j) __asm("NOP"); // 4*3 clocks
GPIOC->PSOR |= 1 << 7; // set clock high
GPIOD->PSOR |= 1 << 3; // set clock2 high
for(int j=8; j!=0; --j) __asm("NOP"); // 4*3 clocks
}
enablePIT(kPIT_Chnl_1, cameraScanTime);
for(int i=0; i<112; ++i) {
GPIOC->PCOR |= 1 << 7; // set clock low
GPIOD->PCOR |= 1 << 3; // set clock2 low
for(int j=8; j!=0; --j) __asm("NOP"); // 4*3 clocks
GPIOC->PSOR |= 1 << 7; // set clock high
GPIOD->PSOR |= 1 << 3; // set clock2 high
for(int j=8; j!=0; --j) __asm("NOP"); // 4*3 clocks
}
GPIOC->PCOR |= 1 << 7; // set clock low
GPIOD->PCOR |= 1 << 3; // set clock2 low
PIT->CHANNEL[1].TFLG = PIT_TFLG_TIF_MASK;
}
}
}
extern "C" {
void PIT_CHANNEL_1_IRQHANDLER(void) {
if(PIT->CHANNEL[1].TFLG & PIT_TFLG_TIF_MASK) {
PIT->CHANNEL[1].TFLG = PIT_TFLG_TIF_MASK; // clear flag
#ifndef CAMERA_AVERAGING
enablePIT(kPIT_Chnl_1, 0xFFFFFFFF);
#endif
GPIOC->PSOR |= 1 << 0; // set SI high
GPIOC->PSOR |= 1 << 12; // set SI2 high
for(int j=15; j!=0; --j) __asm("NOP"); // 4*3 clocks
GPIOC->PSOR |= 1 << 7; // set clock high
GPIOD->PSOR |= 1 << 3; // set clock2 high
for(int j=15; j!=0; --j) __asm("NOP"); // 4*5 clocks
//ADC0_SC1A = AIEN_OFF | DIFF_SINGLE | ADC_SC1_ADCH(6);
ADC0->SC1[0] = ADC_SC1_AIEN(0) | ADC_SC1_DIFF(0) | ADC_SC1_ADCH(12);
GPIOC->PCOR |= 1 << 0; // set SI low
GPIOC->PCOR |= 1 << 12; // set SI2 low
for(int j=15; j!=0; --j) __asm("NOP"); // 4*3 clocks
for(int i=0; i<128; ++i) {
GPIOC->PCOR |= 1 << 7; // set clock low
GPIOD->PCOR |= 1 << 3; // set clock2 low
for(int j=15; j!=0; --j) __asm("NOP"); // 4*5 clocks
while(!(ADC0->SC1[0] & ADC_SC1_COCO_MASK));
short temp = ADC0->R[0];
//temp -= 60;
temp-=170; // 150
if(temp&0x800) {
temp = 0;
}
temp = (temp*3)>>1;
if(temp&0x700) {
temp = 0xFF;
}
#ifdef CAMERA_AVERAGING
if(cameraPeriodWriteCount[currentCameraSwapBuffer]) {
cameraData[currentCameraSwapBuffer][i] += temp;
} else {
cameraData[currentCameraSwapBuffer][i] = temp;
}
#else
cameraData[currentCameraSwapBuffer][i] = temp;
#endif
GPIOC->PSOR |= 1 << 7; // set clock high
GPIOD->PSOR |= 1 << 3; // set clock2 high
for(int j=15; j!=0; --j) __asm("NOP"); // 4*5 clocks
ADC0->SC1[0] = ADC_SC1_AIEN(0) | ADC_SC1_DIFF(0) | ADC_SC1_ADCH(12);
}
isCameraBufferReady[currentCameraSwapBuffer] = 1;
GPIOC->PCOR |= 1 << 7; // set clock low
GPIOD->PCOR |= 1 << 3; // set clock2 low
for(int j=15; j!=0; --j) __asm("NOP"); // 4*5 clocks
GPIOC->PSOR |= 1 << 7; // set clock high
GPIOD->PSOR |= 1 << 3; // set clock2 high
for(int j=15; j!=0; --j) __asm("NOP"); // 4*5 clocks
GPIOC->PCOR |= 1 << 7; // set clock low
GPIOD->PCOR |= 1 << 3; // set clock2 low
#ifdef CAMERA_AVERAGING
cameraPeriodWriteCount[currentCameraSwapBuffer]++;
#endif
}
}
}
// pointer obtained by getNextImage is valid till next call of getNextImage
unsigned short* getNextImage() { // will return null if there is no image yet
unsigned char oldBuffer = currentCameraSwapBuffer;
if(isCameraBufferReady[oldBuffer] && isCameraPeriodReady) {
// we need to change current buffer without changing current buffer
// to value which is bigger than bufferCount - 1
currentCameraSwapBuffer ^= 1;
isCameraBufferReady[oldBuffer] = 0;
unsigned short* oldData = (unsigned short*)cameraData[oldBuffer];
#ifdef CAMERA_AVERAGING
unsigned char writeCount = cameraPeriodWriteCount[oldBuffer];
for(int i = 0; i<128; i++) {
oldData[i] = oldData[i]/writeCount;
}
cameraPeriodWriteCount[oldBuffer] = 0;
#endif
isCameraPeriodReady = 0;
return oldData;
}
return 0;
}
// info about camera values, updated at call of calibrateCamera
unsigned char cameraMinValue = 0;
unsigned char cameraMaxValue = 0;
unsigned char cameraMiddleValue = 0;
void calibrateCamera(unsigned short* cameraData) {
unsigned int minVal = 1020;
unsigned int maxVal = 0;
for(int j=125; j; j--) {
unsigned short average = ((unsigned short)cameraData[j+0]) + ((unsigned short)cameraData[j+1]) + ((unsigned short)cameraData[j+2]) + ((unsigned short)cameraData[j+3]);
if(average > maxVal ) {
maxVal = average;
} else if(average < minVal ) {
minVal = average;
}
}
if(minVal == 0 && maxVal == 1020) {
return;
}
int middle = minVal + maxVal;
if(middle < 8) middle = 8;
cameraScanTime *= 1024.0f / (float)middle;
}
void cameraInitialCalibration() {
for(int i=0; i<40;) {
unsigned short* cameraData = getNextImage();
if(cameraData) {
i++;
calibrateCamera(cameraData);
}
}
}
void initI2C() {
i2c_master_config_t config = {
.enableMaster = true,
.enableStopHold = false,
.baudRate_Bps = 400000,
.glitchFilterWidth = 0
};
I2C_MasterInit(I2C0, &config, 12000000U);
PORTE->PCR[24] = PORT_PCR_MUX(5);
PORTE->PCR[25] = PORT_PCR_MUX(5);
}
void setupIOExpander() {
uint8_t data[] = { 6, 0b11111111, 0b10111111 }; // 1 = input, 0 = output
i2c_master_transfer_t transfer;
transfer.flags = kI2C_TransferDefaultFlag;
transfer.slaveAddress = 0x24;
transfer.direction = kI2C_Write;
transfer.subaddress = 0;
transfer.subaddressSize = 0;
transfer.data = data;
transfer.dataSize = sizeof(data);
I2C_MasterTransferBlocking(I2C0, &transfer);
PORTC->PCR[1] = PORT_PCR_MUX(1) | (1 << 24) | (0b1010 << 16); // GPIO + interrupt + falling edge interrupt type
GPIOC->PDDR &= ~(1 << 1);
}
struct ExpanderData {
bool sw1 : 1;
bool sw2 : 1;
bool sw3 : 1;
bool sw4 : 1;
bool btn1 : 1;
bool btn2 : 1;
bool btn3 : 1;
bool btn4 : 1;
bool btn5 : 1;
bool btKey : 1;
bool btState : 1;
bool undef1 : 1;
bool undef2 : 1;
bool undef3 : 1;
bool undef4 : 1;
bool undef5 : 1;
};
ExpanderData readIOExapnder() {
ExpanderData data;
i2c_master_transfer_t transfer;
transfer.flags = kI2C_TransferDefaultFlag;
transfer.slaveAddress = 0x24;
transfer.direction = kI2C_Read;
transfer.subaddress = 0;
transfer.subaddressSize = 1;
transfer.data = (uint8_t*)&data;
transfer.dataSize = 2;
I2C_MasterTransferBlocking(I2C0, &transfer);
return data;
}
void setupGyroscope() {
uint8_t data[] = { 0x13, 0b00000010 }; // CTRL_REG1[ACTIVE] = 1
i2c_master_transfer_t transfer;
transfer.flags = kI2C_TransferDefaultFlag;
transfer.slaveAddress = 0x20;
transfer.direction = kI2C_Write;
transfer.subaddress = 0;
transfer.subaddressSize = 0;
transfer.data = data;
transfer.dataSize = sizeof(data);
I2C_MasterTransferBlocking(I2C0, &transfer);
PORTB->PCR[20] = PORT_PCR_MUX(1) | (1 << 24) | (0b1010 << 16); // INT1 // GPIO + interrupt + falling edge interrupt type
GPIOB->PDDR &= ~(1 << 20);
PORTE->PCR[26] = PORT_PCR_MUX(1) | (1 << 24) | (0b1010 << 16); // INT2 // GPIO + interrupt + falling edge interrupt type
GPIOE->PDDR &= ~(1 << 26);
}
void setupAccelerometerAndMagnetometer() {
const int commandLen = 2;
const int commandCount = 5;
uint8_t data[commandCount][commandLen] = {
{ 0x2A, 0b00000000 }, // set to standy mode
{ 0x5B, 0b00011111 }, // setup magnetometer
{ 0x5C, 0b00100000 }, // setup magnetometer part 2
{ 0x0E, 0b00000001 }, // set accelerometer range
{ 0x2A, 0b00001101 } // launch accelerometer
};
i2c_master_transfer_t transfer;
transfer.flags = kI2C_TransferDefaultFlag;
transfer.slaveAddress = 0x20;
transfer.direction = kI2C_Write;
transfer.subaddress = 0;
transfer.subaddressSize = 0;
for(int i=0; i<commandCount; i++) {
transfer.data = data[i];
transfer.dataSize = commandLen;
I2C_MasterTransferBlocking(I2C0, &transfer);
}
{
const int commandLen = 2;
const int commandCount = 1;
uint8_t data[commandCount][commandLen] = {
{ 0x00, 0b00000000 }
};
i2c_master_transfer_t transfer;
transfer.flags = kI2C_TransferDefaultFlag;
transfer.slaveAddress = 0x20;
transfer.direction = kI2C_Read;
transfer.subaddress = 0;
transfer.subaddressSize = 0;
for(int i=0; i<commandCount; i++) {
transfer.data = data[i];
transfer.dataSize = commandLen;
I2C_MasterTransferBlocking(I2C0, &transfer);
}
}
}
namespace Bluetooth {
void setup() {
uart_config_t uartConfig;
uartConfig.baudRate_Bps = 9600;
uartConfig.parityMode = kUART_ParityDisabled;
uartConfig.stopBitCount = kUART_OneStopBit;
uartConfig.txFifoWatermark = 0;
uartConfig.rxFifoWatermark = 1;
uartConfig.enableRxRTS = false;
uartConfig.enableTxCTS = false;
uartConfig.idleType = kUART_IdleTypeStartBit;
uartConfig.enableTx = true;
uartConfig.enableRx = true;
UART_Init(UART3, &uartConfig, 60000000);
PORTC->PCR[16] = PORT_PCR_MUX(3);
PORTC->PCR[17] = PORT_PCR_MUX(3);
}
void print(char* text) {
while (*text)
{
while (!(UART3->S1 & UART_S1_TDRE_MASK));
UART3->D = *(text++);
}
while (!(UART3->S1 & UART_S1_TDRE_MASK));
}
void print(char ch) {
while (!(UART3->S1 & UART_S1_TDRE_MASK));
UART3->D = ch;
while (!(UART3->S1 & UART_S1_TDRE_MASK));
}
void print(int i) {
char text[16];
itoa(i, text, 10);
print(text);
}
void printLn(char* text) {
print(text);
print('\n');
}
};
namespace Stepper {
uint8_t state = 0;
int position = 0;
int desiredPosition = 0;
const uint8_t positionsB[] = {
0b01,
0b11,
0b10,
0b10,
0b00,
0b00,
0b00,
0b01
};
const uint8_t positionsC[] = {
0b00,
0b00,
0b00,
0b10,
0b10,
0b11,
0b01,
0b01
};
char getEndState() {
return (GPIOB->PDIR & (1 << 3)) >> 3;
}
void unsafeStepUp() {
state++;
state &= 0x07;
GPIOB->PSOR = positionsB[state] << 10;
GPIOB->PCOR = ((~positionsB[state])&3) << 10;
GPIOC->PSOR = positionsC[state] << 10;
GPIOC->PCOR = ((~positionsC[state])&3) << 10;
position++;
}
void stepUp() {
if(position < 1000) {
unsafeStepUp();
}
}
void unsafeStepDown() {
state--;
state &= 0x07;
GPIOB->PSOR = positionsB[state] << 10;
GPIOB->PCOR = ((~positionsB[state])&3) << 10;
GPIOC->PSOR = positionsC[state] << 10;
GPIOC->PCOR = ((~positionsC[state])&3) << 10;
position--;
}
void stepDown() {
if(position > 0) {
unsafeStepDown();
}
}
void calibrate() {
while(!getEndState()) {
unsafeStepDown();
for(int i=0; i<10000; i++) {
__asm("NOP");
}
}
position = 0;
}
void setup() {
PORTB->PCR[10] = PORT_PCR_MUX(1);
PORTB->PCR[11] = PORT_PCR_MUX(1);
PORTC->PCR[11] = PORT_PCR_MUX(1);
PORTC->PCR[10] = PORT_PCR_MUX(1);
GPIOB->PSOR |= 1 << 10;
GPIOB->PCOR |= 1 << 11;
GPIOC->PCOR |= 1 << 11;
GPIOC->PCOR |= 1 << 10;
GPIOB->PDDR |= 1 << 10;
GPIOB->PDDR |= 1 << 11;
GPIOC->PDDR |= 1 << 11;
GPIOC->PDDR |= 1 << 10;
calibrate();
enablePIT(kPIT_Chnl_2, 600000);
}
};
extern "C" {
void PIT_CHANNEL_2_IRQHANDLER(void) {
if(PIT->CHANNEL[2].TFLG & PIT_TFLG_TIF_MASK) {
PIT->CHANNEL[2].TFLG = PIT_TFLG_TIF_MASK;
if(Stepper::desiredPosition != Stepper::position) {
if(Stepper::desiredPosition<Stepper::position) {
Stepper::stepDown();
} else {
Stepper::stepUp();
}
}
}
}
}
extern void onEncoderUpdate();
namespace Encoder {
float currentSpeed = 0.0f;
float readsPerSecond = 20.0f;
void setup() {
ftm_config_t ftmInfo;
FTM_GetDefaultConfig(&ftmInfo);
FTM_Init(FTM2, &ftmInfo);
FTM_SetQuadDecoderModuloValue(FTM2, 0, -1);
ftm_phase_params_t phaseOptions;
phaseOptions.phasePolarity = kFTM_QuadPhaseNormal;
phaseOptions.enablePhaseFilter = false;
phaseOptions.phaseFilterVal = 0;
FTM_SetupQuadDecode(FTM2, &phaseOptions, &phaseOptions, kFTM_QuadPhaseEncode);
PORTB->PCR[18] = PORT_PCR_MUX(6); // ENC1A
PORTB->PCR[19] = PORT_PCR_MUX(6); // ENC1B
PORTA->PCR[2] = PORT_PCR_MUX(1); // ENC2A
PORTB->PCR[23] = PORT_PCR_MUX(1); // ENC2B
enablePIT(kPIT_Chnl_3, 60000000/readsPerSecond);
}
int read() {
int encoderCount = (int16_t)FTM_GetQuadDecoderCounterValue(FTM2);
/* Clear counter */
FTM_ClearQuadDecoderCounterValue(FTM2);
/* Read direction */
/*if (!(FTM_GetQuadDecoderFlags(FTM2) & kFTM_QuadDecoderCountingIncreaseFlag)) {
encoderCount = -encoderCount;
}*/
return encoderCount;
}
};
extern "C" {
void PIT_CHANNEL_3_IRQHANDLER(void) {
if(PIT->CHANNEL[3].TFLG & PIT_TFLG_TIF_MASK) {
PIT->CHANNEL[3].TFLG = PIT_TFLG_TIF_MASK;
Encoder::currentSpeed = Encoder::read()*Encoder::readsPerSecond;
onEncoderUpdate();
}
}
}
#include "u8g2.h"
namespace Display {
u8g2_t u8g2;
uint8_t u8x8_gpio_and_delay(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
{
int waitClocks;
switch(msg)
{
case U8X8_MSG_GPIO_AND_DELAY_INIT: // called once during init phase of u8g2/u8x8
PORTC->PCR[5] = PORT_PCR_MUX(2); // SCK
PORTA->PCR[1] = PORT_PCR_MUX(1); // RES
PORTB->PCR[9] = PORT_PCR_MUX(1); // CS
PORTC->PCR[4] = PORT_PCR_MUX(1); // DC
PORTD->PCR[2] = PORT_PCR_MUX(2); // SDA
GPIOA->PDDR |= 1 << 1; // RES
GPIOB->PDDR |= 1 << 9; // CS
GPIOC->PDDR |= 1 << 4; // DC
break; // can be used to setup pins
case U8X8_MSG_DELAY_NANO: // delay arg_int * 1 nano second
waitClocks = arg_int*40/1000;
for(int i=0; i<waitClocks; i++) __asm("NOP");
break;
case U8X8_MSG_DELAY_100NANO: // delay arg_int * 100 nano seconds
waitClocks = arg_int*40/10;
for(int i=0; i<waitClocks; i++) __asm("NOP");
break;
case U8X8_MSG_DELAY_10MICRO: // delay arg_int * 10 micro seconds
waitClocks = arg_int*40*10;
for(int i=0; i<waitClocks; i++) __asm("NOP");
break;
case U8X8_MSG_DELAY_MILLI: // delay arg_int * 1 milli second
waitClocks = arg_int*40*1000;
for(int i=0; i<waitClocks; i++) __asm("NOP");
break;
case U8X8_MSG_DELAY_I2C: // arg_int is the I2C speed in 100KHz, e.g. 4 = 400 KHz
break; // arg_int=1: delay by 5us, arg_int = 4: delay by 1.25us
case U8X8_MSG_GPIO_D0: // D0 or SPI clock pin: Output level in arg_int
//case U8X8_MSG_GPIO_SPI_CLOCK:
break;
case U8X8_MSG_GPIO_D1: // D1 or SPI data pin: Output level in arg_int
//case U8X8_MSG_GPIO_SPI_DATA:
break;
case U8X8_MSG_GPIO_D2: // D2 pin: Output level in arg_int
break;
case U8X8_MSG_GPIO_D3: // D3 pin: Output level in arg_int
break;
case U8X8_MSG_GPIO_D4: // D4 pin: Output level in arg_int
break;
case U8X8_MSG_GPIO_D5: // D5 pin: Output level in arg_int
break;
case U8X8_MSG_GPIO_D6: // D6 pin: Output level in arg_int
break;
case U8X8_MSG_GPIO_D7: // D7 pin: Output level in arg_int
break;
case U8X8_MSG_GPIO_E: // E/WR pin: Output level in arg_int
break;
case U8X8_MSG_GPIO_CS: // CS (chip select) pin: Output level in arg_int
if(arg_int) {
GPIOB->PSOR |= 1 << 9;
} else {
GPIOB->PCOR |= 1 << 9;
}
break;
case U8X8_MSG_GPIO_DC: // DC (data/cmd, A0, register select) pin: Output level in arg_int
if(arg_int) {
GPIOC->PSOR |= 1 << 4;
} else {
GPIOC->PCOR |= 1 << 4;
}
break;
case U8X8_MSG_GPIO_RESET: // Reset pin: Output level in arg_int
if(arg_int) {
GPIOA->PSOR |= 1 << 1;
} else {
GPIOA->PCOR |= 1 << 1;
}
break;
case U8X8_MSG_GPIO_CS1: // CS1 (chip select) pin: Output level in arg_int
break;
case U8X8_MSG_GPIO_CS2: // CS2 (chip select) pin: Output level in arg_int
break;
case U8X8_MSG_GPIO_I2C_CLOCK: // arg_int=0: Output low at I2C clock pin
break; // arg_int=1: Input dir with pullup high for I2C clock pin
case U8X8_MSG_GPIO_I2C_DATA: // arg_int=0: Output low at I2C data pin
break; // arg_int=1: Input dir with pullup high for I2C data pin
case U8X8_MSG_GPIO_MENU_SELECT:
u8x8_SetGPIOResult(u8x8, 0);
break;
case U8X8_MSG_GPIO_MENU_NEXT:
u8x8_SetGPIOResult(u8x8, 0);
break;
case U8X8_MSG_GPIO_MENU_PREV:
u8x8_SetGPIOResult(u8x8, 0);
break;
case U8X8_MSG_GPIO_MENU_HOME:
u8x8_SetGPIOResult(u8x8, 0);
break;
default:
u8x8_SetGPIOResult(u8x8, 1); // default return value
break;
}
return 1;
}
extern "C" uint8_t u8x8_byte_arduino_hw_spi(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr) {
switch(msg) {
case U8X8_MSG_BYTE_SEND:
dspi_transfer_t transferConfig;
transferConfig.dataSize = arg_int;
transferConfig.txData = (uint8_t *)arg_ptr;
transferConfig.rxData = NULL;
transferConfig.configFlags = 0;
DSPI_MasterTransferBlocking(SPI0, &transferConfig);
break;
case U8X8_MSG_BYTE_INIT:
dspi_master_config_t spiConfig;
spiConfig.whichCtar = kDSPI_Ctar0;
spiConfig.ctarConfig.baudRate = u8x8->display_info->sck_clock_hz;
spiConfig.ctarConfig.bitsPerFrame = 8;
if(u8x8->display_info->spi_mode&0x2) {
spiConfig.ctarConfig.cpol = static_cast<dspi_clock_polarity_t>(1);
} else {
spiConfig.ctarConfig.cpol = static_cast<dspi_clock_polarity_t>(0);
}
if(u8x8->display_info->spi_mode&0x1) {
spiConfig.ctarConfig.cpha = static_cast<dspi_clock_phase_t>(1);
} else {
spiConfig.ctarConfig.cpha = static_cast<dspi_clock_phase_t>(0);
}
spiConfig.ctarConfig.direction = kDSPI_MsbFirst;
spiConfig.ctarConfig.pcsToSckDelayInNanoSec = 10000;
spiConfig.ctarConfig.lastSckToPcsDelayInNanoSec = 10000;
spiConfig.ctarConfig.betweenTransferDelayInNanoSec = 10000;
spiConfig.whichPcs = kDSPI_Pcs0;
spiConfig.pcsActiveHighOrLow = kDSPI_PcsActiveLow;
spiConfig.enableContinuousSCK = false;
spiConfig.enableRxFifoOverWrite = false;
spiConfig.enableModifiedTimingFormat = false;
spiConfig.samplePoint = kDSPI_SckToSin0Clock;
DSPI_MasterInit(SPI0, &spiConfig, 60000000);
u8x8_gpio_SetCS(u8x8, u8x8->display_info->chip_disable_level);
break;
case U8X8_MSG_BYTE_SET_DC:
u8x8_gpio_SetDC(u8x8, arg_int);
break;
case U8X8_MSG_BYTE_START_TRANSFER:
u8x8_gpio_SetCS(u8x8, u8x8->display_info->chip_enable_level);
u8x8->gpio_and_delay_cb(u8x8, U8X8_MSG_DELAY_NANO, u8x8->display_info->post_chip_enable_wait_ns, NULL);
break;
case U8X8_MSG_BYTE_END_TRANSFER:
u8x8->gpio_and_delay_cb(u8x8, U8X8_MSG_DELAY_NANO, u8x8->display_info->pre_chip_disable_wait_ns, NULL);
u8x8_gpio_SetCS(u8x8, u8x8->display_info->chip_disable_level);
break;
default:
return 0;
}
return 1;
}
const uint8_t loading_img[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x03, 0x80, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x07, 0x80, 0x00, 0x3c, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x07, 0x80, 0x00, 0x7c, 0x00, 0x38, 0xf0, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x07, 0x80, 0x00, 0xfc, 0x00, 0x78, 0xf0, 0xf8, 0x00, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00,
0x00, 0x07, 0xc0, 0x01, 0xfc, 0x00, 0xf8, 0xf1, 0xf0, 0x0e, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00,
0x00, 0x03, 0xc0, 0x03, 0xf8, 0x01, 0xf8, 0xf3, 0xe0, 0x1e, 0x00, 0xf0, 0x07, 0xc0, 0x00, 0x00,
0x00, 0x03, 0xe0, 0x07, 0xc0, 0x03, 0xf8, 0xf7, 0xe0, 0x3e, 0x01, 0xf0, 0x0f, 0xc0, 0x00, 0x00,
0x00, 0x01, 0xe0, 0x0f, 0xc0, 0x03, 0xf8, 0xff, 0x80, 0x3e, 0x03, 0xf0, 0x0f, 0xc0, 0x00, 0x00,
0x00, 0x01, 0xe0, 0x0f, 0x80, 0x0f, 0xf0, 0x7f, 0x80, 0x7f, 0x07, 0xf0, 0x1f, 0xc0, 0x00, 0x00,
0x00, 0x01, 0xe0, 0x0f, 0x00, 0x1f, 0xf0, 0x7f, 0x80, 0x7f, 0x07, 0xc0, 0x1f, 0xc0, 0x00, 0x00,
0x00, 0x01, 0xf0, 0x1f, 0x00, 0x3f, 0xe0, 0x7f, 0x00, 0xff, 0x0f, 0x80, 0x3f, 0xc0, 0x00, 0x00,
0x00, 0x00, 0xf0, 0x3e, 0x00, 0x3f, 0xe0, 0x7f, 0x00, 0xff, 0x0f, 0x00, 0x3f, 0xc0, 0x00, 0x00,
0x00, 0x00, 0xf0, 0x7c, 0x00, 0x7f, 0xe0, 0x7e, 0x01, 0xff, 0x1f, 0x00, 0x7f, 0xc0, 0x00, 0x00,
0x00, 0x00, 0xf0, 0xf8, 0x00, 0xfb, 0xc0, 0x7c, 0x01, 0xef, 0x1e, 0x00, 0xfb, 0xc0, 0x00, 0x00,
0x00, 0x00, 0xf8, 0xf0, 0x01, 0xf3, 0xc0, 0xf8, 0x01, 0xef, 0x1e, 0x01, 0xf3, 0xc0, 0x00, 0x00,
0x00, 0x00, 0x79, 0xf0, 0x03, 0xe3, 0xc1, 0xf8, 0x01, 0xef, 0x3e, 0x01, 0xe3, 0xc0, 0x00, 0x00,
0x00, 0x00, 0x7b, 0xe0, 0x07, 0xcf, 0xc3, 0xfc, 0x03, 0xef, 0x3c, 0x01, 0xe3, 0xc0, 0x00, 0x00,
0x00, 0x00, 0x7b, 0xc0, 0x0f, 0xff, 0x87, 0xfc, 0x03, 0xcf, 0x7c, 0x03, 0xe3, 0xc0, 0x00, 0x00,
0x00, 0x00, 0x7f, 0xc0, 0x1f, 0xff, 0x87, 0xfc, 0x07, 0xcf, 0xf8, 0x03, 0xc3, 0xc0, 0x00, 0x00,
0x00, 0x00, 0x7f, 0x80, 0x3f, 0xff, 0x8f, 0xbc, 0x07, 0x87, 0xf8, 0x07, 0xc3, 0xc0, 0x00, 0x00,
0x00, 0x00, 0x7f, 0x00, 0x7c, 0xff, 0x1f, 0x3c, 0x07, 0x87, 0xf8, 0x07, 0x83, 0xc0, 0x00, 0x00,
0x00, 0x00, 0x3f, 0x00, 0xf8, 0x0f, 0x3e, 0x3c, 0x07, 0x87, 0xf0, 0x0f, 0x87, 0xc0, 0x00, 0x00,
0x00, 0x00, 0x3e, 0x01, 0xf0, 0x0f, 0x3c, 0x3c, 0x0f, 0x87, 0xf0, 0x1f, 0x87, 0x80, 0x00, 0x00,
0x00, 0x00, 0x3c, 0x03, 0xe0, 0x1f, 0x3c, 0x3c, 0x0f, 0x07, 0xf0, 0x3f, 0xff, 0x80, 0x00, 0x00,
0x00, 0x00, 0x1c, 0x03, 0xc0, 0x1f, 0x38, 0x3c, 0x0f, 0x07, 0xe0, 0x7f, 0xff, 0x80, 0x00, 0x00,
0x00, 0x00, 0x00, 0x03, 0x80, 0x0e, 0x00, 0x3c, 0x1f, 0x07, 0xe0, 0xff, 0xff, 0x80, 0x00, 0x00,
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x3c, 0x1e, 0x07, 0xe0, 0xf0, 0x7f, 0x80, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x1e, 0x03, 0xc1, 0xf0, 0x07, 0x80, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x1e, 0x03, 0xc3, 0xe0, 0x07, 0x80, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x01, 0xc7, 0xe0, 0x07, 0x80, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xc0, 0x07, 0x80, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x07, 0x80, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x80, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x80, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xe0, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xfc, 0x07, 0x80, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0x07, 0xfc, 0x07, 0x07, 0x80, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x87, 0xff, 0x0f, 0x0f, 0x80, 0xf0, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x1f, 0xc7, 0xff, 0x0f, 0x0f, 0x81, 0xf8, 0x0e, 0x07, 0x80,
0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x03, 0x8f, 0xff, 0x0f, 0x1f, 0x83, 0xf0, 0x1e, 0x0f, 0x80,
0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x01, 0x0f, 0x0f, 0x1f, 0x1f, 0x07, 0xe0, 0x1e, 0x3f, 0x80,
0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x0f, 0x1f, 0x1e, 0x3e, 0x0f, 0x80, 0x1e, 0xff, 0x80,
0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x0f, 0x1f, 0x1e, 0x3c, 0x0f, 0x00, 0x1f, 0xfe, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x0f, 0x3e, 0x1e, 0x3c, 0x1f, 0x00, 0x1f, 0xf8, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x0f, 0x3e, 0x1e, 0x7c, 0x1e, 0x00, 0x1f, 0xe0, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x0f, 0x3c, 0x1e, 0x78, 0x3e, 0x00, 0x1f, 0xc0, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x1f, 0x3c, 0x1e, 0x78, 0x7c, 0x00, 0x3f, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x1e, 0x3f, 0x1e, 0xf8, 0x78, 0x00, 0x3f, 0x80, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x1e, 0x1f, 0x9e, 0xf0, 0x78, 0x3c, 0x3f, 0x80, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x3e, 0x0f, 0xde, 0xf0, 0xf8, 0x7e, 0x3f, 0xc0, 0x00,
0x10, 0x89, 0x94, 0x5e, 0x00, 0xf8, 0x00, 0x3e, 0x07, 0xdf, 0xf0, 0xf3, 0xfc, 0x7f, 0xe0, 0x00,
0x11, 0x55, 0x56, 0x50, 0x00, 0xf0, 0x00, 0x1c, 0x03, 0xdf, 0xe0, 0xff, 0xf8, 0x7b, 0xf0, 0x00,
0x11, 0x55, 0x55, 0x56, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x0f, 0xc0, 0xff, 0xf0, 0x79, 0xfc, 0x00,
0x11, 0x5d, 0x54, 0xd2, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x07, 0xc0, 0x7f, 0xc0, 0x38, 0xfe, 0x00,
0x1c, 0x95, 0x94, 0x5e, 0xa8, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x7e, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
void setup() {
u8g2_Setup_ssd1306_128x64_noname_f(&u8g2, U8G2_R0, u8x8_byte_arduino_hw_spi, u8x8_gpio_and_delay);
u8g2_InitDisplay(&u8g2);
u8g2_SetPowerSave(&u8g2, 0);
u8g2_ClearBuffer(&u8g2);
u8g2_SetFont(&u8g2, u8g2_font_ncenB08_tr);
//u8g2_DrawStr(&u8g2, 0, 10, "Hello world!");
u8g2_DrawBitmap(&u8g2, 0, 0, 16, 64, loading_img);
u8g2_SendBuffer(&u8g2);
}
};
void enableClocks() {
CLOCK_EnableClock(kCLOCK_PortA);
CLOCK_EnableClock(kCLOCK_PortB);
CLOCK_EnableClock(kCLOCK_PortC);
CLOCK_EnableClock(kCLOCK_PortD);
CLOCK_EnableClock(kCLOCK_PortE);
}
void setupTFC() {
enableClocks();
setupServo(0);
Motor::setup();
setupCamera();
initI2C();
setupIOExpander();
setupGyroscope();
setupAccelerometerAndMagnetometer();
Display::setup();
Bluetooth::setup();
Stepper::setup();
Encoder::setup();
}
#endif /* __TFC_H__ */