ADC existencial doubt

Hello,

I need to use the ADC through an interrupt and changing the chanel after each conversion. I did follow the guide from this forum and by the Datasheet of 328p. After read fine both documents did me arise the next existencial doubt: When I execute the routine associated to the ADC vector handler, Is the interrupt flag cleared at the begining or at he end of the code contained on the ISR(){} routine?

I ask this because the page 255 of datasheet said :

If both ADATE and ADEN is written to one, an interrupt event can occur at any time. If the ADMUX Register is changed in this period, the user cannot tell if the next conversion is based on the old or the new settings. ADMUX can be safely updated in the following ways:

a. When ADATE or ADEN is cleared.

b. During conversion, minimum one ADC clock cycle after the trigger event.

c. After a conversion, before the Interrupt Flag used as trigger source is cleared.

If I suppose that the flag is cleared immediatly at the begining of the ISR(){} routine, the only way to change the conversion channel inside of the ISR routine, is writting 0 to ADATE, for stop the auto trigger, change the channel, activate the ADATE again and exit from the ISR

What do you think about this? I'm right? Exists another method? or
(in the best of cases) Is the flag cleared after execute the complete ISR{} Routine? (And I can change the channel multiplexer with security inside the ISR)

Regards

c. After a conversion, before the Interrupt Flag used as trigger source is cleared.

I would not interpret that as the ADIF flag (else the documentation writer probably would have written ADIF directly instead of using this formulation) but the interrupt flag of the trigger source, so p.e. the TOV0 flag if the ADTS bits are 100.

The ADATE bit starts the auto-trigger, meaning that you have no idea when the conversion will start as it is defined by timers or the comparator. Is that something you’ll have?

If you plan to use the auto-trigger with a timer, skip the reading after you changed the channel.

unsigned char skip();

ADC_int(){

if (skip == 1) {
  read_adc();
  skip = 0;
}
else{
adc_value = read_adc();
}

loop() {


channel++; 
skip = 1;

What that is saying is that whenever you change the channel, another conversion is already underway. And so the reading will be from the previous channel. So if you skip that one, the next reading will definitely be the right one.
The other way, would be to use the single conversion mode triggered inside the a timer interrupt. This way you are in control of when the AD conversion is started. Do you understand why it is like this?

If I suppose that the flag is cleared immediatly at the begining of the ISR(){} routine, the only way to change the conversion channel inside of the ISR routine, is writting 0 to ADATE, for stop the auto trigger, change the channel, activate the ADATE again and exit from the ISR

What is the ISR? There are at least two option, TIMER and ADC_vect. If you are starting conversion by timer, you better to trigger ISR(TIMER) to do a MUX change and data store. Even conversion would be already started before you get in the ISR, delay is a constant, data you taking is always
"stamped" 1 cycle of the MUX settings back.
With ADC_vect there would be less time for MUX to "settle" at new channel. That actually important on fast sampling rate. What is yours?

ozcy:
I need to use the ADC through an interrupt and changing the chanel after each conversion. I did follow the guide from this forum and by the Datasheet of 328p. After read fine both documents did me arise the next existencial doubt: When I execute the routine associated to the ADC vector handler, Is the interrupt flag cleared at the begining or at he end of the code contained on the ISR(){} routine?

A test shows that the ADIF flag is clear once the ISR starts executing. Thus the sentence:

ADIF is cleared by hardware when executing the corresponding interrupt handling vector.

... means "when it starts executing ...".

This makes sense because interrupts in general can be queued, eg. once you start processing an incoming serial byte interrupt, it can then notice another serial byte arriving, which will then be detected once the current ISR finishes.

After reading the datasheet a few times, I think this might be the easiest:

During conversion, minimum one ADC clock cycle after the trigger event.

If you have a prescaler of 128, then one ADC clock cycle is 8 uS.

So this should work:

ADCSRA |= _BV (ADSC);  // start this conversion
delayMicroseconds (8);

// change MUX channel now (ready for next conversion)

However I note that the analogRead function does not do it this way. My reading of the datasheet suggests that the MUX settings are continuously copied into the temporary register used during an ADC conversion. Then when the conversion starts, in the first ADC clock cycle, the MUX value is latched into the temporary register (so it is used from then on during the conversion).

Thus, if a conversion is not in progress, and you are not using auto-triggering, then it should be safe to change the MUX input before starting the conversion.