Other Parts Discussed in Thread: C2000WARE, CONTROLSUITE
Hi Team,
I'm posting on behalf of the customer.
I am using a TMDSPREX28335 board. I am trying to dump an external sinusoidal signal (grid voltage which is 50 Hz) into the controller using its ADC port. The signal is well conditioned and is between the safety limits of 0 and 3 Volts.
Initially, I had tied the ADC to CPU Timer0 Interrupt (happening every 25 micro seconds or 40 kHz) and observed the signal in the GRAPH window.
The code for ADC triggered by CPU TIMER0 Interrupt is as follows:
#include "math.h"
#include "IQmathlib.h"
#include "DSP2833x_Device.h" // DSP2833x Headerfile Include File
#include "DSP2833x_Examples.h" // DSP2833x Examples Include File
// Prototype statements for functions found within this file.
interrupt void cpu_timer0_isr(void);
// Variables used for plotting, reading from ADC and interrupt count
Uint32 count=1;
int sample = 0;
float array_sine[800];
float voltage_grid = 0, vg1 = 0, voltage_offset = 0, voft1 = 0;
main()
{
InitSysCtrl();
// EALLOW;
// SysCtrlRegs.HISPCP.all = 0x3; // HSPCLK = SYSCLKOUT/6
// EDIS;
DINT; // disable CPU interrupts
InitPieCtrl(); // disable all peripheral interrupts
EALLOW;
SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC = 0; // Stop all the TB clocks
EDIS;
EALLOW;
SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC = 1; // Start all the timers synced
EDIS;
IER = 0x0000; // disables all interrupts
IFR = 0x0000; // clears flags of all interrupts
InitPieVectTable();
//************ADC INITIALISATION and CONFIGURATION BEGINS************//
InitAdc(); // basic ADC setup (including calibration)
AdcRegs.ADCTRL1.all = 0; // clear ADCTRL1 before initializing
AdcRegs.ADCTRL1.bit.ACQ_PS = 0xf; // sample and hold for (15+1)=16 ADC cycles
AdcRegs.ADCTRL1.bit.CPS = 0; // divide further by 1
AdcRegs.ADCTRL1.bit.SEQ_CASC = 1; // cascaded mode for ADC (16 states)
AdcRegs.ADCTRL1.bit.CONT_RUN = 0; // continuous run mode for ADC disabled
// AdcRegs.ADCTRL2.all = 0; // clear ADCTRL2 before initializing
AdcRegs.ADCTRL2.bit.INT_ENA_SEQ1 = 1; // enable interrupt on SEQ1
AdcRegs.ADCTRL2.bit.INT_MOD_SEQ1 = 0; // enable interrupt every end of sequence
AdcRegs.ADCTRL2.bit.RST_SEQ1 = 1; // reset SEQ1
AdcRegs.ADCTRL2.bit.SOC_SEQ1 = 0; // start SEQ1 from ePWM1_SOCA trigger
AdcRegs.ADCTRL3.bit.SMODE_SEL = 0; // sequential simultaneous conversion for ADC
AdcRegs.ADCTRL3.bit.ADCCLKPS = 3; // 3 because HSPCLK for ADC is 75 Mhz (150/6); see above
// from DSP2833x_SysCtrl.c FCLK for ADC is 75 MHz and not 150 MHz;
// 75/(2*3) = 12.5 MHz
AdcRegs.ADCMAXCONV.all = 0x0001; // 2 conversions
AdcRegs.ADCCHSELSEQ1.bit.CONV00 = 0x2; // assign ADCINA2 to conv00
AdcRegs.ADCCHSELSEQ1.bit.CONV01 = 0x3; // assign ADCINA3 to conv01
//************ADC INITIALISATION and CONFIGURATION ENDS************//
EALLOW; // This is needed to write to EALLOW protected registers
PieVectTable.TINT0 = &cpu_timer0_isr;
EDIS;
InitCpuTimers();
ConfigCpuTimer(&CpuTimer0, 150, 25); // generate TINT0 at 25 us or 40 kHz
CpuTimer0Regs.TCR.all = 0x4001; // disable cpu timer0 interrupt (not needed)
IER |= 1; // Enable all of INT1 group
PieCtrlRegs.PIEIER1.bit.INTx7 = 1; // enable ADC INT (6th interrupt in group 1)
EINT; // Enable Global interrupt INTM
ERTM; // Enable Global realtime interrupt DBGM
}
interrupt void cpu_timer0_isr(void)
{
count++; // check if interrupt is being generated
AdcRegs.ADCTRL2.bit.SOC_SEQ1 = 1;
voltage_grid = AdcRegs.ADCRESULT0>>4; // read from ADC
voltage_offset = AdcRegs.ADCRESULT1>>4; // read from ADC
vg1 = voltage_grid*3/4095; // get original value
voft1 = voltage_offset*3/4095; // get original value
if (sample > 799)
sample = 0;
array_sine[sample] = vg1;
sample++;
// 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
}
//===========================================================================
// End of SourceCode.
//===========================================================================
The graph corresponding to the above code is this:
As you can see there is a discontinuity in the (converted) viewed signal.
I then reattempted by giving command to the ADC from the ePWM1 Interrupt (under the same conditions i.e., every 25 micro seconds or 40 kHz). The code for ADCSoC from ePWM1 Interrupt is as follows:
/* OBJECTIVE:
* a) use ePWM1 triggered ADC interrupt at 25 us
* b) ADC in cascaded mode
* c) ADC does sequential sampling
* d) ACQ_PS = 0xf (15+1=16 hold cycles)
* e) ADC frequency is 12.5 MHz
* f) observe the plot
*/
#include "math.h"
#include "IQmathlib.h"
#include "DSP2833x_Device.h" // DSP2833x Headerfile Include File
#include "DSP2833x_Examples.h" // DSP2833x Examples Include File
// Prototype statements for functions found within this file.
void InitEPwmTimer(void);
interrupt void adc_isr(void);
// Variables used for plotting, reading from ADC and interrupt count
Uint32 count=1;
int sample = 0;
float array_sine[800];
float voltage_grid = 0, vg1 = 0, voltage_offset = 0, voft1 = 0;
main()
{
InitSysCtrl();
// EALLOW;
// SysCtrlRegs.HISPCP.all = 0x3; // HSPCLK = SYSCLKOUT/6
// EDIS;
DINT; // disable CPU interrupts
InitPieCtrl(); // disable all peripheral interrupts
EALLOW;
SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC = 0; // Stop all the TB clocks
EDIS;
InitEPwmTimer(); // initiate the required ePWM registers and configure interrupt requirements
EALLOW;
SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC = 1; // Start all the timers synced
EDIS;
IER = 0x0000; // disables all interrupts
IFR = 0x0000; // clears flags of all interrupts
InitPieVectTable();
//************ADC INITIALISATION and CONFIGURATION BEGINS************//
InitAdc(); // basic ADC setup (including calibration)
AdcRegs.ADCTRL1.all = 0; // clear ADCTRL1 before initializing
AdcRegs.ADCTRL1.bit.ACQ_PS = 0xf; // sample and hold for (15+1)=16 ADC cycles
AdcRegs.ADCTRL1.bit.CPS = 0; // divide further by 1
AdcRegs.ADCTRL1.bit.SEQ_CASC = 1; // cascaded mode for ADC (16 states)
AdcRegs.ADCTRL1.bit.CONT_RUN = 0; // continuous run mode for ADC disabled
// AdcRegs.ADCTRL2.all = 0; // clear ADCTRL2 before initializing
AdcRegs.ADCTRL2.bit.INT_ENA_SEQ1 = 1; // enable interrupt on SEQ1
AdcRegs.ADCTRL2.bit.INT_MOD_SEQ1 = 0; // enable interrupt every end of sequence
AdcRegs.ADCTRL2.bit.RST_SEQ1 = 1; // reset SEQ1
AdcRegs.ADCTRL2.bit.EPWM_SOCA_SEQ1 = 1; // start SEQ1 from ePWM1_SOCA trigger
AdcRegs.ADCTRL3.bit.SMODE_SEL = 0; // sequential simultaneous conversion for ADC
AdcRegs.ADCTRL3.bit.ADCCLKPS = 3; // 3 because HSPCLK for ADC is 75 Mhz (150/6); see above
// from DSP2833x_SysCtrl.c FCLK for ADC is 75 MHz and not 150 MHz;
// 75/(2*3) = 12.5 MHz
AdcRegs.ADCMAXCONV.all = 0x0001; // 2 conversions
AdcRegs.ADCCHSELSEQ1.bit.CONV00 = 0x2; // assign ADCINA2 to conv00
AdcRegs.ADCCHSELSEQ1.bit.CONV01 = 0x3; // assign ADCINA3 to conv01
//************ADC INITIALISATION and CONFIGURATION ENDS************//
EALLOW; // This is needed to write to EALLOW protected registers
PieVectTable.ADCINT = &adc_isr;
EDIS;
InitCpuTimers();
ConfigCpuTimer(&CpuTimer0, 150, 25); // generate TINT0 at 25 us or 40 kHz
// CpuTimer0Regs.TCR.all = 0x4001; // disable cpu timer0 interrupt (not needed)
IER |= 1; // Enable all of INT1 group
PieCtrlRegs.PIEIER1.bit.INTx6 = 1; // enable ADC INT (6th interrupt in group 1)
EINT; // Enable Global interrupt INTM
ERTM; // Enable Global realtime interrupt DBGM
}
void InitEPwmTimer(void)
{
EALLOW;
GpioCtrlRegs.GPAMUX1.bit.GPIO0 = 1; // ePWM1A active
GpioCtrlRegs.GPAMUX1.bit.GPIO1 = 1; // ePWM1B active
EDIS;
// ePWM 1 module clock sync disabled
// ePWM1 TBCTL INITIALISATIONS
EPwm1Regs.TBCTL.bit.FREE_SOFT = 11; // free run
EPwm1Regs.TBCTL.bit.PHSDIR = 1; // count up after sync
EPwm1Regs.TBCTL.bit.CLKDIV = 0; // TBCLK = HSPCLK/1
EPwm1Regs.TBCTL.bit.HSPCLKDIV = 1; // HSPCLK = SYSCLK/2
EPwm1Regs.TBCTL.bit.SWFSYNC = 0; // software sync disabled
EPwm1Regs.TBCTL.bit.SYNCOSEL = 3; // disable sync
EPwm1Regs.TBCTL.bit.PRDLD = 0; // load on CTR = 0
EPwm1Regs.TBCTL.bit.PHSEN = 0; // phase enable disabled
EPwm1Regs.TBCTL.bit.SYNCOSEL = 3; // disable sync
EPwm1Regs.TBCTL.bit.CTRMODE = 0; // count in up-mode
// ePWM1 ETPS INITIALISATIONS
EPwm1Regs.ETPS.bit.SOCBCNT = 0; // this is a read only bit
EPwm1Regs.ETPS.bit.SOCBPRD = 0; // disabled because interrupt is to be generated by ePWM1A
EPwm1Regs.ETPS.bit.SOCACNT = 0; // this is a read only bit
EPwm1Regs.ETPS.bit.SOCAPRD = 1; // interrupt is to be generated by ePWM1A every time
EPwm1Regs.ETPS.bit.INTCNT = 0; // read only bit doesn't matter
EPwm1Regs.ETPS.bit.INTPRD = 1; // generate interrupt every event
// ePWM1 ETSEL INITIALISATIONS
EPwm1Regs.ETSEL.bit.SOCBEN = 0; // disable SOCB
EPwm1Regs.ETSEL.bit.SOCBSEL = 0; // because SOCB is disabled
EPwm1Regs.ETSEL.bit.SOCAEN = 1; // enable SOCA
EPwm1Regs.ETSEL.bit.SOCASEL = 1; // generate interrupt when CTR = 0
EPwm1Regs.ETSEL.bit.INTEN = 0; // disable PWM interrupt
EPwm1Regs.ETSEL.bit.INTSEL = 0; // doesn't matter as PWM interrupt is disabled
// ePWM1 ETSEL INITIALISATIONS
EPwm1Regs.TBPRD = 1875; // fpwm = 40 khz = finterrupt
}
interrupt void adc_isr(void)
{
count++; // check if interrupt is being generated
voltage_grid = AdcRegs.ADCRESULT0>>4; // read from ADC
voltage_offset = AdcRegs.ADCRESULT1>>4; // read from ADC
vg1 = voltage_grid*3/4095; // get original value
voft1 = voltage_offset*3/4095; // get original value
if (sample > 799)
sample = 0;
array_sine[sample] = vg1;
sample++;
// 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
}
//===========================================================================
// End of SourceCode.
//===========================================================================
And the corresponding output in the graph window is as follows:
As you can see in both the cases (be it ADC connected to TIMER0 interrupt or ADC connected to ePWM1 interrupt) I am getting discontinuous data even though I am collecting 800 points (50 Hz = 20 milli seconds, 40 kHz = 25 us; 20m/25u = 800 points) and plotting all of them.
Another interesting thing is that even though the ADCTRL2 should either show 0x4800 or 0x2800 (depending on RST = 1 or SOC = 1) in case of TIMER0 Interrupt or 0x4900 or 0x0999 (depending on RST = 1 or 0) in case of SOC by ePWM1. However, ACTRL2 is maintaining a permanent value of 0x0800 for TIMER0 and 0x0900 for ePWM1.
Why is the data missing from the graph window in both cases and why is ADCTRL2 maintaining a permanent value?
Can the C2000 experts help me in debugging these issues because I have been trying to solve this issue for a couple of weeks now but the problem still exists.
I hope you can help.
Regards,
Marvin