hi all,
I am using a PWM to trigger my ADC ISR, when I toggle an output in the ADC ISR, The delay between each sampling is 400Khz. I need 800Khz at least.
has anyone an idea of what I am doing wrong to be so slow ???.
Thanks a million for your support,
greg.
void InitCan(void){ // Specific clock setting SysCtrlRegs.HISPCP.all = ADC_MODCLK; // HSPCLK = SYSCLKOUT/2*ADC_MODCLK // init the ADC, calibration InitAdc(); // ADC SETUP //sequential sampling mode AdcRegs.ADCTRL3.bit.SMODE_SEL = 0x0; AdcRegs.ADCMAXCONV.all = 0x0000; // Set up ADC to perform 1ere conversions on A0 AdcRegs.ADCCHSELSEQ1.bit.CONV00 = 0x0; // selection reference exterieure 2.048V AdcRegs.ADCREFSEL.bit.REF_SEL = 0x1; //enable ISR to CPU AdcRegs.ADCTRL2.bit.INT_MOD_SEQ1 = 0x0; AdcRegs.ADCTRL2.bit.INT_ENA_SEQ1 = 0x1; AdcRegs.ADCTRL1.bit.ACQ_PS = ADC_SHCLK; //ADC operates as a 16-state sequencer AdcRegs.ADCTRL1.bit.SEQ_CASC = 0x1; AdcRegs.ADCTRL3.bit.ADCCLKPS = ADC_CKPS; AdcRegs.ADCTRL2.bit.RST_SEQ1 = 0x1;}
interrupt void adc_isr(void){ GpioDataRegs.GPASET.bit.GPIO2 = 1; g_AdcMesure.uiVoieMes[g_iCptMes] = AdcRegs.ADCRESULT0 >>4; // Reinitialize for next ADC sequence AdcRegs.ADCTRL2.bit.RST_SEQ1 = 1; // Reset SEQ1 AdcRegs.ADCST.bit.INT_SEQ1_CLR = 1; // Clear INT SEQ1 bit // Acknowledge interrupt to PIE PieCtrlRegs.PIEACK.bit.ACK6 = 1; GpioDataRegs.GPACLEAR.bit.GPIO2 = 1;}
void InitEPwm(void){ // Initialize ePWM2//---------------------------------------------------------------------//--- Must disable the clock to the ePWM modules if you //--- want all ePMW modules synchronized.//--------------------------------------------------------------------- asm(" EALLOW"); // Enable EALLOW protected register access SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC = 0; asm(" EDIS"); // Disable EALLOW protected register access//---------------------------------------------------------------------//--- Configure ePWM2 to trigger the ADC at 800 kHz rate//--------------------------------------------------------------------- EPwm2Regs.TBCTL.bit.CTRMODE = 0x3; // Disable the timer EPwm2Regs.TBCTL.all = 0xC033; // Configure timer control register// bit 15-14 11: FREE/SOFT, 11 = ignore emulation suspend// bit 13 0: PHSDIR, 0 = count down after sync event// bit 12-10 000: CLKDIV, 000 => TBCLK = HSPCLK/1// bit 9-7 000: HSPCLKDIV, 000 => HSPCLK = SYSCLKOUT/1// bit 6 0: SWFSYNC, 0 = no software sync produced// bit 5-4 11: SYNCOSEL, 11 = sync-out disabled// bit 3 0: PRDLD, 0 = reload PRD on counter=0// bit 2 0: PHSEN, 0 = phase control disabled// bit 1-0 11: CTRMODE, 11 = timer stopped (disabled) EPwm2Regs.TBCTR = 0x0000; // Clear timer counter EPwm2Regs.TBPRD = ADC_SAMPLE_PERIOD; // // 187 = (187.5-1) = 150 MHz SYSCLKOUT / 800 KHz sampling EPwm2Regs.TBPHS.half.TBPHS = 0x0000; // Set timer phase EPwm2Regs.ETPS.all = 0x0100; // Configure SOCA// bit 15-14 00: EPWMxSOCB, read-only// bit 13-12 00: SOCBPRD, don't care// bit 11-10 00: EPWMxSOCA, read-only// bit 9-8 01: SOCAPRD, 01 = generate SOCA on first event// bit 7-4 0000: reserved// bit 3-2 00: INTCNT, don't care// bit 1-0 00: INTPRD, don't care EPwm2Regs.ETSEL.all = 0x0A00; // Enable SOCA to ADC// bit 15 0: SOCBEN, 0 = disable SOCB// bit 14-12 000: SOCBSEL, don't care// bit 11 1: SOCAEN, 1 = enable SOCA// bit 10-8 010: SOCASEL, 010 = SOCA on PRD event// bit 7-4 0000: reserved// bit 3 0: INTEN, 0 = disable interrupt// bit 2-0 000: INTSEL, don't care EPwm2Regs.TBCTL.bit.CTRMODE = 0x0; // Enable the timer in count up mode//---------------------------------------------------------------------//--- Enable the clocks to the ePWM module. //--- Note: this should be done after all ePWM modules are configured//--- to ensure synchronization between the ePWM modules.//--------------------------------------------------------------------- asm(" EALLOW"); // Enable EALLOW protected register access SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC = 1; // HSPCLK to ePWM modules enabled asm(" EDIS"); // Disable EALLOW protected register access }
Hi!
Your timer causes an interrupt every 188 clock cycles. Hence, your ADC interrupt service routine must be (a lot) faster than that. If it is not, you will miss interrupts. You use gpio2 as monitor for your isr runtime. How long does it take?
Best regards,Edwin Krasser
hi !!!
the period is 6.24µsec, the duty cycle almost 50%.
best regards,
This means that you are approximately 3 us in your interrupt service routine? Hence you cannot get every interrupt because you are still in the isr when the next interrupt request occurs.
Hi !,
does it mean I can reach a sampling rate of 1/3µsec ?. I can not figure out what the DSP is doing during the other 3µsec ?.
Anyway, I want to achieved a 800Khz sampling rate, is it possible with the F28335 and how ?. I have lowered the set-up and hold to its minimum, my ADC freq is 25Mhz so can I reach the 12.5MSPS rate ?.
Well, the ADC is able to achieve 12.5 MSPS. But how do you want to process this data? At 12.5 MSPS you have got 12 clock cycles per sample. Hence you cannot work with interrupts, you have to start a free running adc at maximum sampling rate and a synchronous data acquisition loop with exactly 12 clock cycles storing the conversion results into a buffer. But in this time, your processor cannot handle anything else. And after storing all the data you can process it.
At 1 MSPS you will have 150 clock cycles per sample. This might be enough for calling the isr and store the data (and perhaps some very simple processing). But: How many cycles does your processing function need? Do you have any other interrupts in your system?
Hi !!!,
In my application I can acquire all the 8192 samples and then handle them. So The solution would be:
1/ start a free running ADC @ 1MSPS
2/ acquire and store data in SRAM 8192 times
3/ stop ADC and process data
Am I correct ?. How do you garantee that the storing of conversion match exactly the sampling time ?
Best regards,
greg Wauters.
If you just need 1 MHz sampling rate, you can try the interrupt concept. But keep your isr short. And if you want to use a synchronous loop it's the best to write a short assembler function which disables interrupts, starts the adc and does the data acquisition loop 8192 times. Of course, your loop will be much too fast. Just insert some NOPs (rpt #n || nop ... n+1 NOPs).
Best regards and good luck,Edwin Krasser
Hi edwin,
just to thank you for the time you spend on my issue, It works grand now. One big timing improvement was to run my code from RAM.
Hello,
I am having some problems with an application that is similar to the one described in this thread.
I want to:
1) Sample 1000 ADC values on A0 with 12.5MSPS and store the values in an array
2) Analyze the values
3) Send result by SCI to PC
4) Repeat
So the main difference to the problem described in this thread is that I need 12.5MSPS. Based on the example Example_2833xAdcSeq_ovdTest I have written a program that does step 1-4. However my sampling frequency is just about 1MSPS, how do i setup my ADC to sample at 12.5MSPS?
Here is an extract of my code:
// ADC start parameters#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#define ADC_CKPS 0x1 // ADC module clock = HSPCLK/2*ADC_CKPS = 25.0MHz/(1*2) = 12.5MHz#define ADC_SHCLK 0xf // S/H width in ADC module periods = 16 ADC clocks#define AVG 1000 // Average sample limit#define ZOFFSET 0x00 // Average Zero offset#define BUF_SIZE 2048 // Sample buffer size
//declare global vars and functions
main(){ Uint16 i;
// Step 1. Initialize System Control:// PLL, WatchDog, enable Peripheral Clocks// This example function is found in the DSP2833x_SysCtrl.c file. InitSysCtrl();
// Specific clock setting for this example: EALLOW; SysCtrlRegs.HISPCP.all = ADC_MODCLK; // HSPCLK = SYSCLKOUT/ADC_MODCLK EDIS;
// Step 2. Initialize GPIO:// For this example, only init the pins for the SCI-A port.// This function is found in the DSP2833x_Sci.c file. InitSciaGpio();
// 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; // Output on GPIO34 EALLOW; GpioCtrlRegs.GPBMUX1.bit.GPIO34 = 0; // GPIO GpioCtrlRegs.GPBDIR.bit.GPIO34 = 1; // output EDIS;
// For this example, init the ADC InitAdc();
// Specific ADC setup for this example: AdcRegs.ADCTRL1.bit.ACQ_PS = ADC_SHCLK; AdcRegs.ADCTRL3.bit.ADCCLKPS = ADC_CKPS; AdcRegs.ADCTRL1.bit.SEQ_CASC = 1; // 1 Cascaded mode AdcRegs.ADCCHSELSEQ1.bit.CONV00 = 0x0; AdcRegs.ADCTRL1.bit.CONT_RUN = 1; // Setup continuous run
// Step 5. User specific code, enable interrupts:
scia_fifo_init(); // Initialize the SCI FIFO scia_echoback_init(); // Initalize SCI for echoback
// Clear SampleTable for (i=0; i<BUF_SIZE; i++) { SampleTable[i] = 0; }
// Start SEQ1 AdcRegs.ADCTRL2.all = 0x2000;
// Take ADC data and log the in SampleTable array for(;;) { GpioDataRegs.GPBSET.bit.GPIO34 = 1; // GPIO34 is high //sample and put values in SampleTable for (i=0; i<AVG; i++) {
while (AdcRegs.ADCST.bit.INT_SEQ1== 0) {} // Wait for interrupt AdcRegs.ADCST.bit.INT_SEQ1_CLR = 1; SampleTable[i] =((AdcRegs.ADCRESULT0>>4) ); } // print contents of SampleTable on SCI for(i = 0; i < AVG; i++) { if(i%10 == 0) scia_msg("\r\n"); else scia_msg(" ; "); printNum(SampleTable[i]); } scia_msg("\r\n...done!\r\n"); GpioDataRegs.GPBCLEAR.all = 0x4; // GPIO34 is low //wait until next cycle pause(100); }}
//define functions
You have got a sample time of 16 clock cycles. Not okay, you need to sample as fast as possible. Now you just can achieve 25 MHz / 16 samples per second, even if the adc was infinitely fast.
Best regards and good luck,
Edwin Krasser
Hi Edwin,
Thanks for your fast reply!
I've changed
#define ADC_SHCLK 0xf // S/H width in ADC module periods = 16 ADC clocks
to
#define ADC_SHCLK 0x0
and it works much better now! However, I still only get around 5MSPS :( Could it be that I loose half my sampling rate when I write the ADC value to the SamplingTable array in:
//sample and put values in SampleTable for (i=0; i<AVG; i++) { while (AdcRegs.ADCST.bit.INT_SEQ1== 0) {} // Wait for interrupt AdcRegs.ADCST.bit.INT_SEQ1_CLR = 1; SampleTable[i] =((AdcRegs.ADCRESULT0>>4) ); }
Or is it some register that I have set to the wrong value?
Thanks!
I think your loop is not fast enough. Just think about the cpu clock frequency. At 12.5 MHz sampling rate you just have 12 ticks for storing the adc results. For high speed adc sampling I suggest to write a free running loop that stores the adc results into an array. Write it in assembler and be sure every loop cycle takes exactly 12 ticks (insert nops ifyou need). Something like that: AVG -> ar0 SampleTable -> xarnloop: adcresult -> acc acc -> *xarn++ nop ; some nops to get exactly 12 ticks per loop banz loop,ar0--
Best regards and good luckEdwin Krasser
Thanks a lot Edwin, I havent worked with assembler before but I guess this is a good opportunity to learn. I'll try to write the sampling loop in assembler as you suggest.
Best wishes!