MEAM.Design - ATmega32 Programming - Analog-to-Digital Conversion
Overview
The ATmega32U4 contains a 10-bit successive approximation analog-to-digital converter. Twelve of the GPIO pins can be used as analog inputs, and can be configured as either single-ended or differential.
To set up a conversion, you need to:
2. set the ADC clock prescaler
3. disable some digital inputs
4. set up interrupts and triggering, if desired
5. select the desired analog input
6. enable conversions
7. start the conversion process
8. wait for the conversion to complete
9. read the result
10. clear the conversion complete (or interrupt) flag
Once started, it will take 25 ADC clock cycles for the first conversion, then 13 clock cycles for subsequent conversions.
Voltage Reference
The reference voltage for the ADC is set by the REFS1 and REFS0 bits in ADMUX as:
ADMUX: REFS1 | ADMUX: REFS0 | |
0 | 0 | external AREF (AR pin) - DEFAULT |
0 | 1 | Vcc |
1 | 1 | internal 2.56V |
Note - Do not set this to Vcc or 2.56V if there is a voltage applied to the AR pin, as they will be shorted together!
ADC Prescaler
The ADC clock should be set to between 50 and 200 kHz for maximum accuracy. The ADC prescaler works off of the system clock, so you must know what your system prescaler is set to first, then set the following:
ADCSRA: ADPS2 | ADCSRA: ADPS1 | ADCSRA: ADPS0 | |
0 | 0 | 0 or 1 | /2 |
0 | 1 | 0 | /4 |
0 | 1 | 1 | /8 |
1 | 0 | 0 | /16 |
1 | 0 | 1 | /32 |
1 | 1 | 0 | /64 |
1 | 1 | 1 | /128 |
Disabling Digital Inputs
When you connect an analog signal to one of the ADC pins, you need to disable that pin's digital input circuitry by setting the ADCnD bit in either DIDR0 or DIDR2 (bits 0-7 are in DIDR0, while 8-13 are in DIDR2).
Then note this interesting tidbit from section 24.7.2 (page 302) of the datasheet: "If any ADC port pins are used as digital outputs, it is essential that these do not switch while a conversion is in progress." Take that for what you will.
Interrupts
To call an interrupt when each conversion is finished, set the ADCSRA : ADIE bit, and enable global interrupts, as discussed here. The interrupt will point to the ADC_vect interrupt vector.
Triggering
To have the ADC begin a new conversion immediately after finishing a previous conversion, set the ADCSRA : ADATE bit. This will default into a "free-running" mode, where it will start a new sample on whatever channel is set in the MUXn bits (as described below). To continue sampling from a single channel, leave the MUXn bits alone. To cycle through multiple channels, you will need to modify the MUXn bits while the previous conversion is in process, but be careful about associating the read register with the proper channel.
Note - there are other ways to trigger the start of conversion (timers, external interrupts, analog comparator) - see section 24.9.4 of the full datasheet for more information.
Single-Ended Channel Selection
To connect a single-ended channel to the ADC unit, set the MUXn bits which are spread across ADMUX and ADCSRB according to the following table.
Note: to avoid spurious behavior, these bits should only be changed when the ADC system is disabled (ADCSRA : ADEN = 0) or at least one ADC clock cycle has passed since the start of a conversion.
ADCSRB: MUX5 | ADMUX: MUX2 | ADMUX: MUX1 | ADMUX: MUX0 | ||
0 | 0 | 0 | 0 | ADC0 | F0 |
0 | 0 | 0 | 1 | ADC1 | F1 |
0 | 1 | 0 | 0 | ADC4 | F4 |
0 | 1 | 0 | 1 | ADC5 | F5 |
0 | 1 | 1 | 0 | ADC6 | F6 |
0 | 1 | 1 | 1 | ADC7 | F7 |
1 | 0 | 0 | 0 | ADC8 | D4 |
1 | 0 | 0 | 1 | ADC9 | D6 |
1 | 0 | 1 | 0 | ADC10 | D7 |
1 | 0 | 1 | 1 | ADC11 | B4 |
1 | 1 | 0 | 0 | ADC12 | B5 |
1 | 1 | 0 | 1 | ADC13 | B6 |
1 | 1 | 1 | 1 | temp. sensor |
Starting the Conversion Process
To enable the ADC subsystem, set ADCSRA : ADEN.
To begin conversion, set ADCSRA : ADSC. This bit will be cleared automatically when each conversion is finished.
Note: Even in free-running mode you need to set ADSC to start the first conversion, but bit after the first.
Reading the Result
Once a conversion is finished, the ADCSRA : ADIF flag is set. This flag is either automatically reset when a corresponding interrupt is serviced or you need to clear it manually by writing a logical 1 to the bit.
The easiest way to access the result is to use the 16-bit register mask ADC, or you can access the individual bytes using ADCL and ADCH (Note on using the low and high byte registers: Once you read from ADCL, both registers will be frozen until you read from ADCH).
Notes
Differential Channels - To set up differential measurements, check section 24 of the datasheet.
Sample-and-Hold - To get a stable reading on the ADC, the input contains a 14pF capacitor to ground. Your input must be able to source enough current to charge up this cap within approximately one ADC clock cycle. An output impedance of less than 10kohms should work fine.