Accessing ADFR value to set ADC as free-running?

Hi,

I'm trying to set the ADC in free-running mode, and take data when a conversion is complete.

However, when I include:

ADCSRA |= (1 << ADFR);

in my sketch, the compiler gives an error. I've included both avr/io.h and avr/interrupt.h in my sketch, and the other AVR values I'm accessing work fine. What am I missing?

Two things...

  1. From a quick glance at the ATmega328 datasheet, enabling "free running" mode is a bit more complicated than setting a bit. You might want to spend some time reading.

  2. "ADFR" is a label on a control line; it is not a defined bit in the ADCSRA register. While you have the datasheet open, be sure to read through the "ADCSRA – ADC Control and Status Register A" section.

I've included both avr/io.h and avr/interrupt.h in my sketch

This is not necessary. But I don't think it will cause problems.

In future posts, you should also include which board / processor you're using.

Thanks for the reply. I've actually been reading since I posted and I see now that I have to set ADATE and ADCSRB.

There was some Arduino code online that purported to set ADFR in the way I quoted, which is where I got it from.

I'm using the 328p on a Duemilanove.

It looks like the ATmega128 has an "ADFR" bit.

I think free-running has been discussed here a few times. You may also want to search the forum.

I believe free-running requires an interrupt service routine. If that's the case, be sure to read about the volatile keyword, disabling interrupts, and atomic operations.

Thanks for the reply. Free-running has been discussed here a few times, as well as on the AVRFreaks forum, and I read the pertinent posts on both.

I'm still not certain why the ADFR didn't work, maybe only the 128 has that and not the 328p? I was under the impression that they were more or less identical except for their memory?

I don't think you need an interrupt service routine to run the ADC in free-running mode, though I was trying to implement free-running so I could call the conversion complete interrupt with clock regularity.

I was able to get it to work using ADATE to set auto-triggering and setting ADCSRB to free-running mode. However, a word of warning to anyone who might be reading this: make sure you read ADCL before ADCH! I read that fact multiple times and STILL made the mistake, it's an easy one to make.

Anyway, thanks for the input everyone, but it looks like I've finally got the thing working!

I've chopped up my code, removing the non-pertinent parts, to present what should give an average ADC value every second, but don't come knocking on my door if it breaks everything. I haven't tested it with all the omissions.

But I figured I'd include it anyway just in case it proves helpful to anyone (or if some gurus want to point out that I've done something horrendously wrong).

volatile long adcbin;
volatile long cnt;


void setup()
{
  Serial.begin(115200);     //begin Serial comm

  adcbin = 0;    //accumulation bin
  cnt = 0;    //count variable

  ADMUX |= (1 << REFS0); // Set ADC reference to AVCC

  ADCSRA |= (1 << ADEN);  // Enable ADC
  ADCSRA |= (1 << ADATE); // Enable auto-triggering
  ADCSRA |= (1 << ADIE);  // Enable ADC Interrupt

  sei();                 // Enable Global Interrupts

  ADCSRA |= (1 << ADSC);  // Start A2D Conversions
}

void loop()
{
  delay(1000);        //Every second:

  ADCSRA &= ~(1 << ADSC);    //Stop ADC
  ADCSRA &= ~(1(ADCSRA,ADIE);    //Disable ADC interrupts

  Serial.print(adcbin,DEC);    //Print the sum of ADC values
  Serial.print("/");
  Serial.print(cnt,DEC);    //divided by the number of samples
  cnt = adcbin / cnt;        
  Serial.println(cnt,DEC);    //Gives you the average sample's ADC value

  cnt = 0;            //Re-initialize
  adcbin = 0;

  ADCSRA |= (1 << ADIE);    //Re-enable ADC interrupts and A2D conversions
  ADCSRA |= (1 << ADSC);
}

ISR(ADC_vect)            //ADC interrupt
{
  uint8_t high,low;

  low = ADCL;            //Make certain to read ADCL first, it locks the values
  high = ADCH;            //and ADCH releases them.

  aval = (high << 8) | low;

  /* for further brevity at cost of clarity

      aval = ADCL | (ADCH << 8);

  also seems to work        */

    adcbin = adcbin + aval;    //accumulate the ADC values
    cnt++;            //iterate the counter

}