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
}