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 }