Hardware components | ||||||
![]() |
| × | 1 | |||
![]() |
| × | 1 | |||
![]() |
| × | 1 | |||
Software apps and online services | ||||||
![]() |
| |||||
![]() |
|
Shown below is an edited version of the team's in-class final presentation. It should demonstrate the function of the project clearly:
In addition, shown below here is a video explaining the integration of all the hardware and software that we used while creating our project:
Discussed here are a few paragraphs from each team member detailing their specific contributions to the project.
Michael: For our final project, Jonah and I programmed our robot to detect different musical notes from a recorder and move in certain ways based on those detected notes. We also used CPU2 on our red board to send those detected notes to LABVIEW and had LABVIEW display what notes were being detected. This second part of the project was the part that I worked on. The first thing that I worked on was getting the robot communicating with LABVIEW. This was done by using an ESP8266 chip soldered onto our green board.
Using code composer and LABVIEW, we initially programmed the chip to receive data sent from LABVIEW and send a string back to LABVIEW. We had to connect the chip to the same WIFI network as LABVIEW by inputting the same IP address and port for both the chip and LABVIEW to connect to. Then, using a similar VI to the one used in LABVIEW assignment 4, we sent a string of numbers out from LABVIEW to the ESP8266 chip and had the chip send a string, usually different letters, back to LABVIEW. We created an array that would be populated by characters that the ESP8266 chip would send to TeraTerm for things like the connection status, if the data was send or received correctly, and the string that was sent out by LABVIEW. Then, we scanned this array for the string that was sent out by LABVIEW and watched for it with watch expressions in code composer to make sure that the chip was correctly receiving data. Finally, the chip would then send out a string of characters back to LABVIEW and would be displayed on our VI. This was one of the more difficult tasks because sometimes the LABVIEW VI would timeout if the data wasn’t sent or sent incorrectly. It turned out that the VI needed a \r and a \n after our sent strings for it to receive and display properly in the VI, otherwise it would timeout. For an aesthetic look, I also created a musical scale that would display different notes that matched the string being sent.
The next thing I worked on was getting the red board’s CPU1 to communicate with CPU2. There was a lot of setup code involved for both CPUs, including CPU1 give CPU2 permission for controlling several GPIOs, several interrupts for CPU1 to send data over to CPU2, and having CPU2 wait for CPU1 to send over data. After adjusting our given CPU2 code to our needs, Jonah added his FFT and note recognition code into the CPU1 code and I added my sending to LABVIEW code into CPU2. At this point, we had some issues again with sending data to LABVIEW because the code was not correctly sending data to the chip to send to LABVIEW. We also had some issues with LABVIEW not connecting to the internet correctly, but we were able to get it all working in time before presenting it.
Jonah: For this final project, when we decided that the goal of the project was to create a robot that both responded to musical notes and displayed them on a screen via WiFi using a second CPU, we promptly split the project up into two parts. One part was to integrate the WiFi with CPU2 and communicate with LABView, and the other part was to use the main processor CPU1 to customize the performance of the robot. I undertook the latter of the two parts. Therefore, I was to write code for CPU1 which correctly heard musical notes, then took action based on those notes, all the while communicating these actions to CPU2 in order to eventually communicate with LABView.
Initially, I used TI's FFT (Fast Fourier Transform) library to switch back and forth between taking the FFT of two different 1024 data point arrays. While the FFT of the first array, called ping_array was being taken, 1024 data points of the microphone were being taken at a rate of 10kHz and being put into the other array: pong_array. Then, pong_array's FFT was taken while ping_array received new values. I struggled with getting the flow of this code to run correctly. However, eventually it was all integrated properly. At this point, by using watch expression in code composer I was able to fine tune the possible range of frequency indices that corresponded to all five tones I was working with. I also looked at the power of the signal produced by these tones and used a minimum power threshold to filter out insignificant noise. Once this was done, I successfully had the robot hearing musical notes and printing the correct note to the serial port.
I then had to add in the code we had used in a previous lab this semester that controlled the robot to move. Using PI control (proportional-integral control), these control laws used two controls, turn and v_ref, to control how the robot moves. By accounting for the error between the expected speed/turn values and the actual values computed using the encoder, simply adjusting v_ref for velocity and turn for rotation allows for complete control of the robot's motion. This was integrated into the code by initial the EPWM2 register as well as the EQEP peripheral on the launchpad to work with the motors and the encoder. Inside of one of the CPU timer's interrupt the control equations were run every 4 ms. Therefore, I simply added code that adjusted v_ref and turn accordingly based on each note, and the robot moved as I desired. The notes controlled the robot in this way:
C Note: Move forward. A Note: Move backward. F Note: Turn left. G Note: Turn right. Shrill note from mouth of recorder: Stop all motion.
At this point, the robot properly responded to the notes from the recorder, and all that was left for me to do was to integrate the communication with CPU2 into my code. This was tricky, but eventually it was done by populating an array called cpu1tocpu2 with values corresponding the index in the alphabet of each note. For example, if an A was played cpu1tocpu2[0] was set to 1.0, and if a G was played cpu1tocpu2[0] was set to 7.0. Arbitrarily the shrill note was set to 9.0. Then, if CPU2 received a 7.0 it knew to send the string 'G' to LABView. If it received 3.0, it would send 'C' and so on and so forth. This was the last modification I had to make, however some hiccups in WiFi communication forced me to slightly adjust some of the CPU2 code the day of our presentation as well. After this was done, we successfully controlled our robot with recorder notes and displayed them to the LABView screen using WiFi.
//#############################################################################
// FILE: labstarter_main.c
//
// TITLE: Lab Starter
//#############################################################################
// Included Files
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <math.h>
#include <limits.h>
#include "F28x_Project.h"
#include "driverlib.h"
#include "device.h"
#include "f28379dSerial.h"
#include "dsp.h"
#include "fpu32/fpu_rfft.h"
// For IPC
#include "F2837xD_Ipc_drivers.h"
#define PI 3.1415926535897932384626433832795
#define TWOPI 6.283185307179586476925286766559
#define HALFPI 1.5707963267948966192313216916398
#define FEETINONEMETER 3.28083989501312
#define MIN(A,B) (((A) < (B)) ? (A) : (B));
//*****************************************************************************
// the defines for FFT
//*****************************************************************************
#define RFFT_STAGES 10
#define RFFT_SIZE (1 << RFFT_STAGES)
//*****************************************************************************
// the globals
//*****************************************************************************
#ifdef __cplusplus
#pragma DATA_SECTION("FFT_buffer_2")
#else
#pragma DATA_SECTION(pwrSpec, "FFT_buffer_2")
#endif
float pwrSpec[(RFFT_SIZE/2)+1];
float maxpwr = 0;
int16_t maxpwrindex = 0;
#ifdef __cplusplus
#pragma DATA_SECTION("FFT_buffer_2")
#else
#pragma DATA_SECTION(test_output, "FFT_buffer_2")
#endif
float test_output[RFFT_SIZE];
#ifdef __cplusplus
#pragma DATA_SECTION("FFT_buffer_1")
#else
#pragma DATA_SECTION(ping_input, "FFT_buffer_1")
#endif
float ping_input[RFFT_SIZE];
#ifdef __cplusplus
#pragma DATA_SECTION("FFT_buffer_1")
#else
#pragma DATA_SECTION(pong_input, "FFT_buffer_1")
#endif
float pong_input[RFFT_SIZE];
#ifdef __cplusplus
#pragma DATA_SECTION("FFT_buffer_2")
#else
#pragma DATA_SECTION(RFFTF32Coef,"FFT_buffer_2")
#endif //__cplusplus
//! \brief Twiddle Factors
//!
float RFFTF32Coef[RFFT_SIZE];
//! \brief Object of the structure RFFT_F32_STRUCT
//!
RFFT_F32_STRUCT rfft;
//! \brief Handle to the RFFT_F32_STRUCT object
//!
RFFT_F32_STRUCT_Handle hnd_rfft = &rfft;
// Interrupt Service Routines predefinition
__interrupt void cpu_timer0_isr(void);
__interrupt void cpu_timer1_isr(void);
__interrupt void cpu_timer2_isr(void);
__interrupt void SWI_isr(void);
__interrupt void ADCB_isr(void); //Define interrupt for ADCB
__interrupt void SPIB_isr(void); //Predefines the SPI interrupt
__interrupt void CPU2toCPU1IPC0(void);
float *cpu2tocpu1; //float pointer for the location CPU2 will give data to CPU1
float *cpu1tocpu2; //float pointer for the location CPU1 will give data to CPU2
char *commandtoCPU2;
void serialRXA(serial_t *s, char data);
void setEPWM2A(float controleffort); //Function definition to pass values EPWM2A (right motor)
void setEPWM2B(float controleffort); //Function definition to pass values EPWM2B (left motor)
float saturate(float input, float saturation_limit); //Function definition for saturate function
void init_eQEPs(void); //Function definition to initialize eQEP
float readEncLeft(void); //Function definition to read left encoder
float readEncRight(void); //Function definition to read right encoder
void setupSpib(void); //Predefines the SPI setup function
// Count variables
uint32_t numTimer0calls = 0;
uint32_t numSWIcalls = 0;
uint32_t numRXA = 0;
uint16_t UARTPrint = 0;
uint32_t numCPU2COMs = 0;
float receivefloats[4] = {0,0,0,0};
float sendfloats[4] = {0,0,0,0};
uint32_t timecounter = 0;
uint32_t ADCB_ISR_calls = 0; //Counts number of times ADCB interrupt was called
int16_t pingPong = 1;
int16_t runPong = 0;
int16_t runPing = 0;
int16_t ping_index = 0;
int16_t pong_index = 0;
int16_t powerThreshold = 100;
int16_t G_Low_Threshold = 75;
int16_t G_High_Threshold = 83;
int16_t A_Low_Threshold = 86;
int16_t A_High_Threshold = 95;
int16_t F_Low_Threshold = 69;
int16_t F_High_Threshold = 77;
int16_t C_Low_Threshold = 103;
int16_t C_High_Threshold = 113;
int16_t Stop_Low_Threshold = 118;
int16_t Stop_High_Threshold = 126;
int16_t spivalue1 = 0;
int16_t spivalue2 = 0;
float theta_l = 0; //Stores left encoder value
float theta_r = 0; //Stores right encoder value
float rad_to_feet = 0.19916351; //=1/5.021 is our conversion factor determined for radians to feet based on wheel geometry
float right_dist = 0; //Used to store the distance traveled by the right wheel
float left_dist = 0; //Used to store the distance traveled by the left wheel
float uLeft = 5; //Passed to left motor speed
float uRight = 5; //Passed to right motor speed
float PosLeft_K = 0; //Stores current left position
float PosLeft_K_1 = 0; //Stores past left position
float PosRight_K = 0; //Store current right position
float PosRight_K_1 = 0; //Stores past right position
float vel_right = 0; //Stores right wheel linear velocity
float vel_left = 0; //Stores left wheel linear velocity
float v_ref = 0; //Stores velocity to be passed to robot
float ki = 25; //Integral control constant
float kp = 3; //Proportional control constant
float ek_r = 0; //Right wheel control error
float ek_1_r = 0; //Previous right wheel control error
float ik_r = 0; //Right signal passed through integral
float ik_1_r = 0; //Previous right signal passed through integral
float ek_l = 0; //Left wheel control error
float ek_1_l = 0; //Previous left wheel control error
float ik_l = 0; //Left signal passed through integral
float ik_1_l = 0; //Previous left signal passed through integral
float theta_l_1 = 0; //Previous left angular position
float theta_r_1 = 0; //Previous right angular position
float x_r_1 = 0; //Previous robot x position
float y_r_1 = 0; //Previous robot y position
float KP_turn = 3; //Proportional turn constant
float e_turn = 0; //Turn error
float turn = 0; //Turn setpoint
float W_r = 0.57743; //Robot width
float R_wh = 0.19583; //Wheel radius
float phi_r = 0; //Robot pose angle
float x_r = 0; //Robot Pose X Coordinate
float y_r = 0; //Robot Pose Y Coordinate
float theta_avg = 0; //Average angular position
float theta_dot_avg = 0; //Average angular velocity
float theta_dot_l = 0; //Left angular velocity
float theta_dot_r = 0; //Right angular velocity
float y_dot_r = 0; //Y linear velocity
float x_dot_r = 0; //X linear velocity
int16_t updown = 1; //Used to decrease/increase PWM signal
int16_t PWM1 = 0; //Used to send values to PWM1 on DAN28027 chip
int16_t PWM2 = 0; //Used to send values to PWM2 on DAN28027 chip
int16_t SPIB_isr_calls = 0; //Counts number of times SPIB isr function is called
int16_t garbage = 0; //Used for useless SPI outputs
int16_t ADC1 = 0; //ADC1 SPI Output
int16_t ADC2 = 0; //ADC2 SPI Output
float ADC1_v = 0; //ADC1 SPI Output in volts
float ADC2_v = 0; //ADC2 SPI Output in volts
int16_t ACCEL_XOUT_RAW = 0; //Used to read the raw X acceleration from the SPI
int16_t ACCEL_YOUT_RAW = 0; //Used to read the raw Y acceleration from the SPI
int16_t ACCEL_ZOUT_RAW = 0; //Used to read the raw Z acceleration from the SPI
int16_t TEMP_OUT_RAW = 0; //Used to read the temperature from the SPI
int16_t GYRO_XOUT_RAW = 0; //Used to read the raw X gyro data from the SPI
int16_t GYRO_YOUT_RAW = 0; //Used to read the raw Y gyro data from the SPI
int16_t GYRO_ZOUT_RAW = 0; //Used to read the raw Z gyro data from the SPI
float ACCEL_XOUT = 0; //Used to store the converted X acceleration data in the range (-4,4) with units of g
float ACCEL_YOUT = 0; //Used to store the converted Y acceleration data in the range (-4,4) with units of g=(-4g,4g)
float ACCEL_ZOUT = 0; //Used to store the converted Z acceleration data in the range (-4,4) with units of g
float GYRO_XOUT = 0; //Used to store the converted X gyro data in the range (-250,250) with units of deg/sec
float GYRO_YOUT = 0; //Used to store the converted Y gyro data in the range (-250,250) with units of deg/sec
float GYRO_ZOUT = 0; //Used to store the converted Z gyro data in the range (-250,250) with units of deg/sec
void main(void)
{
// PLL, WatchDog, enable Peripheral Clocks
// This example function is found in the F2837xD_SysCtrl.c file.
InitSysCtrl();
InitIpc();
commandtoCPU2 = (char*) 0x3FFFC; // in RAM that CPU1 can R/W but CPU2 can only read.
//location of cpu2tocpu1 ram
cpu2tocpu1 = (float*) 0x3F800;
cpu1tocpu2 = (float*) 0x3FC00;
commandtoCPU2[0] = 'W'; // W for CPU2 wait
// Comment this when use CCS for debugging
// #ifdef _FLASH
// // Send boot command to allow the CPU2 application to begin execution
// IPCBootCPU2(C1C2_BROM_BOOTMODE_BOOT_FROM_FLASH);
// #else
// // Send boot command to allow the CPU2 application to begin execution
// IPCBootCPU2(C1C2_BROM_BOOTMODE_BOOT_FROM_RAM);
// #endif
// Or when you want to run CPU2 from its flash you free run CPU2 and just run IPCBootCPU2 from Flash command. Actually I do not know when you need boot from RAM ???
InitGpio();
// Blue LED on LaunchPad
GPIO_SetupPinMux(31, GPIO_MUX_CPU1, 0);
GPIO_SetupPinOptions(31, GPIO_OUTPUT, GPIO_PUSHPULL);
GpioDataRegs.GPASET.bit.GPIO31 = 1;
// Red LED on LaunchPad
GPIO_SetupPinMux(34, GPIO_MUX_CPU2, 0);
GPIO_SetupPinOptions(34, GPIO_OUTPUT, GPIO_PUSHPULL);
//GpioDataRegs.GPBSET.bit.GPIO34 = 1;
// LED1 and PWM Pin
GPIO_SetupPinMux(22, GPIO_MUX_CPU1, 0);
GPIO_SetupPinOptions(22, GPIO_OUTPUT, GPIO_PUSHPULL);
GpioDataRegs.GPACLEAR.bit.GPIO22 = 1;
// LED2
GPIO_SetupPinMux(94, GPIO_MUX_CPU1, 0);
GPIO_SetupPinOptions(94, GPIO_OUTPUT, GPIO_PUSHPULL);
GpioDataRegs.GPCCLEAR.bit.GPIO94 = 1;
// LED3
GPIO_SetupPinMux(95, GPIO_MUX_CPU1, 0);
GPIO_SetupPinOptions(95, GPIO_OUTPUT, GPIO_PUSHPULL);
GpioDataRegs.GPCCLEAR.bit.GPIO95 = 1;
// LED4
GPIO_SetupPinMux(97, GPIO_MUX_CPU1, 0);
GPIO_SetupPinOptions(97, GPIO_OUTPUT, GPIO_PUSHPULL);
GpioDataRegs.GPDCLEAR.bit.GPIO97 = 1;
// LED5
GPIO_SetupPinMux(111, GPIO_MUX_CPU1, 0);
GPIO_SetupPinOptions(111, GPIO_OUTPUT, GPIO_PUSHPULL);
GpioDataRegs.GPDCLEAR.bit.GPIO111 = 1;
// LED6
GPIO_SetupPinMux(130, GPIO_MUX_CPU1, 0);
GPIO_SetupPinOptions(130, GPIO_OUTPUT, GPIO_PUSHPULL);
GpioDataRegs.GPECLEAR.bit.GPIO130 = 1;
// LED7
GPIO_SetupPinMux(131, GPIO_MUX_CPU1, 0);
GPIO_SetupPinOptions(131, GPIO_OUTPUT, GPIO_PUSHPULL);
GpioDataRegs.GPECLEAR.bit.GPIO131 = 1;
// LED8
GPIO_SetupPinMux(25, GPIO_MUX_CPU1, 0);
GPIO_SetupPinOptions(25, GPIO_OUTPUT, GPIO_PUSHPULL);
GpioDataRegs.GPACLEAR.bit.GPIO25 = 1;
// LED9
GPIO_SetupPinMux(26, GPIO_MUX_CPU1, 0);
GPIO_SetupPinOptions(26, GPIO_OUTPUT, GPIO_PUSHPULL);
GpioDataRegs.GPACLEAR.bit.GPIO26 = 1;
// LED10
GPIO_SetupPinMux(27, GPIO_MUX_CPU1, 0);
GPIO_SetupPinOptions(27, GPIO_OUTPUT, GPIO_PUSHPULL);
GpioDataRegs.GPACLEAR.bit.GPIO27 = 1;
// LED11
GPIO_SetupPinMux(60, GPIO_MUX_CPU1, 0);
GPIO_SetupPinOptions(60, GPIO_OUTPUT, GPIO_PUSHPULL);
GpioDataRegs.GPBCLEAR.bit.GPIO60 = 1;
// LED12
GPIO_SetupPinMux(61, GPIO_MUX_CPU1, 0);
GPIO_SetupPinOptions(61, GPIO_OUTPUT, GPIO_PUSHPULL);
GpioDataRegs.GPBCLEAR.bit.GPIO61 = 1;
// LED13
GPIO_SetupPinMux(157, GPIO_MUX_CPU1, 0);
GPIO_SetupPinOptions(157, GPIO_OUTPUT, GPIO_PUSHPULL);
GpioDataRegs.GPECLEAR.bit.GPIO157 = 1;
// LED14
GPIO_SetupPinMux(158, GPIO_MUX_CPU1, 0);
GPIO_SetupPinOptions(158, GPIO_OUTPUT, GPIO_PUSHPULL);
GpioDataRegs.GPECLEAR.bit.GPIO158 = 1;
// LED15
GPIO_SetupPinMux(159, GPIO_MUX_CPU1, 0);
GPIO_SetupPinOptions(159, GPIO_OUTPUT, GPIO_PUSHPULL);
GpioDataRegs.GPECLEAR.bit.GPIO159 = 1;
// LED16
GPIO_SetupPinMux(160, GPIO_MUX_CPU1, 0);
GPIO_SetupPinOptions(160, GPIO_OUTPUT, GPIO_PUSHPULL);
GpioDataRegs.GPFCLEAR.bit.GPIO160 = 1;
//DRV8874 #1 DIR Direction
GPIO_SetupPinMux(29, GPIO_MUX_CPU1, 0);
GPIO_SetupPinOptions(29, GPIO_OUTPUT, GPIO_PUSHPULL);
GpioDataRegs.GPASET.bit.GPIO29 = 1;
//DRV8874 #2 DIR Direction
GPIO_SetupPinMux(32, GPIO_MUX_CPU1, 0);
GPIO_SetupPinOptions(32, GPIO_OUTPUT, GPIO_PUSHPULL);
GpioDataRegs.GPBSET.bit.GPIO32 = 1;
//MPU9250 CS Chip Select
GPIO_SetupPinMux(66, GPIO_MUX_CPU1, 0);
GPIO_SetupPinOptions(66, GPIO_OUTPUT, GPIO_PUSHPULL);
GpioDataRegs.GPCSET.bit.GPIO66 = 1;
//WIZNET CS Chip Select
GPIO_SetupPinMux(125, GPIO_MUX_CPU1, 0);
GPIO_SetupPinOptions(125, GPIO_OUTPUT, GPIO_PUSHPULL);
GpioDataRegs.GPDSET.bit.GPIO125 = 1;
//SPIRAM CS Chip Select
GPIO_SetupPinMux(19, GPIO_MUX_CPU1, 0);
GPIO_SetupPinOptions(19, GPIO_OUTPUT, GPIO_PUSHPULL);
GpioDataRegs.GPASET.bit.GPIO19 = 1;
//PushButton 1
GPIO_SetupPinMux(4, GPIO_MUX_CPU1, 0);
GPIO_SetupPinOptions(4, GPIO_INPUT, GPIO_PULLUP);
//PushButton 2
GPIO_SetupPinMux(5, GPIO_MUX_CPU1, 0);
GPIO_SetupPinOptions(5, GPIO_INPUT, GPIO_PULLUP);
//PushButton 3
GPIO_SetupPinMux(6, GPIO_MUX_CPU1, 0);
GPIO_SetupPinOptions(6, GPIO_INPUT, GPIO_PULLUP);
//PushButton 4
GPIO_SetupPinMux(7, GPIO_MUX_CPU1, 0);
GPIO_SetupPinOptions(7, GPIO_INPUT, GPIO_PULLUP);
//Joy Stick Pushbutton
GPIO_SetupPinMux(8, GPIO_MUX_CPU1, 0);
GPIO_SetupPinOptions(8, GPIO_INPUT, GPIO_PULLUP);
EALLOW;
GpioCtrlRegs.GPDPUD.bit.GPIO122 = 0; // Enable Pull-ups on SPI PINs Recommended by TI for SPI Pins
GpioCtrlRegs.GPDPUD.bit.GPIO123 = 0;
GpioCtrlRegs.GPDPUD.bit.GPIO124 = 0;
GpioCtrlRegs.GPDQSEL2.bit.GPIO122 = 3; // Set prequalifier for SPI PINS
GpioCtrlRegs.GPDQSEL2.bit.GPIO123 = 3; // The prequalifier eliminates short noise spikes
GpioCtrlRegs.GPDQSEL2.bit.GPIO124 = 3; // by making sure the serial pin stays low for 3 clock periods.
EDIS;
// Clear all interrupts and initialize PIE vector table:
// Disable CPU interrupts
DINT;
// Initialize the PIE control registers to their default state.
// The default state is all PIE interrupts disabled and flags
// are cleared.
// This function is found in the F2837xD_PieCtrl.c file.
InitPieCtrl();
// Disable CPU interrupts and clear all CPU interrupt flags:
IER = 0x0000;
IFR = 0x0000;
// Initialize the PIE vector table with pointers to the shell Interrupt
// Service Routines (ISR).
// This will populate the entire table, even if the interrupt
// is not used in this example. This is useful for debug purposes.
// The shell ISR routines are found in F2837xD_DefaultIsr.c.
// This function is found in F2837xD_PieVect.c.
InitPieVectTable();
// Interrupts that are used in this example are re-mapped to
// ISR functions found within this project
EALLOW; // This is needed to write to EALLOW protected registers
PieVectTable.TIMER0_INT = &cpu_timer0_isr;
PieVectTable.TIMER1_INT = &cpu_timer1_isr;
PieVectTable.TIMER2_INT = &cpu_timer2_isr;
PieVectTable.SCIA_RX_INT = &RXAINT_recv_ready;
//PieVectTable.SCIC_RX_INT = &RXCINT_recv_ready;
PieVectTable.SCID_RX_INT = &RXDINT_recv_ready;
PieVectTable.SCIA_TX_INT = &TXAINT_data_sent;
//PieVectTable.SCIC_TX_INT = &TXCINT_data_sent;
PieVectTable.SCID_TX_INT = &TXDINT_data_sent;
PieVectTable.IPC0_INT = &CPU2toCPU1IPC0;
PieVectTable.ADCB1_INT = &ADCB_isr; //Enables ADCB interrupt for when it is needed
PieVectTable.EMIF_ERROR_INT = &SWI_isr;
EDIS; // This is needed to disable write to EALLOW protected registers
// Initialize the CpuTimers Device Peripheral. This function can be
// found in F2837xD_CpuTimers.c
InitCpuTimers();
// Configure CPU-Timer 0, 1, and 2 to interrupt every second:
// 200MHz CPU Freq, 1 second Period (in uSeconds)
ConfigCpuTimer(&CpuTimer0, 200, 4000);
ConfigCpuTimer(&CpuTimer1, 200, 40000);
ConfigCpuTimer(&CpuTimer2, 200, 222000);
// Enable CpuTimer Interrupt bit TIE
CpuTimer0Regs.TCR.all = 0x4000;
CpuTimer1Regs.TCR.all = 0x4000;
CpuTimer2Regs.TCR.all = 0x4000;
init_serial(&SerialA,115200,serialRXA);
init_eQEPs(); //Initialize the eQEP
setupSpib(); //Setup the SPI
EALLOW;
//EPWM 2 Initializations used to pass PWM values to motors
EPwm2Regs.TBCTL.bit.FREE_SOFT = 3;
EPwm2Regs.TBCTL.bit.CLKDIV = 0;
EPwm2Regs.TBCTL.bit.CTRMODE = 0;
EPwm2Regs.TBCTL.bit.PHSEN = 0;
EPwm2Regs.TBCTR = 0;
EPwm2Regs.TBPRD = 2500; //50 MHz/20KHz=2500 50 MHz is frequency of clock source being counted, 20 KHz is desired
EPwm2Regs.CMPA.bit.CMPA = 0; //Start duty cycle at 0
EPwm2Regs.AQCTLA.bit.CAU = 1;
EPwm2Regs.AQCTLA.bit.ZRO = 2;
EPwm2Regs.TBPHS.bit.TBPHS = 0;
EPwm2Regs.CMPB.bit.CMPB = 0; //The following three bits are defined again for EPWM2B
EPwm2Regs.AQCTLB.bit.CBU = 1;
EPwm2Regs.AQCTLB.bit.ZRO = 2;
GPIO_SetupPinMux(2, GPIO_MUX_CPU1, 1); //GPIO PinName, CPU, Mux Index
GPIO_SetupPinMux(3, GPIO_MUX_CPU1, 1); //GPIO PinName, CPU, Mux Index
EPwm5Regs.ETSEL.bit.SOCAEN = 0; // Disable SOC on A group
EPwm5Regs.TBCTL.bit.CTRMODE = 3; // freeze counter
EPwm5Regs.ETSEL.bit.SOCASEL = 2; // Select Event when counter equal to PRD
EPwm5Regs.ETPS.bit.SOCAPRD = 1; // Generate pulse on 1st event (“pulse” is the same as “trigger”)
EPwm5Regs.TBCTR = 0x0; // Clear counter
EPwm5Regs.TBPHS.bit.TBPHS = 0x0000; // Phase is 0
EPwm5Regs.TBCTL.bit.PHSEN = 0; // Disable phase loading
EPwm5Regs.TBCTL.bit.CLKDIV = 0; //Divide by zero for exercises 1-3 and end of exercise 4
//EPwm5Regs.TBCTL.bit.CLKDIV = 2; //Divide by 4 to sample at 4 kHz for start of exercise 4
//EPwm5Regs.TBPRD = 50000; // Use for all except end of exercise 4. Set Period to 1ms sample (or.25 ms for start of exercise 4.) Input clock is 50MHz.
EPwm5Regs.TBPRD = 5000; //Use for end of exercise 4. 5000 instead of 50000 results in 10 KHz frequency of sampling.
// Notice here that we are not setting CMPA or CMPB because we are not using the PWM signal
EPwm5Regs.ETSEL.bit.SOCAEN = 1; //enable SOCA
EPwm5Regs.TBCTL.bit.CTRMODE = 0; //unfreeze, and enter up count mode
EDIS;
EALLOW;
//write configurations for all ADCs ADCA, ADCB, ADCC, ADCD
AdcbRegs.ADCCTL2.bit.PRESCALE = 6; //set ADCCLK divider to /4
AdcaRegs.ADCCTL2.bit.PRESCALE = 6; //set ADCCLK divider to /4
AdcSetMode(ADC_ADCB, ADC_RESOLUTION_12BIT, ADC_SIGNALMODE_SINGLE); //read calibration settings
AdcSetMode(ADC_ADCA, ADC_RESOLUTION_12BIT, ADC_SIGNALMODE_SINGLE); //read calibration settings
//Set pulse positions to late
AdcaRegs.ADCCTL1.bit.INTPULSEPOS = 1;
AdcbRegs.ADCCTL1.bit.INTPULSEPOS = 1;
//power up the ADCs
AdcaRegs.ADCCTL1.bit.ADCPWDNZ = 1;
AdcbRegs.ADCCTL1.bit.ADCPWDNZ = 1;
//delay for 1ms to allow ADC time to power up
DELAY_US(1000);
//ADCA
AdcaRegs.ADCSOC0CTL.bit.CHSEL = 2; //SOC0 will convert Channel you choose Does not have to be A0
//For us we had ADCA SOC0 convert channel 2
AdcaRegs.ADCSOC0CTL.bit.ACQPS = 99; //sample window is acqps + 1 SYSCLK cycles = 500ns
AdcaRegs.ADCSOC0CTL.bit.TRIGSEL = 13;// EPWM5 ADCSOCA or another trigger you choose will trigger SOC0
AdcaRegs.ADCSOC1CTL.bit.CHSEL = 3; //SOC1 will convert Channel you choose Does not have to be A1
//Similarly SOC1 converted channel 3
AdcaRegs.ADCSOC1CTL.bit.ACQPS = 99; //sample window is acqps + 1 SYSCLK cycles = 500ns
AdcaRegs.ADCSOC1CTL.bit.TRIGSEL = 13;// EPWM5 ADCSOCA or another trigger you choose will trigger SOC1
AdcaRegs.ADCINTSEL1N2.bit.INT1SEL = 1; //set to last SOC that is converted and it will set INT1 flag ADCA1
//Last SOC was SOC1
AdcaRegs.ADCINTSEL1N2.bit.INT1E = 1; //enable INT1 flag
AdcaRegs.ADCINTFLGCLR.bit.ADCINT1 = 1; //make sure INT1 flag is cleared
//ADCB
AdcbRegs.ADCSOC0CTL.bit.CHSEL = 4; //SOC0 will convert Channel you choose Does not have to be B0
//Only SOC0 is used, and it will convert channel 4
AdcbRegs.ADCSOC0CTL.bit.ACQPS = 99; //sample window is acqps + 1 SYSCLK cycles = 500ns
AdcbRegs.ADCSOC0CTL.bit.TRIGSEL = 13; // EPWM5 ADCSOCA or another trigger you choose will trigger SOC0
//AdcbRegs.ADCSOC1CTL.bit.CHSEL = 1; //SOC1 will convert Channel you choose Does not have to be B1
//AdcbRegs.ADCSOC1CTL.bit.ACQPS = 99; //sample window is acqps + 1 SYSCLK cycles = 500ns
//AdcbRegs.ADCSOC1CTL.bit.TRIGSEL = 13; // EPWM5 ADCSOCA or another trigger you choose will trigger SOC1
//AdcbRegs.ADCSOC2CTL.bit.CHSEL = 2; //SOC2 will convert Channel you choose Does not have to be B2
//AdcbRegs.ADCSOC2CTL.bit.ACQPS = 99; //sample window is acqps + 1 SYSCLK cycles = 500ns
//AdcbRegs.ADCSOC2CTL.bit.TRIGSEL = 13; // EPWM5 ADCSOCA or another trigger you choose will trigger SOC2
//AdcbRegs.ADCSOC3CTL.bit.CHSEL = 3; //SOC3 will convert Channel you choose Does not have to be B3
//AdcbRegs.ADCSOC3CTL.bit.ACQPS = 99; //sample window is acqps + 1 SYSCLK cycles = 500ns
//AdcbRegs.ADCSOC3CTL.bit.TRIGSEL = 13; // EPWM5 ADCSOCA or another trigger you choose will trigger SOC3
AdcbRegs.ADCINTSEL1N2.bit.INT1SEL = 0; //set to last SOC that is converted and it will set INT1 flag ADCB1
//SOC0 was last SOC
AdcbRegs.ADCINTSEL1N2.bit.INT1E = 1; //enable INT1 flag
AdcbRegs.ADCINTFLGCLR.bit.ADCINT1 = 1; //make sure INT1 flag is cleared
EDIS;
GPIO_SetupPinMux(9, GPIO_MUX_CPU1, 0); // Set as GPIO9 and used as DAN28027 SS
GPIO_SetupPinOptions(9, GPIO_OUTPUT, GPIO_PUSHPULL); // Make GPIO9 an Output Pin
GpioDataRegs.GPASET.bit.GPIO9 = 1; //Initially Set GPIO9/SS High so DAN28027 is not selected
GPIO_SetupPinMux(66, GPIO_MUX_CPU1, 0); // Set as GPIO66 and used as MPU-9250 SS
GPIO_SetupPinOptions(66, GPIO_OUTPUT, GPIO_PUSHPULL); // Make GPIO66 an Output Pin
GpioDataRegs.GPCSET.bit.GPIO66 = 1; //Initially Set GPIO66/SS High so MPU-9250 is not selected
GPIO_SetupPinMux(63, GPIO_MUX_CPU1, 15); //Set GPIO63 pin to SPISIMOB
GPIO_SetupPinMux(64, GPIO_MUX_CPU1, 15); //Set GPIO64 pin to SPISOMIB
GPIO_SetupPinMux(65, GPIO_MUX_CPU1, 15); //Set GPIO65 pin to SPICLKB
EALLOW;
GpioCtrlRegs.GPBPUD.bit.GPIO63 = 0; // Enable Pull-ups on SPI PINs Recommended by TI for SPI Pins
GpioCtrlRegs.GPCPUD.bit.GPIO64 = 0;
GpioCtrlRegs.GPCPUD.bit.GPIO65 = 0;
GpioCtrlRegs.GPBQSEL2.bit.GPIO63 = 3; // Set I/O pin to asynchronous mode recommended for SPI
GpioCtrlRegs.GPCQSEL1.bit.GPIO64 = 3; // Set I/O pin to asynchronous mode recommended for SPI
GpioCtrlRegs.GPCQSEL1.bit.GPIO65 = 3; // Set I/O pin to asynchronous mode recommended for SPI
EDIS;
SpibRegs.SPICCR.bit.SPISWRESET = 0; // Put SPI in Reset
SpibRegs.SPICTL.bit.CLK_PHASE = 1; //This happens to be the mode for both the DAN28027 and
SpibRegs.SPICCR.bit.CLKPOLARITY = 0; //The MPU-9250, Mode 01.
SpibRegs.SPICTL.bit.MASTER_SLAVE = 1; // Set to SPI Master
SpibRegs.SPICCR.bit.SPICHAR = 15; // Set to transmit and receive 16 bits each write to SPITXBUF (f in hex)
SpibRegs.SPICTL.bit.TALK = 1; // Enable transmission
SpibRegs.SPIPRI.bit.FREE = 1; // Free run, continue SPI operation
SpibRegs.SPICTL.bit.SPIINTENA = 0; // Disables the SPI interrupt
SpibRegs.SPIBRR.bit.SPI_BIT_RATE = 50; // Set SCLK bit rate to 1 MHz so 1us period. SPI base clock is
// 50MHZ. And this setting divides that base clock to create SCLK’s period
SpibRegs.SPISTS.all = 0x0000; // Clear status flags just in case they are set for some reason
SpibRegs.SPIFFTX.bit.SPIRST = 1;// Pull SPI FIFO out of reset, SPI FIFO can resume transmit or receive.
SpibRegs.SPIFFTX.bit.SPIFFENA = 1; // Enable SPI FIFO enhancements
SpibRegs.SPIFFTX.bit.TXFIFO = 0; // Write 0 to reset the FIFO pointer to zero, and hold in reset
SpibRegs.SPIFFTX.bit.TXFFINTCLR = 1; // Write 1 to clear SPIFFTX[TXFFINT] flag just in case it is set
SpibRegs.SPIFFRX.bit.RXFIFORESET = 0; // Write 0 to reset the FIFO pointer to zero, and hold in reset
SpibRegs.SPIFFRX.bit.RXFFOVFCLR = 1; // Write 1 to clear SPIFFRX[RXFFOVF] just in case it is set
SpibRegs.SPIFFRX.bit.RXFFINTCLR = 1; // Write 1 to clear SPIFFRX[RXFFINT] flag just in case it is set
SpibRegs.SPIFFRX.bit.RXFFIENA = 1; // Enable the RX FIFO Interrupt. RXFFST >= RXFFIL
SpibRegs.SPIFFCT.bit.TXDLY = 16; //Set delay between transmits to 16 spi clocks. Needed by DAN28027 chip
SpibRegs.SPICCR.bit.SPISWRESET = 1; // Pull the SPI out of reset
SpibRegs.SPIFFTX.bit.TXFIFO = 1; // Release transmit FIFO from reset.
SpibRegs.SPIFFRX.bit.RXFIFORESET = 1; // Re-enable receive FIFO operation
SpibRegs.SPICTL.bit.SPIINTENA = 1; // Enables SPI interrupt. !! I don’t think this is needed. Need to Test
SpibRegs.SPIFFRX.bit.RXFFIL = 10; //Interrupt Level to 16 words or more received into FIFO causes interrupt. This is just the initial setting for the register. Will be changed below
// Enable CPU int1 which is connected to CPU-Timer 0, CPU int13
// which is connected to CPU-Timer 1, and CPU int 14, which is connected
// to CPU-Timer 2: int 12 is for the SWI.
IER |= M_INT1;
IER |= M_INT8; // SCIC SCID
IER |= M_INT9; // SCIA
IER |= M_INT12;
IER |= M_INT13;
IER |= M_INT14;
//need to acknowledge IPC before use
IpcRegs.IPCACK.bit.IPC0 = 1;
PieCtrlRegs.PIEACK.all = PIEACK_GROUP1;
// Enable TINT0 in the PIE: Group 1 interrupt 7
PieCtrlRegs.PIEIER1.bit.INTx7 = 1;
// Enable SWI in the PIE: Group 12 interrupt 9
PieCtrlRegs.PIEIER12.bit.INTx9 = 1;
//Uncomment the line below to enable ADCB1 in the PIE: Group 1 interrupt 6
PieCtrlRegs.PIEIER1.bit.INTx2 = 1;
// Enable SPIB_RX in the PIE: Group 6 interrupt 3
PieCtrlRegs.PIEIER6.bit.INTx3 = 1;
//IPC
PieCtrlRegs.PIEIER1.bit.INTx13 = 1;
// SCIC setup for CPU2
GPIO_SetupPinMux(139, GPIO_MUX_CPU1, 6);
GPIO_SetupPinOptions(139, GPIO_INPUT, GPIO_PULLUP);
GPIO_SetupPinMux(56, GPIO_MUX_CPU1, 6);
GPIO_SetupPinOptions(56, GPIO_OUTPUT, GPIO_PUSHPULL);
uint32_t clk;
uint32_t baud = 115200;
ScicRegs.SCICTL1.bit.SWRESET = 0; // init SCI state machines and opt flags
ScicRegs.SCICCR.all = 0x0;
ScicRegs.SCICTL1.all = 0x0;
ScicRegs.SCICTL2.all = 0x0;
ScicRegs.SCIPRI.all = 0x0;
clk = LSPCLK_HZ; // set baud rate
clk /= baud*8;
clk--;
ScicRegs.SCILBAUD.all = clk & 0xFF;
ScicRegs.SCIHBAUD.all = (clk >> 8) & 0xFF;
ScicRegs.SCICCR.bit.SCICHAR = 0x7; // (8) 8 bits per character
ScicRegs.SCICCR.bit.PARITYENA = 0; // (N) disable party calculation
ScicRegs.SCICCR.bit.STOPBITS = 0; // (1) transmit 1 stop bit
ScicRegs.SCICCR.bit.LOOPBKENA = 0; // disable loopback test
ScicRegs.SCICCR.bit.ADDRIDLE_MODE = 0; // idle-line mode (non-multiprocessor SCI comm)
ScicRegs.SCIFFCT.bit.FFTXDLY = 0; // TX: zero-delay
ScicRegs.SCIFFTX.bit.SCIFFENA = 1; // enable SCI fifo enhancements
ScicRegs.SCIFFTX.bit.TXFIFORESET = 0;
ScicRegs.SCIFFTX.bit.TXFFIL = 0x0;// TX: fifo interrupt at all levels ???? is this correct
ScicRegs.SCIFFTX.bit.TXFFINTCLR = 1; // TX: clear interrupt flag
ScicRegs.SCIFFTX.bit.TXFFIENA = 0; // TX: disable fifo interrupt
ScicRegs.SCIFFTX.bit.TXFIFORESET = 1;
ScicRegs.SCIFFRX.bit.RXFIFORESET = 0; // RX: fifo reset
ScicRegs.SCIFFRX.bit.RXFFINTCLR = 1; // RX: clear interrupt flag
ScicRegs.SCIFFRX.bit.RXFFIENA = 1; // RX: enable fifo interrupt
ScicRegs.SCIFFRX.bit.RXFFIL = 0x1; // RX: fifo interrupt
ScicRegs.SCIFFRX.bit.RXFIFORESET = 1; // RX: re-enable fifo
ScicRegs.SCICTL2.bit.RXBKINTENA = 0; // disable receiver/error interrupt
ScicRegs.SCICTL2.bit.TXINTENA = 0; // disable transmitter interrupt
ScicRegs.SCICTL1.bit.TXWAKE = 0;
ScicRegs.SCICTL1.bit.SLEEP = 0; // disable sleep mode
ScicRegs.SCICTL1.bit.RXENA = 1; // enable SCI receiver
ScicRegs.SCICTL1.bit.RXERRINTENA = 0; // disable receive error interrupt
ScicRegs.SCICTL1.bit.TXENA = 1; // enable SCI transmitter
ScicRegs.SCICTL1.bit.SWRESET = 1; // re-enable SCI
// Do this before giving control to CPU2
EALLOW;
EPwm5Regs.TBCTL.bit.CTRMODE = 0; //unfreeze, and enter up count mode
EDIS;
ScicRegs.SCIFFRX.bit.RXFFINTCLR = 1;
SciaRegs.SCIFFRX.bit.RXFFINTCLR = 1;
PieCtrlRegs.PIEACK.all = PIEACK_GROUP8;
PieCtrlRegs.PIEACK.all = PIEACK_GROUP9;
//for CPU2 to use SCIC and or SPIC
EALLOW;
// DevCfgRegs.CPUSEL6.bit.SPI_C = 1; //SPI C connected to CPU2
DevCfgRegs.CPUSEL5.bit.SCI_C = 1; //SCI C connected to CPU2
EDIS;
commandtoCPU2[0] = 'G'; // G for CPU2 Go
int16_t i = 0;
float samplePeriod = 0.0002;
// Clear input buffers:
for(i=0; i < RFFT_SIZE; i++){
ping_input[i] = 0.0f;
}
for (i=0;i<RFFT_SIZE;i++) {
ping_input[i] = sin(125*2*PI*i*samplePeriod)+2*sin(2400*2*PI*i*samplePeriod);
}
hnd_rfft->FFTSize = RFFT_SIZE;
hnd_rfft->FFTStages = RFFT_STAGES;
hnd_rfft->InBuf = &ping_input[0]; //Input buffer
hnd_rfft->OutBuf = &test_output[0]; //Output buffer
hnd_rfft->MagBuf = &pwrSpec[0]; //Magnitude buffer
hnd_rfft->CosSinBuf = &RFFTF32Coef[0]; //Twiddle factor buffer
RFFT_f32_sincostable(hnd_rfft); //Calculate twiddle factor
for (i=0; i < RFFT_SIZE; i++){
test_output[i] = 0; //Clean up output buffer
}
for (i=0; i <= RFFT_SIZE/2; i++){
pwrSpec[i] = 0; //Clean up magnitude buffer
}
int16_t tries = 0;
while(tries < 10) {
hnd_rfft->InBuf = &ping_input[0]; //Input buffer
RFFT_f32(hnd_rfft); //Calculate real FFT
#ifdef __TMS320C28XX_TMU__ //defined when --tmu_support=tmu0 in the project
// properties
RFFT_f32_mag_TMU0(hnd_rfft); //Calculate magnitude
#else
RFFT_f32_mag(hnd_rfft); //Calculate magnitude
#endif
maxpwr = 0;
maxpwrindex = 0;
for (i=0;i<(RFFT_SIZE/2);i++) {
if (pwrSpec[i]>maxpwr) {
maxpwr = pwrSpec[i];
maxpwrindex = i;
}
}
tries++;
for (i=0;i<RFFT_SIZE;i++) {
ping_input[i] = sin((125 + tries*125)*2*PI*i*samplePeriod)+2*sin((2400-tries*200)*2*PI*i*samplePeriod);
}
}
// Enable global Interrupts and higher priority real-time debug events
EINT; // Enable Global interrupt INTM
ERTM; // Enable Global realtime interrupt DBGM
setEPWM2A(0); //Pass PWM to right motor
setEPWM2B(0); //Pass negative PWM to left motor
// IDLE loop. Just sit and loop forever (optional):
while(1)
{
if (UARTPrint == 1 ) {
serial_printf(&SerialA,"Number CPU2 Timer interrupt Calls %ld \r\n",CpuTimer2.InterruptCount);
UARTPrint = 0;
}
if ((runPing == 1) || (runPong == 1)) {
if (runPing == 1){
hnd_rfft->InBuf = &ping_input[0]; //Input buffer
runPing = 0;
}
if (runPong == 1){
hnd_rfft->InBuf = &pong_input[0]; //Input buffer
runPong = 0;
}
RFFT_f32(hnd_rfft); //Calculate real FFT
#ifdef __TMS320C28XX_TMU__ //defined when --tmu_support=tmu0 in the project
// properties
RFFT_f32_mag_TMU0(hnd_rfft); //Calculate magnitude
#else
RFFT_f32_mag(hnd_rfft); //Calculate magnitude
#endif
maxpwr = 0;
maxpwrindex = 0;
for (i=4;i<(RFFT_SIZE/2);i++) {
if (pwrSpec[i]>maxpwr && pwrSpec[i]>powerThreshold) {
maxpwr = pwrSpec[i];
maxpwrindex = i; //512 is nyquist which is 10 Khz/2 = 5 KHz
}
}
//UARTPrint = 1;
//G Note
if (maxpwrindex > G_Low_Threshold && maxpwrindex < G_High_Threshold){ //80 Expected
serial_printf(&SerialA,"G Note, Index: %ld, Power: %.3f \r\n",maxpwrindex,maxpwr);
turn = turn + 0.5; //turn right in place
v_ref = 0;
cpu1tocpu2[0] = 7.0;
IpcRegs.IPCSET.bit.IPC0 = 1;
DELAY_US(1000000);
}
//F Note
if (maxpwrindex > F_Low_Threshold && maxpwrindex < F_High_Threshold){ //73 expected
serial_printf(&SerialA,"F Note, Index: %ld, Power: %.3f \r\n",maxpwrindex,maxpwr);
turn = turn - 0.5; //turn left in place
v_ref = 0;
cpu1tocpu2[0] = 6.0;
IpcRegs.IPCSET.bit.IPC0 = 1;
DELAY_US(1000000);
}
//A Note
if (maxpwrindex > A_Low_Threshold && maxpwrindex < A_High_Threshold){ //90 expected
serial_printf(&SerialA,"A Note, Index: %ld, Power: %.3f \r\n",maxpwrindex,maxpwr);
v_ref = v_ref - 0.5; //Go backwards
turn = 0;
cpu1tocpu2[0] = 1.0;
IpcRegs.IPCSET.bit.IPC0 = 1;
DELAY_US(1000000);
}
//C Note
if (maxpwrindex > C_Low_Threshold && maxpwrindex < C_High_Threshold){ //108 expected
serial_printf(&SerialA,"C Note, Index: %ld, Power: %.3f \r\n",maxpwrindex,maxpwr);
v_ref = v_ref + 0.5; //Go forwards
turn = 0;
cpu1tocpu2[0] = 3.0;
IpcRegs.IPCSET.bit.IPC0 = 1;
DELAY_US(1000000);
}
//STOP
if (maxpwrindex > Stop_Low_Threshold && maxpwrindex < Stop_High_Threshold){ //108 expected
serial_printf(&SerialA,"STOP, Index: %ld, Power: %.3f \r\n",maxpwrindex,maxpwr);
v_ref = 0; //Go forwards
turn = 0;
cpu1tocpu2[0] = 9.0;
IpcRegs.IPCSET.bit.IPC0 = 1;
DELAY_US(1000000);
}
}
}
}
// SWI_isr, Using this interrupt as a Software started interrupt
__interrupt void SWI_isr(void) {
// These three lines of code allow SWI_isr, to be interrupted by other interrupt functions
// making it lower priority than all other Hardware interrupts.
PieCtrlRegs.PIEACK.all = PIEACK_GROUP12;
asm(" NOP"); // Wait one cycle
EINT; // Clear INTM to enable interrupts
// Insert SWI ISR Code here.......
numSWIcalls++;
// Blink a number of LEDS
// GpioDataRegs.GPATOGGLE.bit.GPIO27 = 1;
// GpioDataRegs.GPBTOGGLE.bit.GPIO60 = 1;
// GpioDataRegs.GPBTOGGLE.bit.GPIO61 = 1;
// GpioDataRegs.GPETOGGLE.bit.GPIO157 = 1;
// GpioDataRegs.GPETOGGLE.bit.GPIO158 = 1;
DINT;
}
//IPC
__interrupt void CPU2toCPU1IPC0(void){
GpioDataRegs.GPBTOGGLE.bit.GPIO52 = 1;
GpioDataRegs.GPETOGGLE.bit.GPIO131 = 1;//led7
//put data from cpu2 into cpu2tocpu1 array
int i;
for (i=0;i<4;i++) {
receivefloats[i] = cpu2tocpu1[i];
}
numCPU2COMs++;
//UARTPrint = 1;
IpcRegs.IPCACK.bit.IPC0 = 1;
PieCtrlRegs.PIEACK.all = PIEACK_GROUP1;
}
__interrupt void ADCB_isr (void) //ADCB Interrupt
{
ADCB_ISR_calls++;
if (pingPong == 1){
ping_input[ping_index] = (float)AdcbResultRegs.ADCRESULT0/1365.0; //Adds microphone reading to array
ping_index++;
if (ping_index >= 1024){
pingPong = 0;
runPing = 1;
ping_index = 0;
pong_index = 0;
}
}
else if (pingPong == 0){
pong_input[pong_index] = (float)AdcbResultRegs.ADCRESULT0/1365.0; //Adds microphone reading to array
pong_index++;
if (pong_index >= 1024){
pingPong = 1;
runPong = 1;
pong_index = 0;
ping_index = 0;
}
}
//pingpong=1 ping input
//pingpong=0 pong input
//when index hits 1024 switch pingpong and set runping/runpong
AdcbRegs.ADCINTFLGCLR.bit.ADCINT1 = 1; //clear interrupt flag
PieCtrlRegs.PIEACK.all = PIEACK_GROUP1;
}
// cpu_timer0_isr - CPU Timer0 ISR
__interrupt void cpu_timer0_isr(void)
{
CpuTimer0.InterruptCount++;
numTimer0calls++;
// We know that passing 5 to setEPWM2? results in 2.085 ft/sec. Therefore, passing 2.398 will result in 1 m/s. Therefore, multiply v_ref by 2.398
//Old States are Being Saved Here
PosLeft_K_1 = left_dist;
PosRight_K_1 = right_dist;
ik_1_r = ik_r;
ik_1_l = ik_l;
ek_1_r = ek_r;
ek_1_l = ek_l;
theta_l_1 = theta_l;
theta_r_1 = theta_r;
x_r_1 = x_r;
y_r_1 = y_r;
//Current states are defined here
theta_l = -readEncLeft(); //Get left angular position from encoder
theta_r = readEncRight(); //Get right angular position from encoder
phi_r = R_wh*(theta_r-theta_l)/W_r; //Calculates pose angle
theta_avg = 0.5*(theta_r+theta_l); //Calculates average position
theta_dot_l = (theta_l - theta_l_1) / (0.004); //Calculates left wheel angular velocity
theta_dot_r = (theta_r - theta_r_1) / (0.004); //Calculates right wheel angular velocity
theta_dot_avg = 0.5*(theta_dot_r+theta_dot_l); //Calculates average angular velocity
x_dot_r = R_wh*theta_dot_avg*cos(phi_r); //Calculates x linear velocity of robot
y_dot_r = R_wh*theta_dot_avg*sin(phi_r); //Calculates y linear velocity of robot
x_r = x_r_1 + 0.004*x_dot_r; //Updates x pose based on previous pose and linear velocity
y_r = y_r_1 + 0.004*y_dot_r; //Updates y pose based on previous pose and linear velocity
right_dist = theta_r * rad_to_feet; //converts radians to feet
left_dist = theta_l * rad_to_feet; //converts radians to feet
PosLeft_K = left_dist; //Stores current left position
PosRight_K = right_dist; //Stores current right position
vel_left = (PosLeft_K - PosLeft_K_1) / (0.004); //Uses two most recent left positions to find left velocity
vel_right = (PosRight_K - PosRight_K_1) / (0.004); //Uses two most recent right positions to find right velocity
e_turn = turn + (vel_left - vel_right); //Sets turn error
ek_r = v_ref - vel_right + KP_turn*e_turn; //Finds total right error
ek_l = v_ref - vel_left - KP_turn*e_turn; //Find total left error
//Avoid integral windup
if (fabs(uRight) < 9.9){
ik_r = ik_1_r + 0.004*(ek_r + ek_1_r)/2;
}
else {
ik_r = ik_1_r; //If wheel is stopped do not increment ik
}
if (fabs(uLeft) < 9.9){
ik_l = ik_1_l + 0.004*(ek_l + ek_1_l)/2;
}
else {
ik_l = ik_1_l; //If wheel is stopped do not increment ik
}
uRight = ek_r*kp + ik_r*ki; //Set PWM to ek*Kp + ik*Ki for the right motor
uLeft = ek_l*kp + ik_l*ki; //Set PWM to ek*Kp + ik*Ki for the left motor
setEPWM2A(uRight); //Pass PWM to right motor
setEPWM2B(-uLeft); //Pass negative PWM to left motor
// if (numTimer0calls % 75 == 0) {
// UARTPrint = 1; //Print every 75 iterations
// }
// if ((numTimer0calls%50) == 0) {
// PieCtrlRegs.PIEIFR12.bit.INTx9 = 1; // Manually cause the interrupt for the SWI
// }
//Clear GPIO9 Low to act as a Slave Select. Right now, just to scope. Later to select DAN28027 chip
//GpioDataRegs.GPACLEAR.bit.GPIO9 = 1; //For DAN Chip
GpioDataRegs.GPCCLEAR.bit.GPIO66 = 1; //For MPU chip
SpibRegs.SPIFFRX.bit.RXFFIL = 8; // Issue the SPIB_RX_INT when two values are in the RX FIFO (2 initially, 3 for ex. 3, 8 for ex. 4)
//SpibRegs.SPITXBUF = 0x4A3B; // 0x4A3B and 0xB517 have no special meaning. Wanted to send (Ex.2)
//SpibRegs.SPITXBUF = 0xB517; // something so you can see the pattern on the Oscilloscope (Ex.2)
...
This file has been truncated, please download it to see its full contents.
//#############################################################################
// FILE: labstarter_main.c
//
// TITLE: Lab Starter
//#############################################################################
// Included Files
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <math.h>
#include <limits.h>
#include "F28x_Project.h"
#include "driverlib.h"
#include "device.h"
#include "f28379dSerialCPU2.h"
#include "dsp.h"
#include "fpu32/fpu_rfft.h"
#define PI 3.1415926535897932384626433832795
#define TWOPI 6.283185307179586476925286766559
#define HALFPI 1.5707963267948966192313216916398
// Interrupt Service Routines predefinition
__interrupt void cpu_timer0_isr(void);
__interrupt void cpu_timer1_isr(void);
__interrupt void cpu_timer2_isr(void);
//__interrupt void SWI_isr(void);
__interrupt void CPU1toCPU2IPC0(void);
void serialRXC(serial_t *s, char data);
// Count variables
uint32_t numTimer0calls = 0;
uint32_t numSWIcalls = 0;
float *cpu2tocpu1;
float *cpu1tocpu2;
char *commandfromCPU1;
uint32_t numRXC = 0;
uint16_t UARTPrint = 0;
uint32_t numCPU1COMs = 0;
float CPU2receivefloats[4] = {0,0,0,0};
float CPU2sendfloats[4] = {0,0,0,0};
uint32_t timecounter = 0;
char sendstring[30] = "This is a string";
int16_t ESP8266whichcommand = 0;
int16_t ESP8266insidecommands = 0;
float myfloat1=0;
//float myfloat2=0;
int16_t collect = 0;
char gusarray[50];
int16_t g = 0;
char debug_array[100];
int16_t debugi = 0;
char sendto8266[10];
int16_t sendingto8266 = 0;
int16_t esp8266LabviewNotDone = 0;
void main(void)
{
// PLL, WatchDog, enable Peripheral Clocks
// This example function is found in the F2837xD_SysCtrl.c file.
InitSysCtrl();
GpioDataRegs.GPCSET.bit.GPIO67 = 1;
commandfromCPU1 = (char*) 0x3FFFC; // in RAM that CPU1 can R/W but CPU2 can only read.
//location of cpu2tocpu1 ram
cpu2tocpu1 = (float*) 0x3F800;
cpu1tocpu2 = (float*) 0x3FC00;
while (commandfromCPU1[0] != 'G') {
DELAY_US(10000);
}
// Initialize the PIE vector table with pointers to the shell Interrupt
// Service Routines (ISR).
// This will populate the entire table, even if the interrupt
// is not used in this example. This is useful for debug purposes.
// The shell ISR routines are found in F2837xD_DefaultIsr.c.
// This function is found in F2837xD_PieVect.c.
InitPieVectTable();
// Interrupts that are used in this example are re-mapped to
// ISR functions found within this project
EALLOW; // This is needed to write to EALLOW protected registers
PieVectTable.TIMER0_INT = &cpu_timer0_isr;
PieVectTable.TIMER1_INT = &cpu_timer1_isr;
PieVectTable.TIMER2_INT = &cpu_timer2_isr;
PieVectTable.SCIC_RX_INT = &RXCINT_recv_ready;
PieVectTable.SCIC_TX_INT = &TXCINT_data_sent;
PieVectTable.IPC0_INT = &CPU1toCPU2IPC0;
//PieVectTable.EMIF_ERROR_INT = &SWI_isr;
EDIS; // This is needed to disable write to EALLOW protected registers
// Initialize the CpuTimers Device Peripheral. This function can be
// found in F2837xD_CpuTimers.c
InitCpuTimers();
// Configure CPU-Timer 0, 1, and 2 to interrupt every second:
// 200MHz CPU Freq, 1 second Period (in uSeconds)
ConfigCpuTimer(&CpuTimer0, 200, 137000); // 137ms
ConfigCpuTimer(&CpuTimer1, 200, 1000);
ConfigCpuTimer(&CpuTimer2, 200, 40000);
// Enable CpuTimer Interrupt bit TIE
CpuTimer0Regs.TCR.all = 0x4000;
CpuTimer1Regs.TCR.all = 0x4000;
CpuTimer2Regs.TCR.all = 0x4000;
init_serial(&SerialC,115200,serialRXC);
// Enable CPU int1 which is connected to CPU-Timer 0, CPU int13
// which is connected to CPU-Timer 1, and CPU int 14, which is connected
// to CPU-Timer 2: int 12 is for the SWI.
IER |= M_INT1;
IER |= M_INT8;//scic
IER |= M_INT12;
IER |= M_INT13;
IER |= M_INT14;
// Enable TINT0 in the PIE: Group 1 interrupt 7
PieCtrlRegs.PIEIER1.bit.INTx7 = 1;
// Enable SWI in the PIE: Group 12 interrupt 9
PieCtrlRegs.PIEIER12.bit.INTx9 = 1;
//IPC0
PieCtrlRegs.PIEIER1.bit.INTx13 = 1;
IpcRegs.IPCACK.bit.IPC0 = 1;
PieCtrlRegs.PIEACK.all = PIEACK_GROUP1;
// Enable global Interrupts and higher priority real-time debug events
EINT; // Enable Global interrupt INTM
ERTM; // Enable Global realtime interrupt DBGM
serial_send(&SerialC,"AT\r\n",strlen("AT\r\n"));
ESP8266whichcommand = 1;
ESP8266insidecommands = 1;
// IDLE loop. Just sit and loop forever (optional):
while(1)
{
if (UARTPrint == 1 ) {
//serial_send(&SerialC, sendstring, 18);
// serial_printf(&SerialC,"B4=%.3f, RXC %ld numCPU2COMs %ld %.3f %.3f %.3f %.3f\r\n",ADCb4volt,numRXC,numCPU1COMs,CPU2receivefloats[0],CPU2receivefloats[1],CPU2receivefloats[2],CPU2receivefloats[3]);
UARTPrint = 0;
}
}
}
// SWI_isr, Using this interrupt as a Software started interrupt
//__interrupt void SWI_isr(void) {
//
// // These three lines of code allow SWI_isr, to be interrupted by other interrupt functions
// // making it lower priority than all other Hardware interrupts.
// PieCtrlRegs.PIEACK.all = PIEACK_GROUP12;
// asm(" NOP"); // Wait one cycle
// EINT; // Clear INTM to enable interrupts
//
//
//
// // Insert SWI ISR Code here.......
//
//
// numSWIcalls++;
//
// DINT;
//
//}
int dancount = 0;
//IPC
__interrupt void CPU1toCPU2IPC0(void){
//put data from cpu2 into cpu2tocpu1 array
int i;
for (i=0;i<4;i++) {
CPU2receivefloats[i] = cpu1tocpu2[i];
}
if (esp8266LabviewNotDone == 0) {
if (CPU2receivefloats[0] == 1.0) {
sendto8266[0] = 'A';
sendto8266[1] = '\r'; //Need this to print properly
sendto8266[2] = '\n'; //Need this to print properly
sendingto8266 = 1;
serial_send(&SerialC,"AT+CIPSEND=0,3\r\n",strlen("AT+CIPSEND=0,3\r\n")); //AT+CIPSEND is send command on chip. 0,3: Not sure what 0 is for (id?) but the 3 corresponds to length being sent.
esp8266LabviewNotDone = 1;
}
if (CPU2receivefloats[0] == 3.0) {
sendto8266[0] = 'C';
sendto8266[1] = '\r'; //Need this to print properly
sendto8266[2] = '\n'; //Need this to print properly
sendingto8266 = 1;
serial_send(&SerialC,"AT+CIPSEND=0,3\r\n",strlen("AT+CIPSEND=0,3\r\n")); //AT+CIPSEND is send command on chip. 0,3: Not sure what 0 is for (id?) but the 3 corresponds to length being sent.
esp8266LabviewNotDone = 1;
}
if (CPU2receivefloats[0] == 6.0) {
sendto8266[0] = 'F';
sendto8266[1] = '\r'; //Need this to print properly
sendto8266[2] = '\n'; //Need this to print properly
sendingto8266 = 1;
serial_send(&SerialC,"AT+CIPSEND=0,3\r\n",strlen("AT+CIPSEND=0,3\r\n")); //AT+CIPSEND is send command on chip. 0,3: Not sure what 0 is for (id?) but the 3 corresponds to length being sent.
esp8266LabviewNotDone = 1;
}
if (CPU2receivefloats[0] == 7.0) {
sendto8266[0] = 'G';
sendto8266[1] = '\r'; //Need this to print properly
sendto8266[2] = '\n'; //Need this to print properly
sendingto8266 = 1;
serial_send(&SerialC,"AT+CIPSEND=0,3\r\n",strlen("AT+CIPSEND=0,3\r\n")); //AT+CIPSEND is send command on chip. 0,3: Not sure what 0 is for (id?) but the 3 corresponds to length being sent.
esp8266LabviewNotDone = 1;
}
if (CPU2receivefloats[0] == 9.0) {
sendto8266[0] = 'Stop';
sendto8266[1] = '\r'; //Need this to print properly
sendto8266[2] = '\n'; //Need this to print properly
sendingto8266 = 1;
serial_send(&SerialC,"AT+CIPSEND=0,3\r\n",strlen("AT+CIPSEND=0,3\r\n")); //AT+CIPSEND is send command on chip. 0,3: Not sure what 0 is for (id?) but the 3 corresponds to length being sent.
esp8266LabviewNotDone = 1;
}
}
numCPU1COMs++;
UARTPrint = 1;
IpcRegs.IPCACK.bit.IPC0 = 1;
PieCtrlRegs.PIEACK.all = PIEACK_GROUP1;
}
// cpu_timer0_isr - CPU Timer0 ISR
__interrupt void cpu_timer0_isr(void)
{
GpioDataRegs.GPASET.bit.GPIO7 = 1;
CpuTimer0.InterruptCount++;
numTimer0calls++;
// if ((numTimer0calls%50) == 0) {
// PieCtrlRegs.PIEIFR12.bit.INTx9 = 1; // Manually cause the interrupt for the SWI
// }
cpu2tocpu1[0] = sin(2*PI*0.1*(timecounter*0.137));
cpu2tocpu1[1] = 2*cos(2*PI*0.1*(timecounter*0.137));
cpu2tocpu1[2] = 3*sin(2*PI*0.1*(timecounter*0.137));
cpu2tocpu1[3] = 4*cos(2*PI*0.1*(timecounter*0.137));
timecounter++;
IpcRegs.IPCSET.bit.IPC0 = 1;
GpioDataRegs.GPCCLEAR.bit.GPIO67 = 1;
if (ESP8266whichcommand == 12) {
dancount++;
if ((dancount % 3) == 0) {
GpioDataRegs.GPBTOGGLE.bit.GPIO34 = 1;
}
} else {
GpioDataRegs.GPBTOGGLE.bit.GPIO34 = 1;
}
GpioDataRegs.GPBTOGGLE.bit.GPIO61 = 1;//led12
// Acknowledge this interrupt to receive more interrupts from group 1
PieCtrlRegs.PIEACK.all = PIEACK_GROUP1;
}
// cpu_timer1_isr - CPU Timer1 ISR
__interrupt void cpu_timer1_isr(void)
{
CpuTimer1.InterruptCount++;
}
// cpu_timer2_isr CPU Timer2 ISR
__interrupt void cpu_timer2_isr(void)
{
CpuTimer2.InterruptCount++;
}
char sendback[10];
char past4[4] = {'\0','\0','\0','\0'};
// This function is called each time a char is received over UARTA.
void serialRXC(serial_t *s, char data) {
if (ESP8266insidecommands == 1) {
if (ESP8266whichcommand == 1) {
past4[0] = data;
if ((past4[0]=='\n') && (past4[1]=='\r') && (past4[2]=='K') && (past4[3]=='O')) {
ESP8266whichcommand = 2;
serial_send(&SerialC,"AT+CWMODE=3\r\n",strlen("AT+CWMODE=3\r\n"));
past4[0] = '\0';
past4[1] = '\0';
past4[2] = '\0';
past4[3] = '\0';
}
past4[3] = past4[2];
past4[2] = past4[1];
past4[1] = past4[0];
} else if (ESP8266whichcommand == 2) {
past4[0] = data;
if ((past4[0]=='\n') && (past4[1]=='\r') && (past4[2]=='K') && (past4[3]=='O')) {
ESP8266whichcommand = 3;
serial_send(&SerialC,"AT+CWJAP=\"MECHNIGHT\",\"f33dback5\"\r\n",strlen("AT+CWJAP=\"MECHNIGHT\",\"f33dback5\"\r\n"));
//serial_send(&SerialC,"AT+CWJAP=\"Jesusloves\",\"n8watchit\"\r\n",strlen("AT+CWJAP=\"JESUSLOVES\",\"n8watchit\"\r\n"));
past4[0] = '\0';
past4[1] = '\0';
past4[2] = '\0';
past4[3] = '\0';
}
past4[3] = past4[2];
past4[2] = past4[1];
past4[1] = past4[0];
} else if (ESP8266whichcommand == 3) {
past4[0] = data;
if ((past4[0]=='\n') && (past4[1]=='\r') && (past4[2]=='K') && (past4[3]=='O')) {
ESP8266whichcommand = 4;
serial_send(&SerialC, "AT+CIPSTA=\"192.168.1.59\"\r\n", strlen("AT+CIPSTA=\"192.168.1.59\"\r\n")); //IP address to type into labview
past4[0] = '\0';
past4[1] = '\0';
past4[2] = '\0';
past4[3] = '\0';
}
past4[3] = past4[2];
past4[2] = past4[1];
past4[1] = past4[0];
} else if (ESP8266whichcommand == 4) {
past4[0] = data;
if ((past4[0]=='\n') && (past4[1]=='\r') && (past4[2]=='K') && (past4[3]=='O')) {
ESP8266whichcommand = 5;
serial_send(&SerialC,"AT+CIPMUX=1\r\n", strlen("AT+CIPMUX=1\r\n"));
past4[0] = '\0';
past4[1] = '\0';
past4[2] = '\0';
past4[3] = '\0';
}
past4[3] = past4[2];
past4[2] = past4[1];
past4[1] = past4[0];
} else if (ESP8266whichcommand == 5) {
past4[0] = data;
if ((past4[0]=='\n') && (past4[1]=='\r') && (past4[2]=='K') && (past4[3]=='O')) {
ESP8266whichcommand = 6;
serial_send(&SerialC,"AT+CIPSERVER=1,1336\r\n", strlen("AT+CIPSERVER=1,1336\r\n")); //1336 is the port to type into Labview
past4[0] = '\0';
past4[1] = '\0';
past4[2] = '\0';
past4[3] = '\0';
}
past4[3] = past4[2];
past4[2] = past4[1];
past4[1] = past4[0];
} else if (ESP8266whichcommand == 6) {
past4[0] = data;
if ((past4[0]=='\n') && (past4[1]=='\r') && (past4[2]=='K') && (past4[3]=='O')) {
ESP8266whichcommand = 12; // should never get in 12
ESP8266insidecommands = 0;
past4[0] = '\0';
past4[1] = '\0';
past4[2] = '\0';
past4[3] = '\0';
}
past4[3] = past4[2];
past4[2] = past4[1];
past4[1] = past4[0];
} else if (ESP8266whichcommand == 12) {
sendback[0] = ' ';
sendback[1] = 'D';
sendback[2] = 'a';
sendback[3] = 'n';
//serial_send(&SerialA,sendback,4);
}
sendback[0] = data;
//serial_send(&SerialA,sendback,1);
} else { // ESP8266insidecommands == 0
// for now just echo char
if (sendingto8266 == 1) {
if (data ){
serial_send(&SerialC,sendto8266,3);
sendingto8266 = 0;
esp8266LabviewNotDone = 0;
}
} else if (collect==0){
if (data == '*'){ //Reading from teraterm, looking for * symbol to start collecting into gusarray, maybe have different symbols for different notes?
collect = 1;
g = 0;
//turnflag = 1;
}
} else if (collect==1){ //If collect == 1, this is what we want to mainly edit
collect = 0;
if (data =='\n'){ //End of array, should collect 1 or 2 floats from the * statement and turn it into myfloat variables, depending on labview
gusarray[g]='\0';
//sscanf(gusarray,"%f %f",&myfloat1,&myfloat2);
sscanf(gusarray,"%f",&myfloat1);
// if (myfloat1 == ){ // Use these if statements for sendto8266 for different tones detected maybe? Call it a different name than myfloat
// sendto8266[0] = 'G';
// sendto8266[1] = '\r'; //Need this to print properly
// sendto8266[2] = '\n'; //Need this to print properly
// }
// else if (myfloat1 == ){
// sendto8266[0] = 'F';
// sendto8266[1] = '\r'; //Need this to print properly
// sendto8266[2] = '\n'; //Need this to print properly
// }
// else if (myfloat1 == ){
// sendto8266[0] = 'A';
// sendto8266[1] = '\r'; //Need this to print properly
// sendto8266[2] = '\n'; //Need this to print properly
// }
// else if (myfloat1 == ){
// sendto8266[0] = 'C'; //High C note
// sendto8266[1] = '\r'; //Need this to print properly
// sendto8266[2] = '\n'; //Need this to print properly
// }
// else{
// sendto8266[0] = 'X'; //For no note detected
// sendto8266[1] = '\r'; //Need this to print properly
// sendto8266[2] = '\n'; //Need this to print properly
// }
//Outside of if statement
// sendto8266[0] = 'C';
// sendto8266[1] = '\r'; //Need this to print properly
// sendto8266[2] = '\n'; //Need this to print properly
// sendingto8266 = 1;
// serial_send(&SerialC,"AT+CIPSEND=0,3\r\n",strlen("AT+CIPSEND=0,3\r\n")); //AT+CIPSEND is send command on chip. 0,3: Not sure what 0 is for (id?) but the 3 corresponds to length being sent.
// if (turnflag == 1){
// turnrate = myfloat1;
// turnflag = 0;
// }
// else if (velflag == 1){
// Vref = myfloat;
// velflag = 0;
// }
// else if (fbflag == 1){
// FB_offset = myfloat;
// fbflag = 0;
// }
collect = 0;
g=0;
} else {
gusarray[g]=data;
g++;
if (g>=50){
g = 0;
}
}
}
if (debugi < 100) {
debug_array[debugi] = data;
debugi++;
}
sendback[0] = data;
//serial_send(&SerialA,sendback,1);
}
}
.zip file of the CPU1 project directory
C/C++No preview (download only).
Comments