I’ve noticed on the Concerto ADC that the sample rate they claim (up to 2.88MSPS) is only the conversion rate and not the whole true conversion time (i.e. sample time + conversion time). Do they claim this due to having 2 sample-and-hold circuits?
-Jason
The Concerto ADC has two sample and hold circuits with some degree of pipelining, so the sample rate does not directly correspond to the sample latency. There are also 2 ADCs on Concerto, each with sample rate 2.88MSPS.
Hello,
does it mean that continues sampling with concerto ADC will not allow to reach 2.8 MSPS continues sampling?
Is it possible to get a clear answer on this matter, or example for this ADC configuration on single channel continues sampling?
Thank you very much,
Ilya
You will be able to get 2.8 MSPS on a single channel, sampling continuously (and since there are actually 2 ADC modules, you can get 2.8MSPS on two different channels at the same time). My point is just that you can not calculate the sample rate using the formula:
Sample Rate = 1 / total conversion time
because the ADC architecture has some degree of pipelining. Even though a sample is still converting, the ADC is able to begin the sampling phase for the next sample.
This is not due to having 2 S+H. The 2 S+H allows you to sample 2 signals at the exact same time, then convert them sequentially. The total sample rate in this case will also be near 2.8MSPS, but the sample rate for a particular signal will be half of that. Note that EACH of the 2 ADCs has 2 S+H, for 4 total S+H circuits.
My fastest configuration yet is attached, where it reaches little bit less than 1MSPS, but no more Idle time is remained to copy aside and handle the results?
What am I doing wrong ?
Thanks,
#include "DSP28x_Project.h" // Device Headerfile and Examples Include File
#define DUTY_CYCLE_A 500#define DUTY_CYCLE_B 500#define PERIOD 1000#define BUFFER_LENGTH (1000)
// Prototype statements for functions found within this file.interrupt void adc2_isr(void);void Adc_Config(void);
// Global variables used in this example:Uint32 LoopCount;Uint16 ConversionCount;//Uint16 Voltage1[BUFFER_LENGTH];Uint16 Voltage2[BUFFER_LENGTH];
main(){ // unsigned short analoginit;
// Step 1. Initialize System Control for Control and Analog Subsytems// Enable Peripheral Clocks// This example function is found in the F28M35x_SysCtrl.c file. InitSysCtrl();
// Step 2. Initialize GPIO:// This example function is found in the F28M35x_Gpio.c file and// illustrates how to set the GPIO to it's default state. InitGpio(); // Skipped for this example EALLOW; GpioG1CtrlRegs.GPCDIR.bit.GPIO70 = 1; //set PC6_GPIO70 as output //LED GpioG1CtrlRegs.GPADIR.bit.GPIO24 = 1; // Set as output EDIS;/* EALLOW; GpioG1CtrlRegs.GPADIR.bit.GPIO0 = 1; //Set as output GpioG1CtrlRegs.GPADIR.bit.GPIO8 = 1; //Set as output GpioG1CtrlRegs.GPAMUX1.bit.GPIO0 = 1; //Set mux to EPWM1A GpioG1CtrlRegs.GPAMUX1.bit.GPIO8 = 3; //Set mux to ADCSOCAn EDIS;*/// 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 F28M35x_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 F28M35x_DefaultIsr.c.// This function is found in F28M35x_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.ADCINT1 = &adc2_isr; EDIS; // This is needed to disable write to EALLOW protected registers
// Step 4. Initialize all the Device Peripherals:// This function is found in F28M35x_InitPeripherals.c// InitPeripherals(); // Not required for this example InitAdc2(); // For this example, init the ADC
// Step 5. User specific code, enable interrupts:
// Enable ADCINT1 in PIE PieCtrlRegs.PIEIER1.bit.INTx1 = 1; // Enable INT 1.1 in the PIE IER |= M_INT1; // Enable CPU Interrupt 1 EINT; // Enable Global interrupt INTM ERTM; // Enable Global realtime interrupt DBGM
LoopCount = 0; ConversionCount = 0;
// Configure ADC EALLOW; Adc2Regs.ADCCTL2.bit.ADCNONOVERLAP = 0; // Enable non-overlap mode i.e. // conversion and future // sampling // events dont overlap //Adc1Regs.ADCCTL1.bit.INTPULSEPOS = 1; // ADCINT1 trips after // AdcResults latch Adc2Regs.INTSEL1N2.bit.INT1E = 1; // Enabled ADC2NT1 Adc2Regs.INTSEL1N2.bit.INT1CONT = 1; // Disable ADC2NT1 Continuous // mode Adc2Regs.INTSEL1N2.bit.INT1SEL = 0; // setup EOC0 to trigger ADCINT1 // to fire Adc2Regs.ADCSOC0CTL.bit.CHSEL = 0; // set SOC0 channel select to // ADC1A0 // Adc1Regs.ADCSOC1CTL.bit.CHSEL = 2; // set SOC1 channel select to // ADC1A2 AnalogSysctrlRegs.TRIG1SEL.all = 0; // Assigning // ADC TRIGGER 1 of the ADC module Adc2Regs.ADCSOC0CTL.bit.TRIGSEL = 0; // Set SOC0 start trigger to // ADC Trigger 1(EPWM1 SOCA) of the // adc Adc2Regs.ADCSOC0CTL.bit.ACQPS = 6; // set SOC0 S/H Window to 7 ADC // Clock Cycles, (6 ACQPS plus // 1) Adc2Regs.ADCSOC1CTL.bit.ACQPS = 6; // set SOC1 S/H Window to 7 ADC // Clock Cycles, (6 ACQPS plus // 1) EDIS;
// count
// Wait for ADC interruptAdc2Regs.ADCSOCFRC1.bit.SOC0 = 1; for(;;) { LoopCount++; if (0 == (LoopCount % 1000000)) { //GpioG1DataRegs.GPATOGGLE.bit.GPIO70 = 1; if(GpioG1DataRegs.GPCDAT.bit.GPIO70 == 0) { GpioG1DataRegs.GPCSET.bit.GPIO70 = 1; } else { GpioG1DataRegs.GPCCLEAR.bit.GPIO70 = 1; } } }
}
interrupt void adc2_isr(void){ Adc2Regs.ADCSOCFRC1.bit.SOC0 = 1; // retriger next conversion Voltage2[ConversionCount] = Adc2Result.ADCRESULT0; // If 1000 conversions have been logged, start over if(ConversionCount == BUFFER_LENGTH - 1) { ConversionCount = 0; GpioG1DataRegs.GPATOGGLE.bit.GPIO24 = 1; } else ConversionCount++;
Adc2Regs.ADCINTFLGCLR.bit.ADCINT1 = 1; //Clear ADCINT1 flag reinitialize // for next SOC PieCtrlRegs.PIEACK.all = PIEACK_GROUP1; // Acknowledge interrupt to PIE
//Adc2Regs.ADCSOCFRC1.bit.SOC0 = 1; // retriger next conversion
return;}
How did you set up the system clock in the M3 code and the ACIB clock? Can you show me that code?
Ricky
i am using the configuration which based on adc_soc example from
C:\TI\controlSUITE\device_support\f28m35x\vBeta1\F28M35x_examples_Control\adc_soc\c28
// Initialize the Analog Sub-System and set the clock divider to divide by 4 (**InitAnalogSystemClock)(ACLKDIV4);
What example did you use for the M3 core? I need to know the clock settings in the M3 code. If you used the setup_m3 example then is this the code you used?
// Sets up PLL, M3 running at 75MHz and C28 running at 150MHz SysCtlClockConfigSet(SYSCTL_USE_PLL | (SYSCTL_SPLLIMULT_M & 0xF) | SYSCTL_SYSDIV_1 | SYSCTL_M3SSDIV_2 | SYSCTL_XCLKDIV_4);
that's right, setup_m3 as it is
I found an error in your ADC2 setup code. If you want ADC2 trigger 1 to be tied to EPWM1 SOCA the following lines need to be changed.The comments are also reversed.AnalogSysctrlRegs.TRIG1SEL.all = 5; // Set SOC0 start trigger to ADC Trigger 1(EPWM1 SOCA) of the adcAdc2Regs.ADCSOC0CTL.bit.TRIGSEL = 5; // Assigning ADC TRIGGER 1 of the ADC module to SOC0Settings these bit fields to 0 is reserved.Also just a note. You have the ADCNONOVERLAP bit set to 0, but the comment says that this statement enables non-overlap mode. Setting this bitto 0 actually puts the ADC in overlap mode. This is what you want to get the fastest performance, so maybe you can change the comment for clarity.
Regards,
Hi,
1. I set those bits to 0, because trigering is performed from the code by
Adc2Regs.INTSEL1N2.bit.INT1CONT = 1 // setting continues mode
and
Adc2Regs.ADCSOCFRC1.bit.SOC0 = 1; // retriger next conversion
inside interrupt handler (this is the only way it's working although continues mode expected to spare the last writing)
2. I am not using the EPWM triger because I need to sample it as fast as possible, is it possible to set the EPWM to triger each SOC 0.5 usec for example?
3. Do I need to link the (EOC0 to SOC1) (EOC1 to SOC2) (EOC2 to SOC3) and so on untill 8 and all CHSEL to one leg?
Do you may be have a simple example on how to sequentially sample even with 1 Msps?
Thank
BR,
Here is code that should run at the max ADC sampling speed.
Adc1Regs.ADCCTL1.bit.INTPULSEPOS = 1; //adcint pulse position at end of sample
Adc1Regs.INTSEL1N2.bit.INT1E = 1; //enable ADCINT1Adc1Regs.INTSEL1N2.bit.INT2E = 1; //enable ADCINT2Adc1Regs.INTSEL1N2.bit.INT1CONT = 0; //disable continuous mode for ADCINT1Adc1Regs.INTSEL1N2.bit.INT2CONT = 0; //disable continuous mode for ADCINT2Adc1Regs.INTSEL1N2.bit.INT1SEL = 6; //EOC6 will trigger ADCINT1Adc1Regs.INTSEL1N2.bit.INT2SEL = 14; //EOC14 will trigger ADCINT2Adc1Regs.ADCINTSOCSEL1.bit.SOC0 = 2; //ADCINT2 starts SOC0Adc1Regs.ADCINTSOCSEL1.bit.SOC1 = 2; //ADCINT2 starts SOC1Adc1Regs.ADCINTSOCSEL1.bit.SOC2 = 2; //ADCINT2 starts SOC2Adc1Regs.ADCINTSOCSEL1.bit.SOC3 = 2; //ADCINT2 starts SOC3Adc1Regs.ADCINTSOCSEL1.bit.SOC4 = 2; //ADCINT2 starts SOC4Adc1Regs.ADCINTSOCSEL1.bit.SOC5 = 2; //ADCINT2 starts SOC5Adc1Regs.ADCINTSOCSEL1.bit.SOC6 = 2; //ADCINT2 starts SOC6Adc1Regs.ADCINTSOCSEL1.bit.SOC7 = 2; //ADCINT2 starts SOC7Adc1Regs.ADCINTSOCSEL2.bit.SOC8 = 1; //ADCINT1 starts SOC8Adc1Regs.ADCINTSOCSEL2.bit.SOC9 = 1; //ADCINT1 starts SOC9Adc1Regs.ADCINTSOCSEL2.bit.SOC10 = 1; //ADCINT1 starts SOC10Adc1Regs.ADCINTSOCSEL2.bit.SOC11 = 1; //ADCINT1 starts SOC11Adc1Regs.ADCINTSOCSEL2.bit.SOC12 = 1; //ADCINT1 starts SOC12Adc1Regs.ADCINTSOCSEL2.bit.SOC13 = 1; //ADCINT1 starts SOC13Adc1Regs.ADCINTSOCSEL2.bit.SOC14 = 1; //ADCINT1 starts SOC14 Adc1Regs.ADCINTSOCSEL2.bit.SOC15 = 1; //ADCINT1 starts SOC15
Adc1Regs.INTSEL1N2.bit.INT1E = 1;Adc1Regs.INTSEL1N2.bit.INT2E = 1;Adc1Regs.ADCSOCFRC1.all = 0x00FF; // force SOC0-15
while(1){while (Adc1Regs.ADCINTFLG.bit.ADCINT1 == 0){}Adc1Regs.ADCINTFLGCLR.bit.ADCINT1 = 1; //clear ADCINT1// Read ADC Results 0 -7 herewhile (Adc1Regs.ADCINTFLG.bit.ADCINT2 == 0){}Adc1Regs.ADCINTFLGCLR.bit.ADCINT2 = 1; //clear ADCINT2// Read ADC Results 8 -15 here
} // loop until done sampling
//disable adcint1 and adcint2 to STOP the ping-pong samplingAdc1Regs.INTSEL1N2.bit.INT1E = 0;Adc1Regs.INTSEL1N2.bit.INT2E = 0;
Ricky,
I plan to use all the available analog inputs provided with the Concerto eval module. This is channels ADC1 - A0,A2, A3, A4, A6, A7, B4 and ADC2 - A0, A2, A3, A4, A6, A7, B0, B4. I could not find the correlation to actual input pin from the SOC number or channel number in the headeer files. Could you explain the relationship or point me to the information?
Pat
Pat,
The SOC number correlates to the ADC result register, so SOC0 puts its result in ADC Result 0, and SOC1 puts its result in ADC Result 1, and so on. It does not matter which ADC channel you use, SOC0 result will always go in ADC Result 0. As far as relating an ADC pin to an ADC channel, see below.
ADC1 - A0 is ADC1INA0 pin - channel field in SOC register should be 0
ADC1 - A2 is ADC1INA2 pin - channel field in SOC register should be 2
ADC1 - B5 is ADC1INB4 pin - channel field in SOC register should be 12 since B0 needs an 8 in the channel field in the SOC register