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.
Hi,
I modified the original example adc_ex5_soc_continuous that has 2 continuous conversion into 1 conversion.
Here is the code:
// // Included Files // #include "driverlib.h" #include "device.h" // // Function Prototypes // void configureADC(uint32_t adcBase); void setupADCContinuous(uint32_t adcBase, uint32_t channel); // // Defines // #define RESULTS_BUFFER_SIZE 1024 //buffer for storing conversion results //(size must be multiple of 16) #define EX_ADC_RESOLUTION 12 // 12 for 12-bit conversion resolution, which supports (ADC_MODE_SINGLE_ENDED) // Sample on single pin (VREFLO is the low reference) // Or 16 for 16-bit conversion resolution, which supports (ADC_MODE_DIFFERENTIAL) // Sample on pair of pins (difference between pins is converted, subject to // common mode voltage requirements; see the device data manual) // // Globals // uint16_t adcAResults[RESULTS_BUFFER_SIZE]; uint16_t resultsIndex; void main(void) { // // Initialize device clock and peripherals // Device_init(); // // Disable pin locks and enable internal pullups. // Device_initGPIO(); // // Initialize PIE and clear PIE registers. Disables CPU interrupts. // Interrupt_initModule(); // // Initialize the PIE vector table with pointers to the shell Interrupt // Service Routines (ISR). // Interrupt_initVectorTable(); // // Configure the ADC and power it up // configureADC(ADCA_BASE); // // Setup the ADC for continuous conversions on channel 0 // setupADCContinuous(ADCA_BASE, 0U); // // Initialize results buffer // for(resultsIndex = 0; resultsIndex < RESULTS_BUFFER_SIZE; resultsIndex++) { adcAResults[resultsIndex] = 0; } resultsIndex = 0; // // Enable global Interrupts and higher priority real-time debug events: // EINT; // Enable Global interrupt INTM ERTM; // Enable Global realtime interrupt DBGM // // Take conversions indefinitely in loop // do { // // Enable ADC interrupts // ADC_enableInterrupt(ADCA_BASE, ADC_INT_NUMBER1); // ADC_enableInterrupt(ADCA_BASE, ADC_INT_NUMBER2); // ADC_enableInterrupt(ADCA_BASE, ADC_INT_NUMBER3); // ADC_enableInterrupt(ADCA_BASE, ADC_INT_NUMBER4); // // Clear all interrupts flags(INT1-4) // HWREGH(ADCA_BASE + ADC_O_INTFLGCLR) = 0x000F; // // Initialize results index // resultsIndex = 0; // // Software force start SOC0 to SOC7 // // HWREGH(ADCA_BASE + ADC_O_SOCFRC1) = 0x00FF; ADC_forceSOC(ADCA_BASE, ADC_SOC_NUMBER0 ); ADC_forceSOC(ADCA_BASE, ADC_SOC_NUMBER1 ); ADC_forceSOC(ADCA_BASE, ADC_SOC_NUMBER2 ); ADC_forceSOC(ADCA_BASE, ADC_SOC_NUMBER3 ); ADC_forceSOC(ADCA_BASE, ADC_SOC_NUMBER4 ); ADC_forceSOC(ADCA_BASE, ADC_SOC_NUMBER5 ); ADC_forceSOC(ADCA_BASE, ADC_SOC_NUMBER6 ); ADC_forceSOC(ADCA_BASE, ADC_SOC_NUMBER7 ); ADC_forceSOC(ADCA_BASE, ADC_SOC_NUMBER8 ); ADC_forceSOC(ADCA_BASE, ADC_SOC_NUMBER9 ); ADC_forceSOC(ADCA_BASE, ADC_SOC_NUMBER10 ); ADC_forceSOC(ADCA_BASE, ADC_SOC_NUMBER11); ADC_forceSOC(ADCA_BASE, ADC_SOC_NUMBER12); ADC_forceSOC(ADCA_BASE, ADC_SOC_NUMBER13); ADC_forceSOC(ADCA_BASE, ADC_SOC_NUMBER14); ADC_forceSOC(ADCA_BASE, ADC_SOC_NUMBER15); // // Keep taking samples until the results buffer is full // while(resultsIndex < RESULTS_BUFFER_SIZE) { // // Wait for first set of 8 conversions to complete // while(false == ADC_getInterruptStatus(ADCA_BASE, ADC_INT_NUMBER1)); // // Clear the interrupt flag // ADC_clearInterruptStatus(ADCA_BASE, ADC_INT_NUMBER1); // // Save results for first 8 conversions // // Note that during this time, the second 8 conversions have // already been triggered by EOC6->ADCIN1 and will be actively // converting while first 8 results are being saved // adcAResults[resultsIndex++] = ADC_readResult(ADCARESULT_BASE, ADC_SOC_NUMBER0); adcAResults[resultsIndex++] = ADC_readResult(ADCARESULT_BASE, ADC_SOC_NUMBER1); adcAResults[resultsIndex++] = ADC_readResult(ADCARESULT_BASE, ADC_SOC_NUMBER2); adcAResults[resultsIndex++] = ADC_readResult(ADCARESULT_BASE, ADC_SOC_NUMBER3); adcAResults[resultsIndex++] = ADC_readResult(ADCARESULT_BASE, ADC_SOC_NUMBER4); adcAResults[resultsIndex++] = ADC_readResult(ADCARESULT_BASE, ADC_SOC_NUMBER5); adcAResults[resultsIndex++] = ADC_readResult(ADCARESULT_BASE, ADC_SOC_NUMBER6); adcAResults[resultsIndex++] = ADC_readResult(ADCARESULT_BASE, ADC_SOC_NUMBER7); // // Wait for the second set of 8 conversions to complete // // while(false == ADC_getInterruptStatus(ADCA_BASE, ADC_INT_NUMBER4)); // // Clear the interrupt flag // // ADC_clearInterruptStatus(ADCA_BASE, ADC_INT_NUMBER4); // // Save results for second 8 conversions // // Note that during this time, the first 8 conversions have // already been triggered by EOC14->ADCIN2 and will be actively // converting while second 8 results are being saved // adcAResults[resultsIndex++] = ADC_readResult(ADCARESULT_BASE, ADC_SOC_NUMBER8); adcAResults[resultsIndex++] = ADC_readResult(ADCARESULT_BASE, ADC_SOC_NUMBER9); adcAResults[resultsIndex++] = ADC_readResult(ADCARESULT_BASE, ADC_SOC_NUMBER10); adcAResults[resultsIndex++] = ADC_readResult(ADCARESULT_BASE, ADC_SOC_NUMBER11); adcAResults[resultsIndex++] = ADC_readResult(ADCARESULT_BASE, ADC_SOC_NUMBER12); adcAResults[resultsIndex++] = ADC_readResult(ADCARESULT_BASE, ADC_SOC_NUMBER13); adcAResults[resultsIndex++] = ADC_readResult(ADCARESULT_BASE, ADC_SOC_NUMBER14); adcAResults[resultsIndex++] = ADC_readResult(ADCARESULT_BASE, ADC_SOC_NUMBER15); } // // Disable all ADCINT flags to stop sampling // ADC_disableInterrupt(ADCA_BASE, ADC_INT_NUMBER1); // ADC_disableInterrupt(ADCA_BASE, ADC_INT_NUMBER2); // ADC_disableInterrupt(ADCA_BASE, ADC_INT_NUMBER3); // ADC_disableInterrupt(ADCA_BASE, ADC_INT_NUMBER4); // // At this point, adcAResults[] contains a sequence of conversions // from the selected channel // // // Software breakpoint, hit run again to get updated conversions // asm(" ESTOP0"); } while(1); // Loop forever } // // configureADC - Write ADC configurations and power up the ADC for both // ADC A and ADC B // void configureADC(uint32_t adcBase) { // // Set ADCDLK divider to /4 // ADC_setPrescaler(adcBase, ADC_CLK_DIV_4_0); // // Set resolution and signal mode (see #defines above) and load // corresponding trims. // #if(EX_ADC_RESOLUTION == 12) ADC_setMode(adcBase, ADC_RESOLUTION_12BIT, ADC_MODE_SINGLE_ENDED); #elif(EX_ADC_RESOLUTION == 16) ADC_setMode(adcBase, ADC_RESOLUTION_16BIT, ADC_MODE_DIFFERENTIAL); #endif // // Set pulse positions to late // ADC_setInterruptPulseMode(adcBase, ADC_PULSE_END_OF_CONV); // // Power up the ADCs and then delay for 1 ms // ADC_enableConverter(adcBase); // // Delay for 1ms to allow ADC time to power up // DEVICE_DELAY_US(1000); } // // setupADCContinuous - setup the ADC to continuously convert on one channel // void setupADCContinuous(uint32_t adcBase, uint32_t channel) { uint16_t acqps; // // Determine acquisition window (in SYSCLKS) based on resolution // if(EX_ADC_RESOLUTION == 12) { acqps = 30; // 150ns } else //resolution is 16-bit { acqps = 64; // 320ns } // // - NOTE: A longer sampling window will be required if the ADC driving // source is less than ideal (an ideal source would be a high bandwidth // op-amp with a small series resistance). See TI application report // SPRACT6 for guidance on ADC driver design. // - NOTE: A slightly longer S+H window is used with 12-bit resolution to // ensure the data collection loop can keep up with the ADC // // // Configure SOCs channel no. & acquisition window. // ADC_setupSOC(adcBase, ADC_SOC_NUMBER0, ADC_TRIGGER_SW_ONLY, (ADC_Channel)channel, acqps); ADC_setupSOC(adcBase, ADC_SOC_NUMBER1, ADC_TRIGGER_SW_ONLY, (ADC_Channel)channel, acqps); ADC_setupSOC(adcBase, ADC_SOC_NUMBER2, ADC_TRIGGER_SW_ONLY, (ADC_Channel)channel, acqps); ADC_setupSOC(adcBase, ADC_SOC_NUMBER3, ADC_TRIGGER_SW_ONLY, (ADC_Channel)channel, acqps); ADC_setupSOC(adcBase, ADC_SOC_NUMBER4, ADC_TRIGGER_SW_ONLY, (ADC_Channel)channel, acqps); ADC_setupSOC(adcBase, ADC_SOC_NUMBER5, ADC_TRIGGER_SW_ONLY, (ADC_Channel)channel, acqps); ADC_setupSOC(adcBase, ADC_SOC_NUMBER6, ADC_TRIGGER_SW_ONLY, (ADC_Channel)channel, acqps); ADC_setupSOC(adcBase, ADC_SOC_NUMBER7, ADC_TRIGGER_SW_ONLY, (ADC_Channel)channel, acqps); ADC_setupSOC(adcBase, ADC_SOC_NUMBER8, ADC_TRIGGER_SW_ONLY, (ADC_Channel)channel, acqps); ADC_setupSOC(adcBase, ADC_SOC_NUMBER9, ADC_TRIGGER_SW_ONLY, (ADC_Channel)channel, acqps); ADC_setupSOC(adcBase, ADC_SOC_NUMBER10, ADC_TRIGGER_SW_ONLY, (ADC_Channel)channel, acqps); ADC_setupSOC(adcBase, ADC_SOC_NUMBER11, ADC_TRIGGER_SW_ONLY, (ADC_Channel)channel, acqps); ADC_setupSOC(adcBase, ADC_SOC_NUMBER12, ADC_TRIGGER_SW_ONLY, (ADC_Channel)channel, acqps); ADC_setupSOC(adcBase, ADC_SOC_NUMBER13, ADC_TRIGGER_SW_ONLY, (ADC_Channel)channel, acqps); ADC_setupSOC(adcBase, ADC_SOC_NUMBER14, ADC_TRIGGER_SW_ONLY, (ADC_Channel)channel, acqps); ADC_setupSOC(adcBase, ADC_SOC_NUMBER15, ADC_TRIGGER_SW_ONLY, (ADC_Channel)channel, acqps); // // Setup interrupt trigger for SOCs. ADCINT2 will trigger first 8 SOCs. // ADCINT1 will trigger next 8 SOCs // // // ADCINT2 trigger for SOC0-SOC7 // ADC_setInterruptSOCTrigger(adcBase, ADC_SOC_NUMBER0, ADC_INT_SOC_TRIGGER_ADCINT1); ADC_setInterruptSOCTrigger(adcBase, ADC_SOC_NUMBER1, ADC_INT_SOC_TRIGGER_ADCINT1); ADC_setInterruptSOCTrigger(adcBase, ADC_SOC_NUMBER2, ADC_INT_SOC_TRIGGER_ADCINT1); ADC_setInterruptSOCTrigger(adcBase, ADC_SOC_NUMBER3, ADC_INT_SOC_TRIGGER_ADCINT1); ADC_setInterruptSOCTrigger(adcBase, ADC_SOC_NUMBER4, ADC_INT_SOC_TRIGGER_ADCINT1); ADC_setInterruptSOCTrigger(adcBase, ADC_SOC_NUMBER5, ADC_INT_SOC_TRIGGER_ADCINT1); ADC_setInterruptSOCTrigger(adcBase, ADC_SOC_NUMBER6, ADC_INT_SOC_TRIGGER_ADCINT1); ADC_setInterruptSOCTrigger(adcBase, ADC_SOC_NUMBER7, ADC_INT_SOC_TRIGGER_ADCINT1); // // ADCINT1 trigger for SOC8-SOC15 // ADC_setInterruptSOCTrigger(adcBase, ADC_SOC_NUMBER8, ADC_INT_SOC_TRIGGER_ADCINT1); ADC_setInterruptSOCTrigger(adcBase, ADC_SOC_NUMBER9, ADC_INT_SOC_TRIGGER_ADCINT1); ADC_setInterruptSOCTrigger(adcBase, ADC_SOC_NUMBER10, ADC_INT_SOC_TRIGGER_ADCINT1); ADC_setInterruptSOCTrigger(adcBase, ADC_SOC_NUMBER11, ADC_INT_SOC_TRIGGER_ADCINT1); ADC_setInterruptSOCTrigger(adcBase, ADC_SOC_NUMBER12, ADC_INT_SOC_TRIGGER_ADCINT1); ADC_setInterruptSOCTrigger(adcBase, ADC_SOC_NUMBER13, ADC_INT_SOC_TRIGGER_ADCINT1); ADC_setInterruptSOCTrigger(adcBase, ADC_SOC_NUMBER14, ADC_INT_SOC_TRIGGER_ADCINT1); ADC_setInterruptSOCTrigger(adcBase, ADC_SOC_NUMBER15, ADC_INT_SOC_TRIGGER_ADCINT1); // // Disable Interrupt flags // ADC_disableInterrupt(adcBase, ADC_INT_NUMBER1); // ADC_disableInterrupt(adcBase, ADC_INT_NUMBER2); // ADC_disableInterrupt(adcBase, ADC_INT_NUMBER3); // ADC_disableInterrupt(adcBase, ADC_INT_NUMBER4); // // Enable continuous mode // ADC_enableContinuousMode(adcBase, ADC_INT_NUMBER1); // ADC_enableContinuousMode(adcBase, ADC_INT_NUMBER2); // ADC_enableContinuousMode(adcBase, ADC_INT_NUMBER3); // ADC_enableContinuousMode(adcBase, ADC_INT_NUMBER4); // // Configure interrupt triggers // ADC_setInterruptSource(adcBase, ADC_INT_NUMBER1, ADC_SOC_NUMBER15); // ADC_setInterruptSource(adcBase, ADC_INT_NUMBER1, ADC_SOC_NUMBER14); // ADC_setInterruptSource(adcBase, ADC_INT_NUMBER1, ADC_SOC_NUMBER13); // good results // ADC_setInterruptSource(adcBase, ADC_INT_NUMBER1, ADC_SOC_NUMBER5); } // // End of file //
When I input 5 kHz sinusoid and use different interrupt sources i see that there are glitches. I would expect ADC_setInterruptSource(adcBase, ADC_INT_NUMBER1, ADC_SOC_NUMBER15); should not have any glitches as it makes sure all conversions completed. Here is the screen shot of the graphs
thanks vadim
Hi,
The expert is out of the office because of Holiday. Please expect a reply by Tuesday.
Thanks.
Hello Vadim,
If you only use 1 interrupt for all 16 SOCs, there will not be enough time to convert the values before beginning the conversion of the next set of SOCs. The example you were looking at provides the proper way to trigger all 16 SOCs (with at least 2 interrupts), that way there is enough time to convert SOCs while reading the results of the other SOCs.
Also, as a future note, please use the Instert -> Code method of copying and pasting code. The way you have inserted your code here makes it unnecessarily difficult to read, and I will not be able to find what you're talking about as easily.
Best regards,
Omer Amir
Hi Omer,
Thanks for your support. I understand that ADC SOC has priorities according to round robin method. I understood this as the current conversion will not start till the previous conversion is not finished.
In this case the interrupt assigned to the last SOC15 should trigger the first SOC0 of the first channel? So if my EPWM time base is larger than sequential 16 SOC*75 ns , I should not see any glitches?
I believe that I am doing the same thing as the example, with the difference of having 16 continuous channels versus 4 in example for A2 input.
//! This example sets up ePWM1 to periodically trigger a set of conversions on //! ADCA including multiple SOCs that all convert A2 to achieve oversampling on //! A2. //! //! ADCA Interrupt ISRs are used to read results of ADCA. //! //! \b External \b Connections \n //! - A0, A1, A2 should be connected to signals to be converted. //! //! \b Watch \b Variables \n //! - \b adcAResult0 - Digital representation of the voltage on pin A0 //! - \b adcAResult1 - Digital representation of the voltage on pin A1 //! - \b adcAResult2 - Digital representation of the voltage on pin A2 //!
thanks Vadim
PS I tried to input code as you suggested.
Hello Vadim,
In this case the interrupt assigned to the last SOC15 should trigger the first SOC0 of the first channel?
The interrupt assigned to an SOC will cause that SOC to trigger, so you can use 1 interrupt to trigger multiple SOCs. However, the way your code was structured made it so that interrupt 1 was triggering all 16 SOCs. By the time an ISR is reached or the interrupt is triggered again, the data may or may not be ready and the SOCs may not have time to convert the results before another interrupt is fired (you can monitor the interrupt overflow status for this).
So if my EPWM time base is larger than sequential 16 SOC*75 ns , I should not see any glitches?
If you're using the ePWM to trigger the SOCs and not just the interrupt or software trigger, then if you make the time base period long enough it should be okay. However, the code you have does not look like the ePWM is being used to trigger the SOCs, it looks like you're using ADC interrupt 1.
PS I tried to input code as you suggested
I've reformatted your original post so that it's easier to view.
Best regards,
Omer Amir
Thanks Omer,
So if I use ADC_TRIGGER_SW_ONLY in
ADC_setupSOC(adcBase, ADC_SOC_NUMBER0, ADC_TRIGGER_SW_ONLY, (ADC_Channel)channel, acqps);
I must define the interrupt that triggers SOC ADC_INT_SOC_TRIGGER_ADCINT1
ADC_setInterruptSOCTrigger(adcBase, ADC_SOC_NUMBER0, ADC_INT_SOC_TRIGGER_ADCINT1);
in original example 16 SOC were split into 2 groups each triggered by different interrupt.
thanks vadim
Hello Vadim,