AVR ADC
The Penguino has a built-in Analog to Digital Converter (ADC) which is multiplexed (shared) over the 8 pins on port A. Each of these pins is called an ADC channel and can be selected to be the input to the ADC. The ADC has a resolution of 10 bits, i.e. the analog signal present on a channel can be converted into a 10-bit number, which gives 1024 different discernible values. The ADC can sample at a rate of up to 15.4 thousand samples per second.
Pins on Port A to be used as ADC channels should be set to inputs in DDRA, and set as tri-state (floating) in PORTA. (see Digital I/O)
Like inputs and outputs, flipping bits of special registers allow you to change the ADC's settings in software. Unlike the I/O registers, the bits to configure different options are in no particular order, so they have names. These are shown in a table below along with their functionality.
When a conversion has completed, the result is stored in two 8-bit registers: ADCL and ADCH. The low bits are stored in ADCL and the high bits are stored in ADCH (unless the ADLAR bit of ADMUX is set, which adjusts the bits to the left). The ADC can be triggered manually, by setting the ADSC bit, or can be auto-triggered by another source. If the auto-trigger source is set to the completion of a conversion (setting the ADIF bit), then it is said to be in 'Free Running' mode: continuously converting and updating the data registers. Ensure settings are changed prior to a conversion taking place.
The ADC also has its own interrupt which can be enabled so that it interrupts when a conversion has completed.
The ADC has its own clock pulse which is a division of the CPU clock. Setting the pre-scale value on this clock allows a trade-off between conversion speed and sample accuracy.
Registers
For an ADC reading at 8-bit precision, ADLAR can be set and just ADCH read.
If a full 10-bit conversion is required, ADCL must be read before ADCH to ensure that the two values belong to the same conversion. The action of reading ADCL locks the values in the ADC Data Registers until ADCH is read.
Any conversions that take place when the ADC Data Registers are locked will be lost.
Register |
Bit |
Bit Name |
Function |
ADCSRA |
|||
|
7 |
ADEN |
ENable - set to enable the ADC with the current configuration |
|
6 |
ADSC |
Start Conversion - set to start a conversion. The hardware will clear this bit when the conversion has completed. |
|
5 |
ADATE |
Auto Trigger Enable - set to enable automatically triggering a conversion using the source selected by the Trigger Select bits in SFIOR |
|
4 |
ADIF |
Interrupt Flag - set by hardware when a conversion has completed and data registers are updated. Cleared by hardware if the ADC Conversion Complete Interrupt executed. |
|
3 |
ADIE |
Interrupt Enable - if this bit is set, and the global interrupt enable in SREG is set, the ADC Conversion Complete Interrupt is enabled. |
|
2 |
ADPS2 |
Pre-Scaler - 3-bit pre-scaler selection to determine the clock frequency for the ADC as a division of the CPU clock. See below. |
|
1 |
ADPS1 |
|
|
0 |
ADPS0 |
|
ADMUX |
|||
|
7 |
REFS1 |
REFerence Selection - 2-bit reference selection to determine the voltage reference for ADC conversions. See below. |
|
6 |
REFS0 |
|
|
5 |
ADLAR |
Left-Adjust the bits in the data (output) Registers. |
|
4 |
MUX4 |
MUltipleXer: Channel and gain selection bits. See below. |
|
3 |
MUX3 |
|
|
2 |
MUX2 |
|
|
1 |
MUX1 |
|
|
0 |
MUX0 |
|
ADCL |
all |
ADC data register Low byte |
The first 8 bits of the 10-bit conversion output. |
ADCH |
all |
ADC data register High byte |
The second 8 bits of the conversion output. Since the output is 10-bit, only the first two bits are used unless ADLAR is set. |
SFIOR - I/O Special Function Register
Three bits in the SFIOR determine the auto-triggering source for the ADC.
ADTS2 (bit 7) |
ADTS1 (bit 6) |
ADTS0 (bit 5) |
Source |
0 |
0 |
0 |
Free-running mode - uses the ADIF interrupt flag in ADCSRA to trigger the ADC conversion. This will continuously sample, updating the data registers. |
0 |
0 |
1 |
Analog Comparator - will trigger on the positive edge of internal analog comparator output (different to the ADC). |
0 |
1 |
0 |
External Interrupt Request 0 |
0 |
1 |
1 |
Timer/Counter 0 Compare Match |
1 |
0 |
0 |
Timer/Counter 0 Overflow |
1 |
0 |
1 |
Timer/Counter 1 Compare Match |
1 |
1 |
0 |
Timer/Counter 1 Overflow |
1 |
1 |
1 |
Timer/Counter 1 Capture Event |
ADPS - Pre-scaler selection
ADPS bits determine what speed the ADC clock runs at, compared to the CPU clock.
ADPS2 |
ADPS1 |
ADPS0 |
Division Factor |
0 |
0 |
0 |
2 |
0 |
0 |
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 |
REFS - Reference selection
REFS bits determine what voltage to use as the reference for ADC comparisons (Vref).
REFS1 |
REFS0 |
Voltage Reference Selection |
0 |
0 |
Uses the voltage on the AREF pin. Internal voltage reference turned off |
0 |
1 |
Uses the voltage on the AVCC pin. External capacitor required on AREF pin |
1 |
0 |
Reserved |
1 |
1 |
Uses internal 2.56V voltage reference. External capacitor required on AREF pin |
ADMUX - ADC Channel and Gain selection
The MUX bits configure the ADC channel multiplexers to determine the single-ended input voltage (Vin) or the positive and negative differential input voltages (V+, V-) and gain to apply.
s denotes a 'single-ended input' channel selection. + and - denote the positive and negative inputs for a differential gain channel selection.
|
Channel |
|
|||||||
MUX bits |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
Gain |
00000 |
|
|
|
|
|
|
|
s |
n/a |
00001 |
|
|
|
|
|
|
s |
|
n/a |
00010 |
|
|
|
|
|
s |
|
|
n/a |
00011 |
|
|
|
|
s |
|
|
|
n/a |
00100 |
|
|
|
s |
|
|
|
|
n/a |
00101 |
|
|
s |
|
|
|
|
|
n/a |
00110 |
|
s |
|
|
|
|
|
|
n/a |
00111 |
s |
|
|
|
|
|
|
|
n/a |
01000 |
|
|
|
|
|
|
|
+/- |
10x |
01001 |
|
|
|
|
|
|
+ |
- |
10x |
01010 |
|
|
|
|
|
|
|
+/- |
200x |
01011 |
|
|
|
|
|
|
+ |
- |
200x |
01100 |
|
|
|
|
|
+/- |
|
|
10x |
01101 |
|
|
|
|
+ |
- |
|
|
10x |
01110 |
|
|
|
|
|
+/- |
|
|
200x |
01111 |
|
|
|
|
+ |
- |
|
|
200x |
10000 |
|
|
|
|
|
|
- |
+ |
1x |
10001 |
|
|
|
|
|
|
+/- |
|
1x |
10010 |
|
|
|
|
|
+ |
- |
|
1x |
10011 |
|
|
|
|
+ |
|
- |
|
1x |
10100 |
|
|
|
+ |
|
|
- |
|
1x |
10101 |
|
|
+ |
|
|
|
- |
|
1x |
10110 |
|
+ |
|
|
|
|
- |
|
1x |
10111 |
+ |
|
|
|
|
|
- |
|
1x |
11000 |
|
|
|
|
|
- |
|
+ |
1x |
11001 |
|
|
|
|
|
- |
+ |
|
1x |
11010 |
|
|
|
|
|
+/- |
|
|
1x |
11011 |
|
|
|
|
+ |
- |
|
|
1x |
11100 |
|
|
|
+ |
|
- |
|
|
1x |
11101 |
|
|
+ |
|
|
- |
|
|
1x |
11110 |
1.22V (Vbg) |
||||||||
11111 |
0V (Gnd) |
||||||||
The resulting ADC reading is given by the formula:
for single-ended channels
and
for differential channels (given in two's complement for negative results).
Selections above with V+ and V- the same are useless.
Fine Print: 10kOhms is the optimal source impedance for ADC signals. Low impedance sources result in faster conversions. Differential gain channels should have and impedance less than a few hundred kOhm. Initial conversions on a channel take longer (25 ADC clock cycles), and are often inaccurate. Normal single-ended conversions take 13 cycles, and half a cycle longer if auto-triggered. Differential conversions take 13-14 cycles.
Setting up the Circuit
See Figure 22-8. of the ATMega32A datasheet.
Example
1 void adc_init( ) {
2 // enable the ADC, ADPS[0..2] bits = div clock by 128
3 ADCSRA = (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0);
4
5 // look at ADC pin 0 (PORTA bit 0 on the atmega32, 'A0' on the Penguino)
6 ADMUX = 0x00;
7
8 // use AVCC (the pin) as reference (REFS[0..1] = 01)
9 // pin 'AVCC' on Penguino should be connected to VCC (via a cap for extra noise reduction, see datasheet)
10 ADMUX |= (1<<REFS0);
11 }
12
13 uint16_t adc_read( ) {
14 // start a conversion
15 ADCSRA |= (1<<ADSC);
16
17 // wait for the conversion to complete
18 while ( ADCSRA & (1<<ADSC) )
19 {
20 // think about important things (nop nop nop nop)
21 }
22
23 return ADCW; // avr-libc short-cut for combining ADCL and ADCH into a 16-bit register
24 }
25
26 int main(void) {
27 // configure the ADC
28 adc_init( );
29
30 // ...
31
32 while ( 1 ) {
33 printf( "ADC: %d\r\n", adc_read( ) );
34 _delay_ms( 100 );
35 }
36
37 return 0;
38 }
![icy [labs]](/moin_static171/common/wikilogo.png)