I am using an Atmel's XPlained mini board with Atmega328PB. I am trying to use ADC interrupt, however I can't get it to fire. Here's the code that I have a problem with:

#define F_CPU 16000000UL
#include <avr/io.h>
#include <avr/interrupt.h>

    PORTC ^= (1<<PINC2);

int main(void)
DDRC |= (1<<PINC2); //pin 2 as output
DDRC &= ~(1<<PINC3); //adc pin as input
ADMUX |= (1<<REFS0); //reference voltage VCC
ADMUX |= (1<<MUX0);
ADMUX |= (1<<MUX1);// channel 3
ADCSRA |= (1<<ADPS2);//
ADCSRA |= (1<<ADPS1);//
ADCSRA |= (1<<ADPS0);//prescaler to 128
ADCSRA |= (1<<ADATE);//auto trigger enable
ADCSRA |= (1<<ADIE); //adc interrupt enable
ADCSRA |= (1<ADEN); //adc enable
ADCSRA |= (1<< ADSC); //start conversion    

while (1) 

As far as I understand the code should enable a constant conversion in a free running mode with the frequency of 16MHz/128, and each time the conversion is completed the ADC_vect should fire toggling PIN2 of Port C. The problem is it doesn't. I am guessing I am not initializing the ADC correctly, however I can not pin point were the problem is.

EDIT: After pointing out that the adc was not being run in a free running mode I cleared the ADTS bits. However I still couldn't toggle the pin. I think something else is at fault here.


2 Answers 2


You've written

ADCSRA |= (1<ADEN); //adc enable

And I think it should be

ADCSRA |= (1<<ADEN); //adc enable

Which seems plausible since the error you've come across is that it never does anything.

  • \$\begingroup\$ That's absolutely right, too bad that such a mistake doesn't trigger any kind of warning. \$\endgroup\$ Commented Dec 20, 2018 at 7:16
  • \$\begingroup\$ @AnthropomorphousDodecahedron Well 1<ADEN is evaluated as if it was inside a if statement. I don't know what value ADEN actually is, but if it is, say equal to 2, then 1<ADEN becomes true which becomes 00000001 which is then OR:ed with ADCSRA. - So it shouldn't generate an error nor a warning, it is perfectly legal code. \$\endgroup\$ Commented Dec 20, 2018 at 8:12

See table 24-6 of the datasheet. You are setting bits ADTS1 and ADTS0 high (leaving ADTS2 as zero). It means that the trigger signal is "Timer/Counter0 Compare Match A". You are not doing anything to configure that timer (and the reset state of the timer is simply "stopped").

To use the free running mode you have to clear ADTS0, ADTS1, ADTS2 in ADCSRB (or just leave ADCSRB alone at its reset value).

  • \$\begingroup\$ Filo is right. "ADCSRB |= (1 << ADTS1) | (1 << ADTS0); //free running mode" here you do not set the free runing mode as the comment mention. For free runing mode: ADCSRB = ~( (1 << ADTS2) | (1 << ADTS1) | (1 << ADTS0) ); \$\endgroup\$
    – pantarhei
    Commented Dec 9, 2018 at 22:48
  • \$\begingroup\$ While the correction is right, and adc was not in free running mode it seems something else was also at fault, since the pin was still not being toggled, even after I cleared the ADTS bits. \$\endgroup\$ Commented Dec 13, 2018 at 21:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.