ADC free running mode

Go To Last Post
8 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello guys

 

I wanna implement ADC in the free running mode on arduino atmega 2560. I opened the datasheet of atmega 2560 and checked that bits that are responsible for this mode and found the ADATE to enable the auto trigger mode and the ADTS0 ,ADTS1 and ADTS2 for the selection of trigger source . What I understand from the datasheet is that the free running mode is the a case of auto triggering mode and the trigger is the interrupt flag of the ADC so I should set the ADCIF to zero to allow the next conversion take place as the trigger is the interrupt..

did I get it right ??

 

this is the code I wrote after checking the datasheet and the important  registers ..I can not try the code out now unfortunately .I have to be in the lab at the faculty and it is weekend .That is if someone is

wondering why did not I try this out..

#include <avr/io.h>
#include <avr/delay.h>
#include <util/delay.h>

uint16_t bits=0;
double volt=0.0;

uint16_t read_adc()
{
   ADMUX = 0b01000000;           //Internal 5 Voltage Reference with external capacitor at AREF pin
                                 // and channel 0 selection

   ADCSRB |= (0<<MUX5);   // to write 0 in mux 5 in register ADCSRB

   ADCSRB |=(0<<ADTS0) |(0<<ADTS1)|(0<<ADTS2);

   ADCSRA |= (1<<ADSC);      //Starts a new conversion

   ADCSRA |=(1<<ADEN);
   ADCSRA |=(1<<ADATE);
   ADCSRA |=(1<<ADIE);

   while(ADCSRA & (1<<ADSC));  //Wait until the conversion is done

   return ADCW;

 }         //Returns the ADC value of the chosen channel

void setup() {

   Serial.begin(9600);

   ADMUX = 0b01000000;           //Internal 5 Voltage Reference with external capacitor at AREF pin
                                 // and channel 0 selection

   ADCSRB |= (0<<MUX5);   // to write 0 in mux 5 in register ADCSRB

   ADCSRB |=(0<<ADTS0) |(0<<ADTS1)|(0<<ADTS2);  //free running mode

   ADCSRA |= (1<<ADSC);      //Starts a new conversion

   ADCSRA |=(1<<ADEN)| (1<<ADATE)| (1<<ADIE);

   ADCSRA |=(1<<ADPS0)|(1<<ADPS1)| (1<<ADPS2); //128 division factor

} 

void loop()
{

  if(ADCSRA & (1<<ADIF)==1)
  {
    bits=ADCW;

    ADCSRA|=(0<<ADIF);

  }

volt=bits*(5.0/1023.0);

Serial.println(volt);
Serial.println(bits);

delay(5);

}

 

Thanksss in advance

Mayar Negm

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Must be the phase of the moon as we’ve had a few posters this week who think 0<<x is going to do something useful for them. 0 shifted as many times as you like still equals zero then ORing that does nothing as x ORed with 0 = x. There’s a tutorial on bit manipulation in the tutorial section that explains.
You also do some nasty things like enabling the interrupts without a corresponding isr. Also fiddling with the adc configuration after you’ve started it is not a good idea.
So why do you wanna use free run mode? The datasheet tells you of possible side effects.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

MayarNegm wrote:
What I understand from the datasheet is that the free running mode is the a case of auto triggering mode and the trigger is the interrupt flag of the ADC so I should set the ADCIF to zero to allow the next conversion take place as the trigger is the interrupt.. did I get it right ??

I think you might be reading too much into that "trigger" sentence in the datasheet.  IMO/IME ADSC is set to start the first conversion in free-running mode and then the rest just "happen".

 

As mentioned, free-running doesn't come up much in practice.

 

The first conversion must be started by writing a logical one to the ADSC bit in ADCSRA. In this mode the ADC will perform successive conversions independently of whether the ADC Interrupt Flag, ADIF is cleared or not.
 

In the few times I've used free-running over the years, I never fussed with ADIF.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
    ADCSRA|=(0<<ADIF);

Apart from the point that Karman made about 0<< (which you really need to understand anyway!) the datasheet says this:

 

so the way to clear it is:

    ADCSRA |= (1 << ADIF);

(and yes that does look counter-intuitive!). Actually the above will do a read-modify-write so it will read the contents of ADCSRA then set the ADIF bit within the value read, then write it back. But you are clearing it because it is already set so simply:

    ADCSRA = ADCSRA;

will clear it in fact ;-)

 

(and how confusing is that ?!)

 

But like Lee says, why bother? If you were going to clear the bit then wait for it to become set again then I could see the point in clearing it. But actually Arduino is going to call loop() regularly anyway. So why not just use:

void loop()
{

    bits=ADCW;

    volt=bits*(5.0/1023.0);
etc.

anyway. Either this just reads the same as last time (because the current conversion is only part way through) or it reads the "next value" because a conversion just completed.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
// Voltage Reference: AVCC pin
#define ADC_VREF_TYPE ((0<<REFS1) | (1<<REFS0) | (0<<ADLAR))

// Read the AD conversion result
unsigned int read_adc(unsigned char adc_input)
{
ADMUX=adc_input | ADC_VREF_TYPE;
// Delay needed for the stabilization of the ADC input voltage
delay_us(10);
// Start the AD conversion
ADCSRA|=(1<<ADSC);
// Wait for the AD conversion to complete
while ((ADCSRA & (1<<ADIF))==0);
ADCSRA|=(1<<ADIF);
return ADCW;
}

 

MG

I don't know why I'm still doing this hobby

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

For instance, the ADC free-running mode allowed me to write time-division programs (written in assembly). 

 

For example, if the ADC prescaler is set at 1/64 (in ATmega8), the interval between two ADC readings would be 832 MCU clock cycles (64*13).

After reading the ADC registers, a common code is executed. Then, by IJMP, one coded slice after another could be executed with time. Each slice will, in turn, LJMP to a common ending code that also returns back to the checking loop of ADIF.

 

In my programs, I usually choose the number of slices from 16 to 256 as the application requires. And it happens that 832 cycles are enough to execute the common, slide and ending codes. I just need to distribute properly my various functions into the time-division parts (slices).

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Kartman wrote:

Must be the phase of the moon as we’ve had a few posters this week who think 0<<x is going to do something useful for them. 0 shifted as many times as you like still equals zero then ORing that does nothing as x ORed with 0 = x.

 

I can think of a couple of justifications for writing 0<<x - While it contributes nothing to the final value, it does explicitly show ones intention of bit x being zero.  I will occasionally do this as a form of comment / documentation when initializing a peripheral

 

Eg:

 

SPCR = (0<<SPIE) | (1<<SPE) | (0<<DORD) | (1<<MSTR) | (0<<CPOL) | (0<<CPHA) | ( (0<<SPR1) | (1<<SPR0) );

 

Which explicitly shows my intended setting of every single single bit in SPCR rather than:

 

SPCR = (1<<SPE) | (1<<MSTR) | (1<<SPR0);

 

 

 

It is also is a matter of convenience.  When debugging or what not, it makes it very easy to adjust settings simply by editing a 0 to a 1 or vice versa.

 

 

Of course that is quite a bit different than

 

SPCR |= (0<<SPIE);

 

But I just don't think the use of 0<<x should be written off entirely as worthless.

Last Edited: Sat. Oct 14, 2017 - 12:42 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
(and yes that does look counter-intuitive!). Actually the above will do a read-modify-write so it will read the contents of ADCSRA then set the ADIF bit within the value read, then write it back. But you are clearing it because it is already set so simply: ADCSRA = ADCSRA; will clear it in fact ;-)

 

And any read-modify-write opartion on any of the other bits of that register will clear it too.

 

 

Paul van der Hoeven.
Bunch of old projects with AVR's:
http://www.hoevendesign.com