[TUT] [C] Newbie's Guide to the AVR ADC

Go To Last Post
324 posts / 0 new

Pages

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

Quote:

when i check at AVR Studio

Do you mean using a debug interface to a real AVR such as Dragon or JTAGICEmkII or are you talking about the simulator? If the latter - trust it about as far as you could comfortably spit it.

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

i meant the simulator in AVR studio 4.
so it doesnt work fine?
hmmm, good to know.
can u tell me more about these "Dragon or JTAGICEmkII"??

and, any clues about the free-running not working ?(or we cant have a conclusion, cause debbuging at AVR studio sucks, and simulation at AVR Simulator IDE sucks too?)

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

A Dragon ($50) or a JTAGICEmkII ($299) is a block of electronics that sits between the PC and the AVR. Unlike an ISP programmer (though both can do that as well) they are also an OCD (On Chip Debug) interface and for those AVRs that have either JTAG, debugWire or PDI interfaces they allow you to step code, set breakpoints, examine memory and registers and all those other things the simulator appears to offer but they are actually opening a "window" into the real AVR so there's no worries about dodgy, half-implemented simulations because now you are watching the code running on the real AVR core which (obviously?) works 100% accurately like the real thing (because it is).

The $50 Dragon is a good way to get started with OCD.

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

Could somebody post very simple C code example of how to use adc in multiple channel mode?

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

Quote:

Could somebody post very simple C code example of how to use adc in multiple channel mode?

Following written for GCC and mega48/88/168/328:

//==================================================================
// following not used (yet) - just documenting that this is
// designed for an 8MHz CPU. Code written for ATmega48/88/168/328
#undef F_CPU
#define F_CPU 8000000UL

#include  
#include 

#define REFERENCE ((0<<REFS1) | (1<<REFS0)) /* ref = AVcc */

volatile uint16_t readings[8];
uint8_t channel;

int main(void) {
    ADMUX = REFERENCE;              // set ref and channel 0
    ADCSRA = (1<<ADEN) |            // enable ADC
             (1<<ADIE) |            // going to use interrupts
             (1<<ADPS2)|(1<<ADPS1); // use 8MHz/64 = 125kHz
    sei();                          // turn on interrupt system
    ADCSRA |= (1<<ADSC);            // trigger first conversion/int
    while(1) {
                                    // use readings[] here
	}
} 

ISR(ADC_vect) {
	// take reading that tiggered interrupt
	readings[channel] = ADCW;
	// move onto next channel
	channel++;
	// but if we have reached 7 return to 0
	channel = (channel > 7) ? 0 : channel;
	// set next channel not forgetting to keep ref setting
	ADMUX = REFERENCE | channel;
	// trigger next conversion
	ADCSRA |= (1<<ADSC);
}

(NB: Tested in simulator V2 but not with real hardware)

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

It would be nice if someone tell me a program of how to convert the output of ADC to readable value. e.g.

ADMUX = 0xED (ADC3 - ADC2, 10x gain, 2.56V reference, left adjusted result)
Voltage on ADC3 is 300 mV, voltage on ADC2 is 500 mV.
ADCR = 512 * 10 * (300 - 500) / 2560 = -400 = 0x270

ADCL will thus read 0x00, and ADCH will read 0x9C. Writing zero to ADLAR right adjusts the
result: ADCL = 0x70, ADCH = 0x02.

but from above value of ADCL/H, how one can understand that the differential voltage was -200mV at gain of 10x???

(P.S. This example is from ATMega128 data sheet)

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

I just wanted to know expert advice whether following code will run or not for ATMega128 (14745600 MHz). As I havn't got the hardware yet but logically I have structured the code

Following function I am calling from the main once

void InitADC(void)
{
	//Configure ADC in order to read Acceleration	
	//Set ADC prescalar to 128 - 115.2KHz sample rate @ 14.7456MHz
	ADCSRA |= (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0);

	//Reference voltage to be taken from AVCC
	ADMUX |= (1 << REFS0);

	//Left adjust ADC result to allow easy 8 bit reading
	ADMUX |= (1 << ADLAR);
	// Enable ADC
	ADCSRA |= (1 << ADEN); 
}

and this one I am calling from a non-premptive co-operative multitasking scheduler at the rate of 50 ms

void ScanADCValues(void)
{
	int iInputChannel = 0;
	
	for (iInputChannel =0; iInputChannel 

If anyone finds anything please let me know so that this can be improved

Thanks in advance!

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

Quote:
14745600 MHz
I don't think a mega128 will run that fast ;)

m_dwAccelerationZAxis = ADCH | (ADCL << 8)

In your InitADC you say you are left adjusting for easy 8 bit reading, but then you read 16 bits. Also, ADCL must be read before ADCH. This code does not guarantee that. Most (if not all) compilers have methods to read the entire 16 bits (in avr-gcc you can use either ADC or ADCW).

Quote:
//No need to configure MUX inputs
Yes there is. Your ADMUX will be set to whatever channel was last read. It is safest to set all MUXx bits whenever you change channels.

 _delay_ms(2); 

Do you really need to wait 2ms between channel reads? Why not just wait for ADSC to go low?

Regards,
Steve A.

The Board helps those that help themselves.

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

And if you were using 10 bits, you have the low and high mixed up: ADCH | (ADCL << 8). It's the high bits that should be shifted left.

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

@Koshchi
OOPS...sorry I mean 14745600 Hz!

as far as 2ms wait is concerned, I have just put it in to have a deterministic delay. The function ScanADCValues() will be run through scheduler. Is it advisable to put something like
" while(!(ADCSRA & (1 << ADSC))); " in schedular?

niways Thanks a lot bretm and Koshchi for valuable inputs

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

Hello.
I'd like to know some information about AREF. What range of voltages can I connect AREF to? I need an external 15v reference. Is there a way to do that?
Thank you!!

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

It can only be up to Vcc+0.5V (it says in the datasheet) so 15V is out of the question. Either use a potential divider or, better, an op-amp to scale the reference and signal to be sampled into the 0V..Vcc range.

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

Hi there, excellent tutorial and great examples.
Is the 330 ohm resistors really necessary, shouldn't the analog input pins have large input impedance.

Thanks
Abunada

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

can this code be used on atmega 88, if not plz mention the changes..

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

Quote:

can this code be used on atmega 88, if not plz mention the changes

The code appears to use ADFR on the mega128 to enable "Free Run" mode. This is slightly different on the mega88. For that chip you set ADATE in ADCSRA to enable auto triggering then the ADTS bits in ADCSRB set what triggers the automatic conversions. As it happens the default setting of the threee ADTS bits are 000 which selects "Free Run" anyway. So simply using ADATE rather than ADFR is all that's required.

(this does then raise the question of whether you want to use "Free Run" anyway - it's fine if you have just one channel and always want an "up to date" reading available but if you plan to read more than one channel forget "Free Run" anyway)

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

This might be known to many of you here but ...seems like mistake to me in 'ATmega128 Manual'

Quote:
The ATmega128 features a 10-bit successive approximation ADC. The ADC is connected to an
8-channel Analog Multiplexer which allows 8 single-ended voltage inputs constructed from the
pins of Port A.
OR is it something different which I could not understand ???

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

That looks like one of Atmel's famous copy/paste errors. They clearly started the ADC text of that datasheet using one of the prior models which typically do have the ADC mux inputs on A, clearly it is F for mega128.

EDIT: wait a minute though, the copy of the mega128 data I have here says:

Quote:
The ATmega128 features a 10-bit successive approximation ADC. The ADC is connected to an 8-channel Analog Multiplexer which allows 8 single-ended voltage inputs constructed from the pins of Port F

this is in issue 2467R–AVR–06/08. Suggests yours may be out of date.

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

suppose i am using sensors to guide a bot which are directly connected to the ADC.Would it not be possible?

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

Quote:
suppose i am using sensors to guide a bot which are directly connected to the ADC.Would it not be possible?

Sorry, I thought it was more or less obvious that I was kind of pulling your leg.

No, you can not read two different ports at exactly the same time. But now the question rather seems to be "sufficiently close enough in time". You can read two ports one after the other, and if your AVR runs at e.g. 8 MHz then the reads will be separated by just a few microseconds. What are your your requirements on timing of two adjacent reads?

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

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

Thanks for the tutorial!

I'm thinking why do you need to change the ADC clock cycle for?

What if I want to receive signal from 20Hz - 20kHz? Is there any necessary changes for that range of frequency?

And just to check my understanding, I have read the ATmega16 datasheet, and it says that the pin can receive the voltage up to 2.56V. How could you measure up to 5V in this case? Or is it just because the ATmega128 and ATmega16 has different feature?

L

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

Quote:

I'm thinking why do you need to change the ADC clock cycle for?

Because the datasheet says that the ADC clock must be in the range 50kHz..200kHz so you divide the 1/2/4/8MHz/whatever that the CPU is clocked at to get the ADC clock into that range. If you can get it to 200kHz (sometimes dropping F_CPU actually helps!) then because of the 13 clock conversion time the maximum rate you can get is 15.3kHz. While you can run faster than this (some people have taken the 200kHz limit to as much as 1MHz) you will start to lose bits of resolution and will no longer get 10 bit accuracy.

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

Quote:
What if I want to receive signal from 20Hz - 20kHz?
You are confusing the frequency of the signal with the frequency of the ADC clock. The ADC clock only determines the length of time the conversion takes.

Regards,
Steve A.

The Board helps those that help themselves.

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

Please don't post general questions on the end of tutorials - post this to AVR Forum instead. Moderator. (are you getting deja vu? See two posts above yours) To others, I'm going to lock this thread - if you have something to add to the tutorial itself PM one of the moderators and we will temporarily unlock it for you to do so.

Last Edited: Sun. Jun 21, 2015 - 02:26 PM

Pages

Topic locked