This thread has been locked.
If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.
There is a myriad of questions with a similar problem. I've read through all of them but none seem to be similar to mine. I am using Code Composer Studio Version: 9.3.0.00012. The program is running from RAM and I am using the default linker file : 2837x_RAM_lnk_cpu1.cmd. The microcontroller is used as a part of the TMDSCNCD28379D control card. The control card is then plugged into a custom PCB board that we've developped. For now the whole system was being tested in debug mode (control card connected to PC via USB and starting the debug mode via the F11 key). The ePWM, ADC and I2C module of the micocontroller have been succesfully used till now. Below is my code which was able to run succesfully on our system in debug mode:
// Included Files #include "F28x_Project.h" #include <My_headers/Timer_Init.h> #include <My_headers/ADC_Interrupts.h> #include <My_headers/ADC_Init.h> #include <My_headers/Gpio_Init.h> #include <My_headers/CPUTimer_Interrupts.h> #include <My_headers/EPwm_Init.h> #include <My_headers/I2C_Init.h> #include <My_headers/I2C_functions.h> #include <My_headers/I2C_Interrupts.h> #include <My_headers/I2C_structs_and_defines.h> #include <stdint.h> //Declaration of int16_t, uint16_t tipova, itd. #include <stdbool.h> //Declaration of _Bool type, true=integer 1, false = integer 0 uint32_t Interruptcount = 0 ; uint16_t ulazni_relej = 0; //This global variable controls GPIO40 which controls the operation of the input relay uint16_t boost_pwm_en = 0; //Enable for boost converter PWM float zadani_izlazni_napon, zadani_ulazni_napon; //Reference values for the input and output voltages float izlazni_napon, ulazni_napon; //Measured values for the input and output voltages float izlazna_struja; //Measured value for output current //extern const uint16_t k; //Number of samples that are used for averaging, do not use this float ulazna_struja_vect [10]; //Input current vector which contains 10 last samples float ulazna_struja_acc; //The sum of the last 10 samples float ulazna_struja; //Averaged input current float ulazni_napon_vect [10]; float ulazni_napon_acc; float ulazni_napon; float izlazni_napon_vect [10]; float izlazni_napon_acc; float izlazni_napon; float izlazna_struja_vect [10]; float izlazna_struja_acc; float izlazna_struja; float dc_bus_napon_vect [10]; float dc_bus_napon_acc; float dc_bus_napon; float zadana_ulazna_struja; //Reference value for battery current (this variable is at the output of the voltage regulator) float duty; //Current regulator output. uint16_t indeks; //Dummy variable for going through measurement vectors. //PID variables volatile struct regulator G_v = {0,0,0,0,0.3,0.75,2,0}; // {error; integral; i_term; p_term; Kp; Ki; i_max; i_min} volatile struct regulator G_i = {0,0,0,0,0.05,1.2,1,0}; // Maybe put a typedef here instead of using struct float dt = 0.00327675; //dt = 65535/200.000.000 s uint16_t enable = 0; //Variable for enabling the control law inside the interrupt function //Variables and definitions for I2C-------------------------------------------------------------------------------------------------------------------------------------------- #define i2c_slave_addr 0x50 //Physical address of I2C slave #define i2c_numbytes 2 //Number of bytes in the message buffer #define i2c_eeprom_high_addr 0x00 //Upper 8 bits of address inside the EEPROM #define i2c_eeprom_low_addr 0x00 //Lower 8 bits of address inside the EEPROM struct i2cmsg I2cMsgOut = { //Message for sending i2c_msgstat_send_withstop, i2c_slave_addr, i2c_numbytes, i2c_eeprom_high_addr, i2c_eeprom_low_addr, 0x12, //Message byte 2 0x34, //Message byte 1 0x64 }; struct i2cmsg I2cMsgIn = { //Message for recieval i2c_msgstat_send_nostop, i2c_slave_addr, i2c_numbytes, i2c_eeprom_high_addr, i2c_eeprom_low_addr //The buffer of this message is left unpopulated }; volatile struct i2cmsg* CurrentMsgPtr = &I2cMsgOut; volatile Uint16 PassCount; volatile Uint16 FailCount; volatile Uint16 IntSource; void main(void) { // Step 1. Initialize System Control: // PLL, WatchDog, enable Peripheral Clocks // This example function is found in the F2837xD_SysCtrl.c file. InitSysCtrl(); // Step 2. Initialize GPIO: // This example function is found in the F2837xD_Gpio.c file and // illustrates how to set the GPIO to it's default state. InitGpio(); InitTimer(); //Function defined in My_headers/Timer_Init.h InitADC_Boost(); //Function defined in My_headers/ADC_Init.h InitADC_ZVSFB(); //Function defined in My_headers/ADC_Init.h initBoostGPIO(); //Function defined in My_headers/Gpio_Init.h initZVSFBGPIO(); //Function defined in My_headers/Gpio_Init.h init_I2C(); //Function defined in My_headers/I2C_Init.h EALLOW; CpuSysRegs.PCLKCR0.bit.TBCLKSYNC = 0; //Disable clocking to the TBCTR register in the EPWM modules EDIS; InitBoostEPwm(); //Function defined in My_headers/EPwm_Init.h InitZVSFBEpwm(); //Function defined in My_headers/EPwm_Init.h EALLOW; CpuSysRegs.PCLKCR0.bit.TBCLKSYNC = 1; //Enable clocking to the TBCTR register in the EPWM modules EDIS; // Step 3. 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(); EALLOW; PieVectTable.TIMER0_INT = &cpu_timer0_isr; //In the PIEVectTable the adress of the ISR is written. The interrupt is defined in My_headers/CPUTimer_Interrupts.h PieVectTable.I2CA_INT = &i2ca_isr; // In the PIEVectTable the adress of the ISR is written. The interrupt is defined in My_headers/I2C_Interrupts.h EDIS; IER |= M_INT1; //Enable CPU PIE group 1 (U toj grupi su prekidi za Timer0 i ADCA1) IER |= M_INT8; //Enable CPU PIE group 8 (U toj grupi su prekidi za I2CA) PieCtrlRegs.PIEIER1.bit.INTx7 = 1; //Timer0 interrupt is in PIE group 1, and channel 7 PieCtrlRegs.PIEIER8.bit.INTx1 = 1; //I2CA interrupt is in PIE group 8, channel 1 // Enable global Interrupts and higher priority real-time debug events: EINT; // Enable Global interrupt INTM ERTM; // Enable Global realtime interrupt DBGM Uint16 array[20]={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19}; i2c_eeprom_write(array, 20, 0x00, 0x00); //Function defined in My_headers/I2C_functions Uint16 array2[20]; __asm(" ESTOP0"); i2c_eeprom_read(array2, 20, 0x00, 0x00); //Function defined in My_headers/I2C_functions for(;;) { GpioDataRegs.GPBDAT.bit.GPIO40 = ulazni_relej ; GpioDataRegs.GPBDAT.bit.GPIO42 = 1 - boost_pwm_en; } } // End of file
Here are all of the included files:
CPUTimer_Interrupts.h EPwm_Init.h
As mentioned, the code runs fine with this configuration. The next step in our application was to add CAN communication capabilties. I followed the can_loopback_bitfields.c example from C2000Ware, and the first thing I added to the existing code were global variable definitions and function declarations, as can be seen in the following section:
// Included Files #include "F28x_Project.h" #include <My_headers/Timer_Init.h> #include <My_headers/ADC_Interrupts.h> #include <My_headers/ADC_Init.h> #include <My_headers/Gpio_Init.h> #include <My_headers/CPUTimer_Interrupts.h> #include <My_headers/EPwm_Init.h> #include <My_headers/I2C_Init.h> #include <My_headers/I2C_functions.h> #include <My_headers/I2C_Interrupts.h> #include <My_headers/I2C_structs_and_defines.h> #include <stdint.h> //Declaration of int16_t, uint16_t tipova, itd. #include <stdbool.h> //Declaration of _Bool type, true=integer 1, false = integer 0 uint32_t Interruptcount = 0 ; uint16_t ulazni_relej = 0; //This global variable controls GPIO40 which controls the operation of the input relay uint16_t boost_pwm_en = 0; //Enable for boost converter PWM float zadani_izlazni_napon, zadani_ulazni_napon; //Reference values for the input and output voltages float izlazni_napon, ulazni_napon; //Measured values for the input and output voltages float izlazna_struja; //Measured value for output current //extern const uint16_t k; //Number of samples that are used for averaging, do not use this float ulazna_struja_vect [10]; //Input current vector which contains 10 last samples float ulazna_struja_acc; //The sum of the last 10 samples float ulazna_struja; //Averaged input current float ulazni_napon_vect [10]; float ulazni_napon_acc; float ulazni_napon; float izlazni_napon_vect [10]; float izlazni_napon_acc; float izlazni_napon; float izlazna_struja_vect [10]; float izlazna_struja_acc; float izlazna_struja; float dc_bus_napon_vect [10]; float dc_bus_napon_acc; float dc_bus_napon; float zadana_ulazna_struja; //Reference value for battery current (this variable is at the output of the voltage regulator) float duty; //Current regulator output. uint16_t indeks; //Dummy variable for going through measurement vectors. //PID variables volatile struct regulator G_v = {0,0,0,0,0.3,0.75,2,0}; // {error; integral; i_term; p_term; Kp; Ki; i_max; i_min} volatile struct regulator G_i = {0,0,0,0,0.05,1.2,1,0}; // Maybe put a typedef here instead of using struct float dt = 0.00327675; //dt = 65535/200.000.000 s uint16_t enable = 0; //Variable for enabling the control law inside the interrupt function //Variables and definitions for I2C-------------------------------------------------------------------------------------------------------------------------------------------- #define i2c_slave_addr 0x50 //Physical address of I2C slave #define i2c_numbytes 2 //Number of bytes in the message buffer #define i2c_eeprom_high_addr 0x00 //Upper 8 bits of address inside the EEPROM #define i2c_eeprom_low_addr 0x00 //Lower 8 bits of address inside the EEPROM struct i2cmsg I2cMsgOut = { //Message for sending i2c_msgstat_send_withstop, i2c_slave_addr, i2c_numbytes, i2c_eeprom_high_addr, i2c_eeprom_low_addr, 0x12, //Message byte 2 0x34, //Message byte 1 0x64 }; struct i2cmsg I2cMsgIn = { //Message for recieval i2c_msgstat_send_nostop, i2c_slave_addr, i2c_numbytes, i2c_eeprom_high_addr, i2c_eeprom_low_addr //The buffer of this message is left unpopulated }; volatile struct i2cmsg* CurrentMsgPtr = &I2cMsgOut; volatile Uint16 PassCount; volatile Uint16 FailCount; volatile Uint16 IntSource; // Globals and functions for CAN----------------------------------------------------------- unsigned char ucTXMsgData[4] = {0x1, 0x2, 0x3, 0x4}; // TX Data unsigned char ucRXMsgData[4] = {0, 0, 0, 0}; // RX Data uint32_t messageSize = sizeof(ucTXMsgData); // Message Size (DLC) volatile unsigned long msgCount = 0; // A counter that keeps track of the // number of times the transmit was // successful. volatile unsigned long errFlag = 0; // A flag to indicate that some // transmission error occurred. static const uint16_t canBitValues[] = { 0x1100, // TSEG2 2, TSEG1 2, SJW 1, Divide 5 0x1200, // TSEG2 2, TSEG1 3, SJW 1, Divide 6 0x2240, // TSEG2 3, TSEG1 3, SJW 2, Divide 7 0x2340, // TSEG2 3, TSEG1 4, SJW 2, Divide 8 0x3340, // TSEG2 4, TSEG1 4, SJW 2, Divide 9 0x3440, // TSEG2 4, TSEG1 5, SJW 2, Divide 10 0x3540, // TSEG2 4, TSEG1 6, SJW 2, Divide 11 0x3640, // TSEG2 4, TSEG1 7, SJW 2, Divide 12 0x3740 // TSEG2 4, TSEG1 8, SJW 2, Divide 13 }; typedef enum { //! Transmit message object. MSG_OBJ_TYPE_TRANSMIT, //! Receive message object. MSG_OBJ_TYPE_RECEIVE } msgObjType; // // Function Prototypes // uint32_t setCANBitRate(uint32_t sourceClock, uint32_t bitRate); void setupMessageObject(uint32_t objID, uint32_t msgID, msgObjType msgType); void sendCANMessage(uint32_t objID); bool getCANMessage(uint32_t objID); void main(void) { // Step 1. Initialize System Control: // PLL, WatchDog, enable Peripheral Clocks // This example function is found in the F2837xD_SysCtrl.c file. InitSysCtrl(); // Step 2. Initialize GPIO: // This example function is found in the F2837xD_Gpio.c file and // illustrates how to set the GPIO to it's default state. InitGpio(); InitTimer(); //Function defined in My_headers/Timer_Init.h InitADC_Boost(); //Function defined in My_headers/ADC_Init.h InitADC_ZVSFB(); //Function defined in My_headers/ADC_Init.h initBoostGPIO(); //Function defined in My_headers/Gpio_Init.h initZVSFBGPIO(); //Function defined in My_headers/Gpio_Init.h init_I2C(); //Function defined in My_headers/I2C_Init.h EALLOW; CpuSysRegs.PCLKCR0.bit.TBCLKSYNC = 0; //Disable clocking to the TBCTR register in the EPWM modules EDIS; InitBoostEPwm(); //Function defined in My_headers/EPwm_Init.h InitZVSFBEpwm(); //Function defined in My_headers/EPwm_Init.h EALLOW; CpuSysRegs.PCLKCR0.bit.TBCLKSYNC = 1; //Enable clocking to the TBCTR register in the EPWM modules EDIS; // Step 3. 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(); EALLOW; PieVectTable.TIMER0_INT = &cpu_timer0_isr; //In the PIEVectTable the adress of the ISR is written. The interrupt is defined in My_headers/CPUTimer_Interrupts.h PieVectTable.I2CA_INT = &i2ca_isr; // In the PIEVectTable the adress of the ISR is written. The interrupt is defined in My_headers/I2C_Interrupts.h EDIS; IER |= M_INT1; //Enable CPU PIE group 1 (U toj grupi su prekidi za Timer0 i ADCA1) IER |= M_INT8; //Enable CPU PIE group 8 (U toj grupi su prekidi za I2CA) PieCtrlRegs.PIEIER1.bit.INTx7 = 1; //Timer0 interrupt is in PIE group 1, and channel 7 PieCtrlRegs.PIEIER8.bit.INTx1 = 1; //I2CA interrupt is in PIE group 8, channel 1 // Enable global Interrupts and higher priority real-time debug events: EINT; // Enable Global interrupt INTM ERTM; // Enable Global realtime interrupt DBGM Uint16 array[20]={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19}; i2c_eeprom_write(array, 20, 0x00, 0x00); //Function defined in My_headers/I2C_functions Uint16 array2[20]; __asm(" ESTOP0"); i2c_eeprom_read(array2, 20, 0x00, 0x00); //Function defined in My_headers/I2C_functions for(;;) { GpioDataRegs.GPBDAT.bit.GPIO40 = ulazni_relej ; GpioDataRegs.GPBDAT.bit.GPIO42 = 1 - boost_pwm_en; } } // End of file
The error I get when debugging can be seen in the following image:
I would like to add here that the program goes through all the initialization succesfully, and also completes the I2C communciation before the infinite for (;;) loop in the main function. This for loop is used for control purposes. A few things I've observed :
1. Once the program is free running (not using Step into and step through functions), it terminates if the two variables from the infinite for(;;) loop and the "enable" variable are set to a "1". The enable variable is used for starting the regualtor inside the cpu_timer0_isr, that is to say it starts a lot of computing every control cycle. This worked fine before adding the CAN variables and function declarations.
2. If I comment and/or completely remove the CAN definitions and function declaration, the problem still persists, even though this program worked just fine before adding the CAN stuff. Tried this on a completely factory new processor. Still same issue.
3. I thought this was a stack overflow issue, so I incresed the stack size in Project Properties -> C2000 Linker -> Basic Options -> Set C system stack size -> 0x400 (the full M1 RAM as defined in the linker)
What are your suggestions for solving this issue? Do you have any general guidelines for writing code that would have prevented this (I use a lot of global variables)?
Hi,
Few more questions that will help me in better understanding of the issue
1 . Is the code "__asm(" ESTOP0");" added intentionally. Ideally ,this command stops the emulation at this line. This is useful only during debugging but should be removed later on.
2. What do you mean by the program gets terminated? Does it get stuck at a particular line of code? Can you the call stack to figure out the execution flow?
3. Ideally the number of global variables should be limited in the code.
Best Regards
Siddharth
1. That part of code is added intentionally. As far as I can tell, it didn't cause any problem whatsoever. I was able to single-step through it.
2. CCS stops the debugger, not allowing me to resume the debug session. From the image above, it seems to be halted at ESTOP0 (at the address 0x3fe493) as can be seen in the disassembly view. It gets stuck when it tries to do some computing inside the control loop and the measured values are ≠ 0. How can I call stack to see the execution flow?
3. I will try to do this in the future.
Hi Emir,
Is there any reason for using "ESTOP" instruction? Why is it added? the ESTOP instruction works only if you have an emulator connected to the board.
In case , you want to add a delay , you can use NOP instruction instead of ESTOP.
Best Regards
Siddharth
It was used only for debug purposes, and not for delays. I will try running the code without it, but I doubt that is the source of my problem here.
Hi ,
Did you try running without the ESTOP instruction?
Refer the following thread to see how to check the call stack in CCS
Best Regards
Siddharth
1. I tried running without the ESTOP instructions. During debug one of the variables which control some of the relays on my PCB started getting totally random values assigned to them. This caused the relay contacts to go crazy. I would like to add here : none of this happened before I added definitions of global CAN variables and CAN function prototypes which I have now removed.
2. Here is the call stack during debug :
The things I will try to do to solve the issue:
1. Try using less global variables
2. Try using less float type variables
Hi,
After you removed the ESTOP instruction , did the program break or continued to execute?
The variable that you mentioned getting assigned random values - is it a global variable?
The call stack indicates that you are getting timer interrupt while executing from main. You can check the code of this ISR to see if something is causing the variable corruption.
Best Regards
Siddharth