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.

TMDSPREX28335: Technical issues

Part Number: TMDSPREX28335
Other Parts Discussed in Thread: C2000WARE

Hi team,

Since my customer can't post on the forum, I submit a question for him.

"I am using a TMDSPREX28335 board and I am trying to dump two signals:
1) an external 50 Hz sinusoidal signal ranging between 1 Volt and 2 Volt
2) a DC signal which is 1 V

After converting the signals in a proper manner I tried to watch the external AC signal and an internally generated unit amplitude 50 Hz sine wave in the same graph window. I found two anomalies while viewing the externally dumped 50 Hz signal in the graph window. They are as follows:

a) The frequency is much more than 50 Hz
b) The data is not getting logged properly and there are abrupt discontinuities in the obtained plot

The code that I am using for ADC initialization, sine wave generation and plotting the data is as follows:

// Global variables used in this example
Uint32 EPwm3TimerIntCount, EPwm5TimerIntCount, CpuTimer0IntCount = 1;
float duty = 0.405, omega = 2*3.1415926535*50, ref_sine = 0, time = 0, ref_sine_offset = 0, wt = 0, wt_offset = 0;
float ref_sine_n = 0, ref_sine_offset_n = 0;
float voltage_grid = 0, voltage_pv = 0, current_grid = 0, current_pv = 0, voltage_offset = 0;

// Variables used for plotting
int plot_count = 0, sample = 0;
float array_sine[400][2], array_sine_offset[400];
void main(void)
{
InitSysCtrl();
DINT; // disable CPU interrupts
InitPieCtrl(); // disable all peripheral interrupts
InitEPwmTimer(); // initiate the required ePWM registers and configure interrupt requirements
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.CONT_RUN = 1; // continuous run mode for ADC
AdcRegs.ADCTRL1.bit.SEQ_CASC = 1; // cascaded mode for ADC (16 states)


AdcRegs.ADCTRL2.all = 0; // clear ADCTRL2 before initializing
AdcRegs.ADCTRL2.bit.SOC_SEQ1 = 1; // start SEQ1
// AdcRegs.ADCTRL2.bit.RST_SEQ2 = 1; // reset SEQ2
// AdcRegs.ADCTRL2.bit.INT_ENA_SEQ1 = 1; // enable interrupt on SEQ1

AdcRegs.ADCTRL3.bit.SMODE_SEL = 0; // sequential simultaneous conversion for ADC
AdcRegs.ADCTRL3.bit.ADCCLKPS = 3; // 3 because 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 = 0xa; // assign ADCINB2 to conv01
AdcRegs.ADCCHSELSEQ1.bit.CONV01 = 0x3; // assign ADCINA3 to conv02
// AdcRegs.ADCCHSELSEQ1.bit.CONV03 = 11; // assign ADCINB3 to conv03
// AdcRegs.ADCCHSELSEQ2.bit.CONV04 = 4; // assign ADCINA4 to conv04
//************ADC INITIALISATION and CONFIGURATION ENDS************//




EALLOW; // This is needed to write to EALLOW protected registers
PieVectTable.TINT0 = &cpu_timer0_isr;
PieVectTable.EPWM3_INT = &epwm3_timer_isr;
PieVectTable.EPWM5_INT = &epwm5_timer_isr;
EDIS;

ConfigCpuTimer(&CpuTimer0, 150, 25); // generate TINT0 at 25 us or 40 kHz
CpuTimer0Regs.TCR.all = 0x4000;


// Initialize counters:
EPwm3TimerIntCount = 1;
EPwm5TimerIntCount = 1;

IER |=1; // enable timer0 interrupt
IER |=4; // enable INT3 for ePWM3 and ePWM5
/* Enable TINT0
// Enable EPWM3A INT in the PIE: Group 3 interrupt 3
// Enable EPWM5A INT in the PIE: Group 3 interrupt 5
*/
PieCtrlRegs.PIEIER1.bit.INTx7=1;
PieCtrlRegs.PIEIER3.bit.INTx3=1;
PieCtrlRegs.PIEIER3.bit.INTx5=1;

// Enable global Interrupts and higher priority real-time debug events:
EINT; // Enable Global interrupt INTM
ERTM; // Enable Global realtime interrupt DBGM

}
interrupt void cpu_timer0_isr(void)
{
CpuTimer0IntCount++;

//****************************READ VALUES FROM ADC BEGINS****************************//
voltage_grid = AdcRegs.ADCRESULT0>>4; // read grid voltage from ADCINA2 into voltage_grid from ADCResult2 register
current_grid = AdcRegs.ADCRESULT1>>4; // read grid current from ADCINB2 into current_grid from ADCResult3 register
// voltage_pv = AdcRegs.ADCRESULT6>>4; // read pv voltage from ADCINA3 into voltage_pv from ADCResult6 register
// current_pv = AdcRegs.ADCRESULT7>>4; // read pv current from ADCINB3 into current_pv from ADCResult7 register
// voltage_offset = AdcRegs.ADCRESULT8>>4; // read reference voltage from ADCINA4 into voltage_offset from ADCResult8 register
AdcRegs.ADCST.bit.INT_SEQ1_CLR = 1; // clear interrupt generated by SEQ1
//****************************READ VALUES FROM ADC ENDS****************************//

if (time > 0.02)
time=0;
wt = omega*time;
wt_offset = omega*(time - 0.0001); // offset of 100 microseconds for the second sine wave
ref_sine = fabs((sin(wt)));
ref_sine_n = sin(wt);
ref_sine_offset = fabs(sin(wt_offset));
ref_sine_offset_n = sin(wt_offset);

if (plot_count == 0)
{
if(sample > 399)
sample = 0;
array_sine[sample][0] = voltage_grid/1000;
array_sine[sample][1] = ref_sine_n;
array_sine_offset[sample] = ref_sine_offset_n;
sample++;
plot_count = 2;
}
plot_count--;
time = time + 0.000025;
PieCtrlRegs.PIEACK.all = PIEACK_GROUP1;
}

And the plot in question is as follows:


As you can see the data is not getting logged properly and compared to the internal sine, the sine obtained from ADC is at least 5 times faster."

Thank you very much for your help.

Best regards,
  • I believe the issue is that your time base for the ADC samples is set incorrectly.  You have set the CONT_RUN bit, which will force the ADC to sample continuously after the first AdcRegs.ADCTRL2.bit.SOC_SEQ1 = 1; // start SEQ1 time the instruction is executed.

    Using your register  settings of ADC Clock = 12.5MHz and ACQPS = 16, this would equate to a sustained sample every 293ns or 3.409MSPS. 

    If you disable CONT_RUN then the SW write above will trigger a new sample each time, likely at the timer rate you have specified of 25us.  If you are using the CPU Timer to control the SOC, it may be more deterministic to tie the SOC to an PWM that is free running at the same timebase you want to sample at.  This way you don't run the risk of any CPU event changing the sample rate timings.

    The example shown here will give the register settings for PWM control of the SOC

    C:\ti\c2000\C2000Ware_4_01_00_00\device_support\f2833x\examples\adc_soc

    There are some other examples in that directory that will give help to use the DMA as well to capture the data.

    Best,

    Matthew

  • Dear Matthew and Zhonghui,

    I’ll begin by thanking both of you. I am grateful to Zhonghui for posting this query on my behalf and thank you Matthew for such a prompt, and, kind response.

    In your response, Matthew, you mention

    1. a) Cont_run = 1 may be the reason why this issue is arising.

    My answer to this concern is as follows:

    Even though cont_run is 1, until the SEQ1 interrupt flag is cleared there cannot (or rather should not) be any further conversions. This according to my understanding should translate into only one set of conversions every 25 us.

    And even if we go by your assumption that simultaneous/continuous conversion is happening, there should only be one maxima and one minima in every 20 ms because the external signal is a 50 Hz sinusoid. Continous conversion should mean that a greater number of converted samples are available which would actually increase the precision of the obtained plot without violating the basic properties of the dumped signal. But as is visible in the image that I provided earlier clearly the converted signal has a frequency which is way beyond 50 Hz and that too with multiple discontinuities (this is the second part of my problem which remains unanswered).

    How can the fundamentals be violated and the obtained frequency becomes completely different from the original frequency?

    Or could it be that I should pass the converted signal through a low pass filter (in software; there’s already a RC (R = 120 ohms and C = 0.33 uF) LPF in hardware before ADC) before logging it in the graph window?

    1. b) Because of ADC clock being 12.5 Mhz and ACQPS being 16, the conversion frequency is 3.409 MSPS (or one sample every 293 ns).

    Because I was unable to figure out the maths behind these numbers would you be kind enough to explain it to me?

    The thing is that as per my PWM system and as per my requirement SOFTWARE Interrupt is the only possible interrupt that I may use. To increase the logging precision, I have used it in conjunction with the CPU TIMER Interrupt.

    I shall rerun the code with cont_run=0, SEQ1 being reset every 25 us in the CPU interrupt and post fresh image tomorrow. However, until then, would you please have a look at the rebuttals that I have in my defence as per my understanding?

     

    Thanks a lot in advance and keeping fingers crossed for a permanent remedy.

     

    With Regards,

    Ankit

    VIT, Vellore, India

  • Ankit,

    Will look for your update on CONT_RUN =0, setting this bit supercedes the SEQ1 interrupt flag behavior that would normally pause the converter until the flag is clear.

    Best,

    Matthew

  • Dear Matthew and Zhonghui,

     

    I apologize for replying to both of you with a delay of more than 48 hours. I was busy with testing the ADC under different conditions.

     

    Matthew,

    From your explanation I now understand the ramifications of setting the bit cont_run to 1. I genuinely appreciate the insight provided by you. Thanks a lot for it.

    I certainly would not question/argue with/doubt someone who has decades worth of experience and knowledge about the C2000 controllers, because each of these controllers is an ocean of knowledge. HATS OFF to every single soul involved/associated with these C2000 processors from the very 1st day till present times.

    However, I was able to debug my code on my own, run the ADC and that too with the following settings:

    cont_run = 1; (as per you this should be cont_run =0;)

    cascaded state (16 states)

    sequential sampling (channel A followed by channel B)

    ACQ_PS = 0xf; (15+1=16 ADC cycle hold)

    SOC_SEQ1 tied to CpuTimer0 interrupt every 25 us (40 kHz)

     

    The issue had surfaced because I had not included the following line in my ADC initialization:

    InitCpuTimers();

    before

    ConfigCpuTImer(&CpuTimer0, 150, 25);

    Not including InitCpuTImers was the bug in my code. Now the ADC is working as I expected it to.

    I just have one last query. Could you please explain how because of ADC clock being 12.5 Mhz and ACQPS being 16, the conversion frequency is 3.409 MSPS (or one sample every 293 ns)?

     

    With Regards,

    Ankit

    VIT, Vellore, India

     

    PS: I will also try ADCSoC with ePWM interrupt as well.

  • Ankit,

    Thanks for the update, and no need to apologize, this is why we have the E2E forum to give help to our customers. :)

    After re-doing the numbers I realize I had made a mistake, if ACQPS = 16 ADC Clocks, that would already limit the sample time to 1.28us or 781.25kSPS w/o converting the sample!

    For the sample rate calculation below is a table from the device TRM on page 449.

    I'll take it from 5th column of the table, ADC clock = 12.5MHz

    Acquisition time is set as ACQPS=15, so this becomes (15+1) *(1/12.5MHz) = 1.28us.  So each time we sample the ADC Input pin we will keep the switch to the sample/hold cap closed for 1.28us before converting the value.

    Here is where things get interesting based on the topology of this particular converter.

    The first sample, after the S/H phase is complete will take 4 ADC Clock cycles to complete

    So for a single sample we have 1.28us for sample and 4*(1/12.5MHz) = 320ns or 1.28us+320ns = 1.6us total. 

    If you only sample a single channel per trigger(which is what you will do, CONT_RUN = 0), then the above is just the delay from your trigger to when the sample is ready, and your "sample rate" is really defined as your trigger rate(either from CPU timer or otherwise).

    However, with CONT_RUN=1, the ADC will begin a new conversion as soon as possible, which is after 2 ADC Clock cycles after the prior conversion(we are taking advantage of the ADC architecture here and not waiting the 4ADC clocks for full conversion).  So in the above case that would be 1.28us of acquisition time + 2*(1/12.5MHz) = 160ns or 1.28us+160ns = 1.44us or 1/1.44us = 694.444kSPS, which is what I think you were getting with CONT_RUN=1.

    Hopefully this clears things up.

    Best,

    Matthew

  • Dear Matthew,

    Thanks a lot for such a detailed explanation.
    As of now my questions related to ADC configuration have all been answered in detail by you.

    You may close this thread now.

    With Regards,
    Ankit

    VIT, Vellore, India