I noticed strange behaviour, for which I cannot find any documented confirmation. In my program I measure two ADC channels:

  • ADC0
  • Internal 1.1 V bandgap reference (in order to know the value of applied supply voltage VCC)

I measure these two channels by polling. It seems when I measure a channel I always get the value of the previous measured channel at first. To get the actual correct value I have to wait some time (delay) and measure again. Why is this? This is my code for reading the ADC values.

Reading ADC0:

ADCSRA &= ~(1<<ADEN); /* ADC ausschalten */

/* Set VCC as reference for ADC */
ADMUX &= ~(1<<REFS1);
ADMUX &= ~(1<<REFS0);

/* Measure PA0 (ADCSRB[MUX5] = 0b0; ADMUX[MUX4-MUX0] = 0b00000)*/
ADCSRB &= ~(1<<MUX5);
ADMUX &= ~((1<<MUX4) | (1<<MUX3) | (1<<MUX2) | (1<<MUX1) | (1<<MUX0));

ADCSRA |= (1<<ADEN) | (1<<ADSC); /* Enable ADC and start conversion */
while((ADCSRA & (1<<ADIF)) == 0); /* Wait until conversion done */
ADCSRA |= (1<<ADIF); /* Reset ADC interrupt flag */

/* At this point I read a wrong value (from previous channel) */

/* My current workaround starts here */
_delay_us(50); /* Wait some time */

/* Measure again */
ADCSRA |= (1<<ADSC); /* Start conversion */
while((ADCSRA & (1<<ADIF)) == 0); /* Wait until conversion done */
ADCSRA |= (1<<ADIF); /* Reset ADC interrupt flag */

/* Now I got my correct value */

ADCSRA &= ~(1<<ADEN); /* Turn off adc */

When reading the 1.1 V bandgap the only thing I change from the code above is:

/* Measure 1V1 bandgap reference (ADCSRB[MUX5] = 0b0; ADMUX[MUX4-MUX0] = 0b11110)*/
ADCSRB &= ~(1<<MUX5);
ADMUX |= (1<<MUX4) | (1<<MUX3) | (1<<MUX2) | (1<<MUX1);
ADMUX &= ~(1<<MUX0);

I have to read the wrong value, then wait, then read again. When I omit one of these steps it does not work anymore.

My target microcontroller is the ATTiny861V and I use avr-gcc under Windows 10 for compiling.

  • 1
    \$\begingroup\$ How [exactly] are you driving these inputs? A schematic would be useful. It can be that if they're not being driven by a low impedance it takes a long time for the voltage to settle after reading the previous input. \$\endgroup\$ – DiBosco Nov 14 '17 at 9:20
  • \$\begingroup\$ ADC0 is fed by an IR sensor output and 1.1V is fed by the internal bandgap reference of the ATTiny861V. \$\endgroup\$ – arminb Nov 14 '17 at 9:27
  • \$\begingroup\$ Well that's not that's not really that exact. I'd try driving the output of the sensor into the micro via an non-inverting buffer op amp. With or without gain depending on your situation. Or switch the multiplexer and wait a time before reading the value. \$\endgroup\$ – DiBosco Nov 14 '17 at 9:38
  • \$\begingroup\$ IIRC this is the expected behavior in multiple applications. The ADC value register is buffered and depending on the ADC mode changing the MUX will only affect the next reading not the current one. It is mentioned in several datasheets and App notes. I might look it up and write a complete answer tomorrow. \$\endgroup\$ – FRob Nov 17 '17 at 0:14

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.