aboutsummaryrefslogtreecommitdiff
path: root/drivers/arm/analog.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/arm/analog.c')
-rw-r--r--drivers/arm/analog.c220
1 files changed, 220 insertions, 0 deletions
diff --git a/drivers/arm/analog.c b/drivers/arm/analog.c
new file mode 100644
index 000000000..57f649a81
--- /dev/null
+++ b/drivers/arm/analog.c
@@ -0,0 +1,220 @@
1/* Copyright 2019 Drew Mills
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 "analog.h"
18#include "quantum.h"
19
20
21/* User configurable ADC options */
22#ifndef ADC_CIRCULAR_BUFFER
23#define ADC_CIRCULAR_BUFFER FALSE
24#endif
25
26#ifndef ADC_NUM_CHANNELS
27#define ADC_NUM_CHANNELS 1
28#elif ADC_NUM_CHANNELS != 1
29#error "The ARM ADC implementation currently only supports reading one channel at a time."
30#endif
31
32#ifndef ADC_BUFFER_DEPTH
33#define ADC_BUFFER_DEPTH 2
34#endif
35
36// For more sampling rate options, look at hal_adc_lld.h in ChibiOS
37#ifndef ADC_SAMPLING_RATE
38#define ADC_SAMPLING_RATE ADC_SMPR_SMP_1P5
39#endif
40
41// Options are 12, 10, 8, and 6 bit.
42#ifndef ADC_RESOLUTION
43#define ADC_RESOLUTION ADC_CFGR1_RES_12BIT
44#endif
45
46
47
48static ADCConfig adcCfg = {};
49static adcsample_t sampleBuffer[ADC_NUM_CHANNELS * ADC_BUFFER_DEPTH];
50
51// Initialize to max number of ADCs, set to empty object to initialize all to false.
52#if defined(STM32F0XX)
53static bool adcInitialized[1] = {};
54#elif defined(STM32F3XX)
55static bool adcInitialized[4] = {};
56#else
57#error "adcInitialized has not been implemented for this ARM microcontroller."
58#endif
59
60
61
62static ADCConversionGroup adcConversionGroup = {
63 ADC_CIRCULAR_BUFFER,
64 (uint16_t)(ADC_NUM_CHANNELS),
65 NULL, // No end callback
66 NULL, // No error callback
67#if defined(STM32F0XX)
68 ADC_CFGR1_CONT | ADC_RESOLUTION,
69 ADC_TR(0, 0).
70 ADC_SAMPLING_RATE,
71 NULL, // Doesn't specify a default channel
72#elif defined(STM32F3XX)
73 ADC_CFGR_CONT | ADC_RESOLUTION,
74 ADC_TR(0, 4095),
75 {
76 ADC_SAMPLING_RATE,
77 ADC_SAMPLING_RATE,
78 },
79 {
80 0, // Doesn't specify a default channel
81 0,
82 0,
83 0,
84 },
85#endif
86};
87
88
89
90static inline ADCDriver* intToADCDriver(uint8_t adcInt) {
91
92 ADCDriver* target;
93
94 switch (adcInt) {
95 // clang-format off
96#if STM32_ADC_USE_ADC1
97 case 0: target = &ADCD1; break;
98#endif
99#if STM32_ADC_USE_ADC2
100 case 1: target = &ADCD2; break;
101#endif
102#if STM32_ADC_USE_ADC3
103 case 2: target = &ADCD3; break;
104#endif
105#if STM32_ADC_USE_ADC4
106 case 3: target = &ADCD4; break;
107#endif
108 default: target = NULL; break;
109 // clang-format on
110 }
111
112 return target;
113}
114
115static inline void manageAdcInitializationDriver(uint8_t adc, ADCDriver* adcDriver) {
116 if (!adcInitialized[adc]) {
117 adcStart(adcDriver, &adcCfg);
118 adcInitialized[adc] = true;
119 }
120}
121
122static inline void manageAdcInitialization(uint8_t adc) {
123 manageAdcInitializationDriver(adc, intToADCDriver(adc));
124}
125
126pin_and_adc pinToMux(pin_t pin) {
127 switch(pin) {
128 // clang-format off
129#if defined(STM32F0XX)
130 case A0: return (pin_and_adc){ ADC_CHANNEL_IN0, 0 };
131 case A1: return (pin_and_adc){ ADC_CHANNEL_IN1, 0 };
132 case A2: return (pin_and_adc){ ADC_CHANNEL_IN2, 0 };
133 case A3: return (pin_and_adc){ ADC_CHANNEL_IN3, 0 };
134 case A4: return (pin_and_adc){ ADC_CHANNEL_IN4, 0 };
135 case A5: return (pin_and_adc){ ADC_CHANNEL_IN5, 0 };
136 case A6: return (pin_and_adc){ ADC_CHANNEL_IN6, 0 };
137 case A7: return (pin_and_adc){ ADC_CHANNEL_IN7, 0 };
138 case B0: return (pin_and_adc){ ADC_CHANNEL_IN8, 0 };
139 case B1: return (pin_and_adc){ ADC_CHANNEL_IN9, 0 };
140 case C0: return (pin_and_adc){ ADC_CHANNEL_IN10, 0 };
141 case C1: return (pin_and_adc){ ADC_CHANNEL_IN11, 0 };
142 case C2: return (pin_and_adc){ ADC_CHANNEL_IN12, 0 };
143 case C3: return (pin_and_adc){ ADC_CHANNEL_IN13, 0 };
144 case C4: return (pin_and_adc){ ADC_CHANNEL_IN14, 0 };
145 case C5: return (pin_and_adc){ ADC_CHANNEL_IN15, 0 };
146#elif defined(STM32F3XX)
147 case A0: return (pin_and_adc){ ADC_CHANNEL_IN1, 0 };
148 case A1: return (pin_and_adc){ ADC_CHANNEL_IN2, 0 };
149 case A2: return (pin_and_adc){ ADC_CHANNEL_IN3, 0 };
150 case A3: return (pin_and_adc){ ADC_CHANNEL_IN4, 0 };
151 case A4: return (pin_and_adc){ ADC_CHANNEL_IN1, 1 };
152 case A5: return (pin_and_adc){ ADC_CHANNEL_IN2, 1 };
153 case A6: return (pin_and_adc){ ADC_CHANNEL_IN3, 1 };
154 case A7: return (pin_and_adc){ ADC_CHANNEL_IN4, 1 };
155 case B0: return (pin_and_adc){ ADC_CHANNEL_IN12, 2 };
156 case B1: return (pin_and_adc){ ADC_CHANNEL_IN1, 2 };
157 case B2: return (pin_and_adc){ ADC_CHANNEL_IN12, 1 };
158 case B12: return (pin_and_adc){ ADC_CHANNEL_IN2, 3 };
159 case B13: return (pin_and_adc){ ADC_CHANNEL_IN3, 3 };
160 case B14: return (pin_and_adc){ ADC_CHANNEL_IN4, 3 };
161 case B15: return (pin_and_adc){ ADC_CHANNEL_IN5, 3 };
162 case C0: return (pin_and_adc){ ADC_CHANNEL_IN6, 0 }; // Can also be ADC2
163 case C1: return (pin_and_adc){ ADC_CHANNEL_IN7, 0 }; // Can also be ADC2
164 case C2: return (pin_and_adc){ ADC_CHANNEL_IN8, 0 }; // Can also be ADC2
165 case C3: return (pin_and_adc){ ADC_CHANNEL_IN9, 0 }; // Can also be ADC2
166 case C4: return (pin_and_adc){ ADC_CHANNEL_IN5, 1 };
167 case C5: return (pin_and_adc){ ADC_CHANNEL_IN11, 1 };
168 case D8: return (pin_and_adc){ ADC_CHANNEL_IN12, 3 };
169 case D9: return (pin_and_adc){ ADC_CHANNEL_IN13, 3 };
170 case D10: return (pin_and_adc){ ADC_CHANNEL_IN7, 2 }; // Can also be ADC4
171 case D11: return (pin_and_adc){ ADC_CHANNEL_IN8, 2 }; // Can also be ADC4
172 case D12: return (pin_and_adc){ ADC_CHANNEL_IN9, 2 }; // Can also be ADC4
173 case D13: return (pin_and_adc){ ADC_CHANNEL_IN10, 2 }; // Can also be ADC4
174 case D14: return (pin_and_adc){ ADC_CHANNEL_IN11, 2 }; // Can also be ADC4
175 case E7: return (pin_and_adc){ ADC_CHANNEL_IN13, 2 };
176 case E8: return (pin_and_adc){ ADC_CHANNEL_IN6, 2 }; // Can also be ADC4
177 case E9: return (pin_and_adc){ ADC_CHANNEL_IN2, 2 };
178 case E10: return (pin_and_adc){ ADC_CHANNEL_IN14, 2 };
179 case E11: return (pin_and_adc){ ADC_CHANNEL_IN15, 2 };
180 case E12: return (pin_and_adc){ ADC_CHANNEL_IN16, 2 };
181 case E13: return (pin_and_adc){ ADC_CHANNEL_IN3, 2 };
182 case E14: return (pin_and_adc){ ADC_CHANNEL_IN1, 3 };
183 case E15: return (pin_and_adc){ ADC_CHANNEL_IN2, 3 };
184 case F2: return (pin_and_adc){ ADC_CHANNEL_IN10, 0 }; // Can also be ADC2
185 case F4: return (pin_and_adc){ ADC_CHANNEL_IN5, 0 };
186#else
187#error "An ADC pin-to-mux configuration has not been specified for this microcontroller."
188#endif
189 default: return (pin_and_adc){ 0, 0 };
190 // clang-format on
191 }
192}
193
194adcsample_t analogReadPin(pin_t pin) {
195 return adc_read(pinToMux(pin));
196}
197
198adcsample_t analogReadPinAdc(pin_t pin, uint8_t adc) {
199 pin_and_adc target = pinToMux(pin);
200 target.adc = adc;
201 return adc_read(target);
202}
203
204adcsample_t adc_read(pin_and_adc mux) {
205#if defined(STM32F0XX)
206 adcConversionGroup.sqr = ADC_CHSELR_CHSEL1;
207#elif defined(STM32F3XX)
208 adcConversionGroup.sqr[0] = ADC_SQR1_SQ1_N(mux.pin);
209#else
210#error "adc_read has not been updated to support this ARM microcontroller."
211#endif
212
213 ADCDriver* targetDriver = intToADCDriver(mux.adc);
214 manageAdcInitializationDriver(mux.adc, targetDriver);
215
216 adcConvert(targetDriver, &adcConversionGroup, &sampleBuffer[0], ADC_BUFFER_DEPTH);
217 adcsample_t* result = sampleBuffer;
218
219 return *result;
220}