aboutsummaryrefslogtreecommitdiff
path: root/platforms/avr/drivers/analog.c
diff options
context:
space:
mode:
Diffstat (limited to 'platforms/avr/drivers/analog.c')
-rw-r--r--platforms/avr/drivers/analog.c138
1 files changed, 138 insertions, 0 deletions
diff --git a/platforms/avr/drivers/analog.c b/platforms/avr/drivers/analog.c
new file mode 100644
index 000000000..8d299ffdb
--- /dev/null
+++ b/platforms/avr/drivers/analog.c
@@ -0,0 +1,138 @@
1/* Copyright 2015 Jack Humbert
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include <avr/io.h>
18#include <avr/pgmspace.h>
19#include <stdint.h>
20#include "analog.h"
21
22static uint8_t aref = ADC_REF_POWER;
23
24void analogReference(uint8_t mode) { aref = mode & (_BV(REFS1) | _BV(REFS0)); }
25
26// Arduino compatible pin input
27int16_t analogRead(uint8_t pin) {
28#if defined(__AVR_ATmega32U4__)
29 // clang-format off
30 static const uint8_t PROGMEM pin_to_mux[] = {
31 //A0 A1 A2 A3 A4 A5
32 //F7 F6 F5 F4 F1 F0
33 0x07, 0x06, 0x05, 0x04, 0x01, 0x00,
34 //A6 A7 A8 A9 A10 A11
35 //D4 D7 B4 B5 B6 D6
36 0x20, 0x22, 0x23, 0x24, 0x25, 0x21
37 };
38 // clang-format on
39 if (pin >= 12) return 0;
40 return adc_read(pgm_read_byte(pin_to_mux + pin));
41#elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB647__) || defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB1287__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328__)
42 if (pin >= 8) return 0;
43 return adc_read(pin);
44#else
45 return 0;
46#endif
47}
48
49int16_t analogReadPin(pin_t pin) { return adc_read(pinToMux(pin)); }
50
51uint8_t pinToMux(pin_t pin) {
52 switch (pin) {
53 // clang-format off
54#if defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB647__) || defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB1287__)
55 case F0: return 0; // ADC0
56 case F1: return _BV(MUX0); // ADC1
57 case F2: return _BV(MUX1); // ADC2
58 case F3: return _BV(MUX1) | _BV(MUX0); // ADC3
59 case F4: return _BV(MUX2); // ADC4
60 case F5: return _BV(MUX2) | _BV(MUX0); // ADC5
61 case F6: return _BV(MUX2) | _BV(MUX1); // ADC6
62 case F7: return _BV(MUX2) | _BV(MUX1) | _BV(MUX0); // ADC7
63 default: return _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1) | _BV(MUX0); // 0V
64#elif defined(__AVR_ATmega16U4__) || defined(__AVR_ATmega32U4__)
65 case F0: return 0; // ADC0
66 case F1: return _BV(MUX0); // ADC1
67 case F4: return _BV(MUX2); // ADC4
68 case F5: return _BV(MUX2) | _BV(MUX0); // ADC5
69 case F6: return _BV(MUX2) | _BV(MUX1); // ADC6
70 case F7: return _BV(MUX2) | _BV(MUX1) | _BV(MUX0); // ADC7
71 case D4: return _BV(MUX5); // ADC8
72 case D6: return _BV(MUX5) | _BV(MUX0); // ADC9
73 case D7: return _BV(MUX5) | _BV(MUX1); // ADC10
74 case B4: return _BV(MUX5) | _BV(MUX1) | _BV(MUX0); // ADC11
75 case B5: return _BV(MUX5) | _BV(MUX2); // ADC12
76 case B6: return _BV(MUX5) | _BV(MUX2) | _BV(MUX0); // ADC13
77 default: return _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1) | _BV(MUX0); // 0V
78#elif defined(__AVR_ATmega32A__)
79 case A0: return 0; // ADC0
80 case A1: return _BV(MUX0); // ADC1
81 case A2: return _BV(MUX1); // ADC2
82 case A3: return _BV(MUX1) | _BV(MUX0); // ADC3
83 case A4: return _BV(MUX2); // ADC4
84 case A5: return _BV(MUX2) | _BV(MUX0); // ADC5
85 case A6: return _BV(MUX2) | _BV(MUX1); // ADC6
86 case A7: return _BV(MUX2) | _BV(MUX1) | _BV(MUX0); // ADC7
87 default: return _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1) | _BV(MUX0); // 0V
88#elif defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328__)
89 case C0: return 0; // ADC0
90 case C1: return _BV(MUX0); // ADC1
91 case C2: return _BV(MUX1); // ADC2
92 case C3: return _BV(MUX1) | _BV(MUX0); // ADC3
93 case C4: return _BV(MUX2); // ADC4
94 case C5: return _BV(MUX2) | _BV(MUX0); // ADC5
95 // ADC7:6 not present in DIP package and not shared by GPIO pins
96 default: return _BV(MUX3) | _BV(MUX2) | _BV(MUX1) | _BV(MUX0); // 0V
97#endif
98 // clang-format on
99 }
100 return 0;
101}
102
103int16_t adc_read(uint8_t mux) {
104 uint16_t low;
105
106 // Enable ADC and configure prescaler
107 ADCSRA = _BV(ADEN) | ADC_PRESCALER;
108
109#if defined(__AVR_ATmega16U4__) || defined(__AVR_ATmega32U4__)
110 // High speed mode and ADC8-13
111 ADCSRB = _BV(ADHSM) | (mux & _BV(MUX5));
112#elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB647__) || defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB1287__)
113 // High speed mode only
114 ADCSRB = _BV(ADHSM);
115#endif
116
117 // Configure mux input
118#if defined(MUX4)
119 ADMUX = aref | (mux & (_BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1) | _BV(MUX0)));
120#else
121 ADMUX = aref | (mux & (_BV(MUX3) | _BV(MUX2) | _BV(MUX1) | _BV(MUX0)));
122#endif
123
124 // Start the conversion
125 ADCSRA |= _BV(ADSC);
126 // Wait for result
127 while (ADCSRA & _BV(ADSC))
128 ;
129 // Must read LSB first
130 low = ADCL;
131 // Must read MSB only once!
132 low |= (ADCH << 8);
133
134 // turn off the ADC
135 ADCSRA &= ~(1 << ADEN);
136
137 return low;
138}