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.
Tool/software: Code Composer Studio
Hello,
I tried working on the adc_soc example. I plan to generate adc_isr and epwm_isr such that the adc_isr will give me an average of 10 successive reading and the epwm_isr will update its CMPA registar with this average value. The code looks a little okay however its performance is pretty awful. I am always getting 100% duty cycle. It is as if the cmpa is not really being updated. I have gone over the code over and over, I simply don't know where I have gone wrong... but I have a feeling the issue will be something very little.
By the way, I read somewhere that adc_isr has a higher priority than epwm_isr, but since the adc is meant to be triggered by the epwm SOCA, does that mean in the very first conversion, the output of the adc will be zero as it has not yet been legitimately triggered so there will be no conversion?
I'd appreciate any advice and pointers these 2 issues.
Thanks.
David
#include "DSP28x_Project.h" // Device Headerfile and Examples Include File // Prototype statements for functions found within this file. __interrupt void adc_isr(void); __interrupt void epwm4_isr(void); void Gpio_select(void); //void Setup_ePWM1A(void); //void Setup_ePWM2A(void); //void Setup_ePWM3A(void); void Setup_ePWM4A(void); // Global variables used in this example: Uint16 i; Uint16 LoopCount; Uint16 Voltage1[10]; float VoltageAve; main() { // Step 1. Initialize System Control: // PLL, WatchDog, enable Peripheral Clocks // This example function is found in the DSP2833x_SysCtrl.c file. InitSysCtrl(); EALLOW; #if (CPU_FRQ_150MHZ) // Default - 150 MHz SYSCLKOUT #define ADC_MODCLK 0x3 // HSPCLK = SYSCLKOUT/2*ADC_MODCLK2 = 150/(2*3) = 25.0 MHz #endif #if (CPU_FRQ_100MHZ) #define ADC_MODCLK 0x2 // HSPCLK = SYSCLKOUT/2*ADC_MODCLK2 = 100/(2*2) = 25.0 MHz #endif EDIS; // Define ADCCLK clock frequency ( less than or equal to 25 MHz ) // Assuming InitSysCtrl() has set SYSCLKOUT to 150 MHz EALLOW; SysCtrlRegs.HISPCP.all = ADC_MODCLK; EDIS; // Step 2. Initialize GPIO: // This example function is found in the DSP2833x_Gpio.c file and // illustrates how to set the GPIO to it's default state. // InitGpio(); // Skipped for this example Gpio_select(); // 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 DSP2833x_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 DSP2833x_DefaultIsr.c. // This function is found in DSP2833x_PieVect.c. InitPieVectTable(); // Interrupts that are used in this example are re-mapped to // ISR functions found within this file. EALLOW; // This is needed to write to EALLOW protected register PieVectTable.ADCINT = &adc_isr; PieVectTable.EPWM4_INT = &epwm4_isr; EDIS; // This is needed to disable write to EALLOW protected registers // Step 4. Initialize all the Device Peripherals: // This function is found in DSP2833x_InitPeripherals.c // InitPeripherals(); // Not required for this example InitAdc(); // For this example, init the ADC // Step 5. User specific code, enable interrupts: // Enable ADCINT in PIE PieCtrlRegs.PIEIER1.bit.INTx6 = 1; PieCtrlRegs.PIEIER3.bit.INTx4 = 1; IER |= 5; // Enable CPU Interrupt 1 and 3 EINT; // Enable Global interrupt INTM ERTM; // Enable Global realtime interrupt DBGM LoopCount = 0; //ConversionCount = 0; // Configure ADC AdcRegs.ADCMAXCONV.all = 0; // Setup 1 conv's on SEQ1 ie number of conversion - 1 AdcRegs.ADCCHSELSEQ1.bit.CONV00 = 0x4; // Setup ADCINA4 as 1st SEQ1 conv. AdcRegs.ADCTRL1.bit.ACQ_PS = 15; //time between multiplexer switch and freezing of samples AdcRegs.ADCTRL1.bit.CONT_RUN = 1; //Start all over again at the end of the 1st conversion w/o waiting for another trigger input signal AdcRegs.ADCTRL1.bit.SEQ_CASC = 1; //Cascaded mode AdcRegs.ADCTRL1.bit.CPS = 0; //ADCCLK = FCLK/CPS+1 = FCLK = 12.5MHz AdcRegs.ADCTRL2.bit.EPWM_SOCA_SEQ1 = 1; // Enable SOCA from ePWM to start SEQ1 AdcRegs.ADCTRL2.bit.INT_ENA_SEQ1 = 1; // Enable SEQ1 interrupt AdcRegs.ADCTRL2.bit.INT_MOD_SEQ1 = 0; // Enable SEQ1 interrupt every EOS AdcRegs.ADCTRL3.bit.SMODE_SEL = 0; //SEQUENTIAL SAMPLING AdcRegs.ADCTRL3.bit.ADCCLKPS = 1; //FCLK = HSPCLK/2*ADCCLKPS = FCLK/2 = 12.5MHz // Assumes ePWM1 clock is already enabled in InitSysCtrl(); Setup_ePWM4A(); // Wait for ADC interrupt for(;;) { LoopCount++; } } void Gpio_select(void) { EALLOW; GpioCtrlRegs.GPAMUX1.all = 0; // GPIO15 ... GPIO0 = General Puropse I/O //GpioCtrlRegs.GPAMUX1.bit.GPIO0 = 1; //GpioCtrlRegs.GPAMUX1.bit.GPIO2 = 1; //GpioCtrlRegs.GPAMUX1.bit.GPIO4 = 1; GpioCtrlRegs.GPAMUX1.bit.GPIO6 = 1; GpioCtrlRegs.GPAMUX2.all = 0; // GPIO31 ... GPIO16 = General Purpose I/O GpioCtrlRegs.GPBMUX1.all = 0; // GPIO47 ... GPIO32 = General Purpose I/O GpioCtrlRegs.GPBMUX2.all = 0; // GPIO63 ... GPIO48 = General Purpose I/O GpioCtrlRegs.GPCMUX1.all = 0; // GPIO79 ... GPIO64 = General Purpose I/O GpioCtrlRegs.GPCMUX2.all = 0; // GPIO87 ... GPIO80 = General Purpose I/O GpioCtrlRegs.GPADIR.all = 0; //GpioCtrlRegs.GPADIR.bit.GPIO0 = 1; // peripheral explorer: LED LD1 at GPIO0 //GpioCtrlRegs.GPADIR.bit.GPIO2 = 1; // peripheral explorer: LED LD1 at GPIO2 //GpioCtrlRegs.GPADIR.bit.GPIO4 = 1; // peripheral explorer: LED LD1 at GPIO4 GpioCtrlRegs.GPADIR.bit.GPIO6 = 1; // peripheral explorer: LED LD1 at GPIO6 GpioCtrlRegs.GPBDIR.all = 0; // GPIO63-32 as inputs GpioCtrlRegs.GPCDIR.all = 0; // GPIO87-64 as inputs EDIS; } __interrupt void adc_isr(void) { for (i=0;i<10;i++) { Voltage1[i] = AdcMirror.ADCRESULT0; VoltageAve += Voltage1[i]; } VoltageAve = (3*VoltageAve)/10/4096; // Reinitialize for next ADC sequence AdcRegs.ADCTRL2.bit.RST_SEQ1 = 1; // Reset SEQ1 AdcRegs.ADCST.bit.INT_SEQ1_CLR = 1; // Clear INT SEQ1 bit PieCtrlRegs.PIEACK.all = PIEACK_GROUP1; // Acknowledge interrupt to PIE return; } __interrupt void epwm4_isr(void) { EPwm4Regs.CMPA.half.CMPA = VoltageAve*(EPwm4Regs.TBPRD); // Reinitialize for next ADC sequence EPwm4Regs.ETCLR.bit.INT = 1; // Clear INT SEQ1 bit PieCtrlRegs.PIEACK.all = PIEACK_GROUP3; // Acknowledge interrupt to PIE return; } void Setup_ePWM4A(void) { EPwm4Regs.TBCTL.bit.CLKDIV = 0; //SysClkOut/1 ie default EPwm4Regs.TBCTL.bit.HSPCLKDIV = 1; //SysClkOut/2 ie default EPwm4Regs.TBCTL.bit.CTRMODE = 0; //UP COUNT EPwm4Regs.TBCTL.bit.PRDLD = 0; //TBPRD period shadow, load on ctr = 0 EPwm4Regs.TBCTL.bit.SYNCOSEL = 3; //disable sync output select EPwm4Regs.TBPRD = 4989/22; //330kHz EPwm4Regs.CMPA.half.CMPA = 0; //initial CMPA = 0 EPwm4Regs.AQCTLA.all = 0x0012; //ctr = 0 (set), ctr = cmpa on up count (clear) EPwm4Regs.ETSEL.bit.SOCAEN = 1; // Enable SOC on A group EPwm4Regs.ETSEL.bit.SOCASEL = 1; // Select SOC from CTR=0 EPwm4Regs.ETPS.bit.SOCAPRD = 1; // Generate pulse on 1st event EPwm4Regs.ETSEL.bit.INTEN = 1; // enable pwm interrupt EPwm4Regs.ETSEL.bit.INTSEL = 2; // enable interrupt on ctr = PRD EPwm4Regs.ETPS.bit.INTPRD = 1; // interrupt on 1st event }
Hi David,
Regarding your CMPA update question, have you checked whether Voltage1 and VoltageAve variables are being updated as expected? If not, you could consider adding the volatile keyword for these variables.
Can you confirm that both the ADC and EPWM ISRs are generated by placing breakpoints inside the ISRs and seeing whether they are reached?
Regards,
Elizabeth
Thank you very much.
1. Leftover issue: I think I can solve that by just placing
VoltageAve = 0;
before the for loop. I guess I just thought it will be overwritten by
Voltage1[i] = AdcMirror.ADCRESULT0;
maybe I was wrong.
2. About superfluous addition, my plan is to take 10 successive samples and average them instead of just accepting a single sample without query. Maybe my approach is wrong as I am not really an experienced programmer.
Can you advise me on a better approach, pls?
Regards.
David.
Hi David,
I focus on FPGA's and not C programming but since you asked:
My interpretation is that AdcMirror.ADCRESULT0 is not changing over your summing period.
Do you agree? My interpretation could be wrong.
Usually I do not respond to questions that result in more work for me, but that is not always the case.
This is from the Example_2833xAdcSoc.c file
__interrupt void adc_isr(void)
{
Voltage1[ConversionCount] = AdcRegs.ADCRESULT0 >>4;
Voltage2[ConversionCount] = AdcRegs.ADCRESULT1 >>4;
// If 40 conversions have been logged, start over
if(ConversionCount == 9)
{
ConversionCount = 0;
}
else
{
ConversionCount++;
}
// ******************************************************* insert begin
// this may not be entirely correct and has not been tested
// TI typically does something like this and they call it a box car average.
// They have a note that says it is not part of the control loop but is for the GUI
VoltageAve = 0;
for
(i=0;i<10;i++)
{
VoltageAve += Voltage1[i];
}
VoltageAve = (3*VoltageAve)/10/4096;
//*************************************** insert end
// Reinitialize for next ADC sequence
AdcRegs.ADCTRL2.bit.RST_SEQ1 = 1; // Reset SEQ1
AdcRegs.ADCST.bit.INT_SEQ1_CLR = 1; // Clear INT SEQ1 bit
PieCtrlRegs.PIEACK.all = PIEACK_GROUP1; // Acknowledge interrupt to PIE
return;
}
Thanks a lot for your efforts.
I appreciate you.
I just tried compiling the corrected code and it keeps saying "unrecognized token", I sincerely don't know why! I'll still keep checking though...
Kind regards.
David.
It may need
Uint16 ConversionCount;
Uint16 Voltage2[10];
after // Global variables used in this example: towards the top of the file.
or you can delete all references to Voltage2;
This post suggested adding --verbose_diagnostics to see where it is coming from
https://e2e.ti.com/support/development_tools/compiler/f/343/p/435084/1557966?tisearch=e2e-sitesearch&keymatch=*F283*%20unrecognized%20token#1557966
Perhaps if you cut and pasted code from the posting to the editor, some funny characters confused the compiler.
Thanks a lot.
"Volatile float" really helped a lot but the loop still didn't work
what I am using now is something like this:
VoltageAve = Voltage1[0]+Voltage1[1]+Voltage1[2]+Voltage1[3]+Voltage1[4]+Voltage1[5]+Voltage1[6]+Voltage1[7]+Voltage1[8]+Voltage1[9];
I know it is super crude but I don't know why the loop doesn't work as expected.
I appreciate all your efforts.
David.