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 everyone!
Question about the ADC10 and it's ADC10BUSY flag in ADC10CTL1:
I use the ADC10 with the Data Transfer Controller to sample a single channel multiple times and use the single block transfer mode to store the data. Here are some code lines
void main( void ) { ... // Vref+/Vss, 64 clocks S&H, ref output on, multiple sample and conversion, 2,5V ref, ref on, ADC10 on, interrupt enable ADC10CTL0 = (SREF_1 | ADC10SHT_3 | REFOUT | MSC | REF2_5V | REFON | ADC10ON | ADC10IE); // Channel A0 selected, ADC10CS bit as trigger, clock divider 0, ADC10OSC, repeat single channel ADC10CTL1 = (INCH_0 | SHS_0 | ADC10DIV_0 | ADC10SSEL_0 | CONSEQ_2); // Analog input A0 ADC10AE0 = 0x01; ... __bis_SR_register( GIE ); // Enable global interrupts // Set number of samples ADC10DTC1 = 8; // Set start address ADC10SA = &adc_average_samples[0]; // Enable and start conversion ADC10CTL0 |= (ENC | ADC10SC); while( 1 ) { ... } } #pragma vector = ADC10_VECTOR __interrupt void ADC10_ISR ( void ) { ADC10CTL0 &= ~ENC; // Disable conversions //while( ADC10CTL1 & ADC10BUSY ); // Only for testing if( ADC10CTL1 & ADC10BUSY ) { err = 1; // <- Is entered directly after the first block transfer, so ADC10BUSY is still set when transfer is finished - WHY? } }
I recognize that sometimes the ADC conversion stop randomly - there isn't another interrupt generated. In the ISR I set a flag to process the data in the main. After processing, another block transfer is initiated (not shown here). But this sometimes does not happen...there is no further interrupt - according to the user's guide, you should first check for ADC10BUSY to be cleared before changing anything of the ADC's configuration. This might be the problem, because I see ADC10BUSY set when entering the ISR and I then change things (switch to another channel - also not shown here).
But why is ADC10BUSY still set here? The IFG is set after a complete block transfer, then the conversions are stopped...what is the ADC still doing? I don't see any loss of interrupts if I insert the while( ADC10CTL1 & ADC10BUSY ); inside the ISR for testing purposes. The bit gets cleared soon after entering the ISR.
Well, maybe I have the answer to my own question...I think I misunderstood the working principle - since I set CONSEQ_2 for repeated single channel, the ADC would perform samples all the time if I would not disable ENC. By setting the DTC count to eight in my case, the DTC simply jumps in and takes the next eight samples that come from the ADC. After that, the DTC waits for another trigger, but the ADC would continue running in the background. Therefore the ADC10BUSY bit is set because the ADC is performing the next (9th) sample. By resetting ENC it stops after the currently running conversion. But since initiating a new transfer while busy is prohibited, I have to wait for UCBUSY to get cleared first.
Am I correct with this consideration?
So I think I can close this thread as a monolog :) It works now without missing interrupts - I have changed my code and will share it with you:
... #define ADC_AVERAGE_COUNT 8 #define ADC_FLG_WAIT_FOR_IDLE 0x80 #define ADC_FLG_RESULTS_AVAILABLE 0x40 #define ADC_FLG_CHANNEL_1_ACTIVE 0x01 #define ADC_FLG_CHANNEL_2_ACTIVE 0x02 volatile uint8_t adc_status = ADC_FLG_CHANNEL_1_ACTIVE; // Start with channel (A0) ... volatile uint16_t adc_average_samples[2][ADC_AVERAGE_COUNT]; // Array for holding multiple samples of two channels ... void main( void ) { ... // Vref+/Vss, 64 clocks S&H, ref output on, multiple sample and conversion, 2,5V ref, ref on, ADC10 on, interrupt enable ADC10CTL0 = (SREF_1 | ADC10SHT_3 | REFOUT | MSC | REF2_5V | REFON | ADC10ON | ADC10IE); // Channel A0 selected, ADC10CS bit as trigger, clock divider 0, ADC10OSC, repeat single channel ADC10CTL1 = (INCH_0 | SHS_0 | ADC10DIV_0 | ADC10SSEL_0 | CONSEQ_2); // Analog input A0 and A3 enabled ADC10AE0 = (0x01 | 0x08); ... __bis_SR_register( GIE ); // Enable global interrupts ADC10DTC1 = ADC_AVERAGE_COUNT; // Set number of samples ADC10SA = &adc_average_samples[0][0]; // Set start address ADC10CTL0 |= (ENC | ADC10SC); // Enable and start conversion while( 1 ) { if( adc_status & ADC_FLG_WAIT_FOR_IDLE ) // Request to wait for ADC idle again { if( !(ADC10CTL1 & ADC10BUSY) ) // Check if ADC is not busy { adc_status &= ~ADC_FLG_WAIT_FOR_IDLE; // Clear flag if( adc_status == ADC_FLG_CHANNEL_1_ACTIVE ) // Channel 1 { adc_status = ADC_FLG_CHANNEL_2_ACTIVE; // Set new status ADC10CTL1 &= ~INCH_0; // Disable channel A0 ADC10CTL1 |= INCH_3; // Enable channel A3 ADC10SA = &adc_average_samples[1][0]; // Set start address ADC10CTL0 |= (ENC | ADC10SC); // Enable and start conversion } else if( adc_status == ADC_FLG_CHANNEL_2_ACTIVE ) // Channel 2 { adc_status = ADC_FLG_CHANNEL_1_ACTIVE; // Set new status ADC10CTL1 &= ~INCH_3; // Disable channel A3 ADC10CTL1 |= INCH_0; // Enable channel A0 ADC10SA = &adc_average_samples[0][0]; // Set start address adc_status |= ADC_FLG_RESULTS_AVAILABLE; // Set flag to signal new data to process } } } if( adc_status & ADC_FLG_RESULTS_AVAILABLE ) // Request for processing data { ... // Process data adc_status &= ~ADC_FLG_RESULTS_AVAILABLE; // Clear flag ADC10CTL0 |= (ENC | ADC10SC); // Enable and start conversion } ... // Do other things in main } } #pragma vector = ADC10_VECTOR __interrupt void ADC10_ISR ( void ) { ADC10CTL0 &= ~ENC; // Disable conversions adc_status |= ADC_FLG_WAIT_FOR_IDLE; // Set flag to signal waiting for ADC idle }
Dennis
Nice to see a thread with ‘loud thinking’ or ‘talking to myself’ <smile>.
Something to the Average;
Taking 8 (new) samples and average them is slow (need to wait for 8 samples) and the result is nearly the same as stripping off a few of the least significant bits. A much better way is ‘the moving 8’ method, but there are more methods depending on your needs.
When randomly taking samples the result is in most cases useless. When for example the first 8 where ready in 100uS and the next 8 in 10mS (due to other processes in your system), you can’t compare both and when you want to use them to control a motor, the motor will be nervous and will be never running smoothly. Always use a timer to initiate a sampling cycle or another time-based way to collect data.
**Attention** This is a public forum