aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/adc_driver.md2
-rw-r--r--drivers/arm/analog.c313
-rw-r--r--drivers/arm/analog.h44
-rw-r--r--keyboards/handwired/onekey/keymaps/adc/config.h1
-rw-r--r--keyboards/handwired/onekey/keymaps/adc/keymap.c38
-rw-r--r--keyboards/handwired/onekey/keymaps/adc/rules.mk3
6 files changed, 248 insertions, 153 deletions
diff --git a/docs/adc_driver.md b/docs/adc_driver.md
index d808a8215..7c4e05efc 100644
--- a/docs/adc_driver.md
+++ b/docs/adc_driver.md
@@ -2,7 +2,7 @@
2 2
3QMK can leverage the Analog-to-Digital Converter (ADC) on supported MCUs to measure voltages on certain pins. This can be useful for implementing things such as battery level indicators for Bluetooth keyboards, or volume controls using a potentiometer, as opposed to a [rotary encoder](feature_encoders.md). 3QMK can leverage the Analog-to-Digital Converter (ADC) on supported MCUs to measure voltages on certain pins. This can be useful for implementing things such as battery level indicators for Bluetooth keyboards, or volume controls using a potentiometer, as opposed to a [rotary encoder](feature_encoders.md).
4 4
5This driver currently supports both AVR and a limited selection of ARM devices. On AVR devices, the values returned are 10-bit integers (0-1023) mapped between 0V and VCC (usually 5V or 3.3V). On supported ARM devices, there is more flexibility in control of operation through `#define`s, but by default the values returned are 12-bit integers (0-4095) mapped between 0V and VCC (usually 3.3V). 5This driver currently supports both AVR and a limited selection of ARM devices. The values returned are 10-bit integers (0-1023) mapped between 0V and VCC (usually 5V or 3.3V for AVR, 3.3V only for ARM), however on ARM there is more flexibility in control of operation through `#define`s if you need more precision.
6 6
7## Usage 7## Usage
8 8
diff --git a/drivers/arm/analog.c b/drivers/arm/analog.c
index 427381f28..a7e6d2525 100644
--- a/drivers/arm/analog.c
+++ b/drivers/arm/analog.c
@@ -14,12 +14,74 @@
14 * along with this program. If not, see <http://www.gnu.org/licenses/>. 14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */ 15 */
16 16
17#include "analog.h"
18#include "quantum.h" 17#include "quantum.h"
18#include "analog.h"
19#include "ch.h"
20#include <hal.h>
21
22#if !HAL_USE_ADC
23# error "You need to set HAL_USE_ADC to TRUE in your halconf.h to use the ADC."
24#endif
25
26#if !STM32_ADC_USE_ADC1 && !STM32_ADC_USE_ADC2 && !STM32_ADC_USE_ADC3 && !STM32_ADC_USE_ADC4
27# error "You need to set one of the 'STM32_ADC_USE_ADCx' settings to TRUE in your mcuconf.h to use the ADC."
28#endif
29
30#if STM32_ADC_DUAL_MODE
31# error "STM32 ADC Dual Mode is not supported at this time."
32#endif
33
34#if STM32_ADCV3_OVERSAMPLING
35# error "STM32 ADCV3 Oversampling is not supported at this time."
36#endif
37
38// Otherwise assume V3
39#if defined(STM32F0XX) || defined(STM32L0XX)
40# define USE_ADCV1
41#elif defined(STM32F1XX) || defined(STM32F2XX) || defined(STM32F4XX)
42# define USE_ADCV2
43#endif
44
45// BODGE to make v2 look like v1,3 and 4
46#ifdef USE_ADCV2
47# if !defined(ADC_SMPR_SMP_1P5) && defined(ADC_SAMPLE_3)
48# define ADC_SMPR_SMP_1P5 ADC_SAMPLE_3
49# define ADC_SMPR_SMP_7P5 ADC_SAMPLE_15
50# define ADC_SMPR_SMP_13P5 ADC_SAMPLE_28
51# define ADC_SMPR_SMP_28P5 ADC_SAMPLE_56
52# define ADC_SMPR_SMP_41P5 ADC_SAMPLE_84
53# define ADC_SMPR_SMP_55P5 ADC_SAMPLE_112
54# define ADC_SMPR_SMP_71P5 ADC_SAMPLE_144
55# define ADC_SMPR_SMP_239P5 ADC_SAMPLE_480
56# endif
57
58# if !defined(ADC_SMPR_SMP_1P5) && defined(ADC_SAMPLE_1P5)
59# define ADC_SMPR_SMP_1P5 ADC_SAMPLE_1P5
60# define ADC_SMPR_SMP_7P5 ADC_SAMPLE_7P5
61# define ADC_SMPR_SMP_13P5 ADC_SAMPLE_13P5
62# define ADC_SMPR_SMP_28P5 ADC_SAMPLE_28P5
63# define ADC_SMPR_SMP_41P5 ADC_SAMPLE_41P5
64# define ADC_SMPR_SMP_55P5 ADC_SAMPLE_55P5
65# define ADC_SMPR_SMP_71P5 ADC_SAMPLE_71P5
66# define ADC_SMPR_SMP_239P5 ADC_SAMPLE_239P5
67# endif
68
69// we still sample at 12bit, but scale down to the requested bit range
70# define ADC_CFGR1_RES_12BIT 12
71# define ADC_CFGR1_RES_10BIT 10
72# define ADC_CFGR1_RES_8BIT 8
73# define ADC_CFGR1_RES_6BIT 6
74#endif
19 75
20/* User configurable ADC options */ 76/* User configurable ADC options */
21#ifndef ADC_CIRCULAR_BUFFER 77#ifndef ADC_COUNT
22# define ADC_CIRCULAR_BUFFER FALSE 78# if defined(STM32F0XX) || defined(STM32F1XX) || defined(STM32F4XX)
79# define ADC_COUNT 1
80# elif defined(STM32F3XX)
81# define ADC_COUNT 4
82# else
83# error "ADC_COUNT has not been set for this ARM microcontroller."
84# endif
23#endif 85#endif
24 86
25#ifndef ADC_NUM_CHANNELS 87#ifndef ADC_NUM_CHANNELS
@@ -29,7 +91,7 @@
29#endif 91#endif
30 92
31#ifndef ADC_BUFFER_DEPTH 93#ifndef ADC_BUFFER_DEPTH
32# define ADC_BUFFER_DEPTH 2 94# define ADC_BUFFER_DEPTH 1
33#endif 95#endif
34 96
35// For more sampling rate options, look at hal_adc_lld.h in ChibiOS 97// For more sampling rate options, look at hal_adc_lld.h in ChibiOS
@@ -39,68 +101,128 @@
39 101
40// Options are 12, 10, 8, and 6 bit. 102// Options are 12, 10, 8, and 6 bit.
41#ifndef ADC_RESOLUTION 103#ifndef ADC_RESOLUTION
42# define ADC_RESOLUTION ADC_CFGR1_RES_12BIT 104# define ADC_RESOLUTION ADC_CFGR1_RES_10BIT
43#endif 105#endif
44 106
45static ADCConfig adcCfg = {}; 107static ADCConfig adcCfg = {};
46static adcsample_t sampleBuffer[ADC_NUM_CHANNELS * ADC_BUFFER_DEPTH]; 108static adcsample_t sampleBuffer[ADC_NUM_CHANNELS * ADC_BUFFER_DEPTH];
47 109
48// Initialize to max number of ADCs, set to empty object to initialize all to false. 110// Initialize to max number of ADCs, set to empty object to initialize all to false.
49#if defined(STM32F0XX) 111static bool adcInitialized[ADC_COUNT] = {};
50static bool adcInitialized[1] = {}; 112
51#elif defined(STM32F3XX) 113// TODO: add back TR handling???
52static bool adcInitialized[4] = {}; 114static ADCConversionGroup adcConversionGroup = {
115 .circular = FALSE,
116 .num_channels = (uint16_t)(ADC_NUM_CHANNELS),
117#if defined(USE_ADCV1)
118 .cfgr1 = ADC_CFGR1_CONT | ADC_RESOLUTION,
119 .smpr = ADC_SAMPLING_RATE,
120#elif defined(USE_ADCV2)
121# if !defined(STM32F1XX)
122 .cr2 = ADC_CR2_SWSTART, // F103 seem very unhappy with, F401 seems very unhappy without...
123# endif
124 .smpr2 = ADC_SMPR2_SMP_AN0(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN1(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN2(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN3(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN4(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN5(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN6(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN7(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN8(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN9(ADC_SAMPLING_RATE),
125 .smpr1 = ADC_SMPR1_SMP_AN10(ADC_SAMPLING_RATE) | ADC_SMPR1_SMP_AN11(ADC_SAMPLING_RATE) | ADC_SMPR1_SMP_AN12(ADC_SAMPLING_RATE) | ADC_SMPR1_SMP_AN13(ADC_SAMPLING_RATE) | ADC_SMPR1_SMP_AN14(ADC_SAMPLING_RATE) | ADC_SMPR1_SMP_AN15(ADC_SAMPLING_RATE),
53#else 126#else
54# error "adcInitialized has not been implemented for this ARM microcontroller." 127 .cfgr = ADC_CFGR_CONT | ADC_RESOLUTION,
128 .smpr = {ADC_SMPR1_SMP_AN0(ADC_SAMPLING_RATE) | ADC_SMPR1_SMP_AN1(ADC_SAMPLING_RATE) | ADC_SMPR1_SMP_AN2(ADC_SAMPLING_RATE) | ADC_SMPR1_SMP_AN3(ADC_SAMPLING_RATE) | ADC_SMPR1_SMP_AN4(ADC_SAMPLING_RATE) | ADC_SMPR1_SMP_AN5(ADC_SAMPLING_RATE) | ADC_SMPR1_SMP_AN6(ADC_SAMPLING_RATE) | ADC_SMPR1_SMP_AN7(ADC_SAMPLING_RATE) | ADC_SMPR1_SMP_AN8(ADC_SAMPLING_RATE) | ADC_SMPR1_SMP_AN9(ADC_SAMPLING_RATE), ADC_SMPR2_SMP_AN10(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN11(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN12(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN13(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN14(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN15(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN16(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN17(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN18(ADC_SAMPLING_RATE)},
55#endif 129#endif
130};
56 131
57static ADCConversionGroup adcConversionGroup = { 132// clang-format off
58 ADC_CIRCULAR_BUFFER, 133__attribute__((weak)) adc_mux pinToMux(pin_t pin) {
59 (uint16_t)(ADC_NUM_CHANNELS), 134 switch (pin) {
60 NULL, // No end callback
61 NULL, // No error callback
62#if defined(STM32F0XX) 135#if defined(STM32F0XX)
63 ADC_CFGR1_CONT | ADC_RESOLUTION, 136 case A0: return TO_MUX( ADC_CHSELR_CHSEL0, 0 );
64 ADC_TR(0, 0).ADC_SAMPLING_RATE, 137 case A1: return TO_MUX( ADC_CHSELR_CHSEL1, 0 );
65 NULL, // Doesn't specify a default channel 138 case A2: return TO_MUX( ADC_CHSELR_CHSEL2, 0 );
139 case A3: return TO_MUX( ADC_CHSELR_CHSEL3, 0 );
140 case A4: return TO_MUX( ADC_CHSELR_CHSEL4, 0 );
141 case A5: return TO_MUX( ADC_CHSELR_CHSEL5, 0 );
142 case A6: return TO_MUX( ADC_CHSELR_CHSEL6, 0 );
143 case A7: return TO_MUX( ADC_CHSELR_CHSEL7, 0 );
144 case B0: return TO_MUX( ADC_CHSELR_CHSEL8, 0 );
145 case B1: return TO_MUX( ADC_CHSELR_CHSEL9, 0 );
146 case C0: return TO_MUX( ADC_CHSELR_CHSEL10, 0 );
147 case C1: return TO_MUX( ADC_CHSELR_CHSEL11, 0 );
148 case C2: return TO_MUX( ADC_CHSELR_CHSEL12, 0 );
149 case C3: return TO_MUX( ADC_CHSELR_CHSEL13, 0 );
150 case C4: return TO_MUX( ADC_CHSELR_CHSEL14, 0 );
151 case C5: return TO_MUX( ADC_CHSELR_CHSEL15, 0 );
66#elif defined(STM32F3XX) 152#elif defined(STM32F3XX)
67 ADC_CFGR_CONT | ADC_RESOLUTION, 153 case A0: return TO_MUX( ADC_CHANNEL_IN1, 0 );
68 ADC_TR(0, 4095), 154 case A1: return TO_MUX( ADC_CHANNEL_IN2, 0 );
69 { 155 case A2: return TO_MUX( ADC_CHANNEL_IN3, 0 );
70 ADC_SAMPLING_RATE, 156 case A3: return TO_MUX( ADC_CHANNEL_IN4, 0 );
71 ADC_SAMPLING_RATE, 157 case A4: return TO_MUX( ADC_CHANNEL_IN1, 1 );
72 }, 158 case A5: return TO_MUX( ADC_CHANNEL_IN2, 1 );
73 { 159 case A6: return TO_MUX( ADC_CHANNEL_IN3, 1 );
74 0, // Doesn't specify a default channel 160 case A7: return TO_MUX( ADC_CHANNEL_IN4, 1 );
75 0, 161 case B0: return TO_MUX( ADC_CHANNEL_IN12, 2 );
76 0, 162 case B1: return TO_MUX( ADC_CHANNEL_IN1, 2 );
77 0, 163 case B2: return TO_MUX( ADC_CHANNEL_IN12, 1 );
78 }, 164 case B12: return TO_MUX( ADC_CHANNEL_IN2, 3 );
165 case B13: return TO_MUX( ADC_CHANNEL_IN3, 3 );
166 case B14: return TO_MUX( ADC_CHANNEL_IN4, 3 );
167 case B15: return TO_MUX( ADC_CHANNEL_IN5, 3 );
168 case C0: return TO_MUX( ADC_CHANNEL_IN6, 0 ); // Can also be ADC2
169 case C1: return TO_MUX( ADC_CHANNEL_IN7, 0 ); // Can also be ADC2
170 case C2: return TO_MUX( ADC_CHANNEL_IN8, 0 ); // Can also be ADC2
171 case C3: return TO_MUX( ADC_CHANNEL_IN9, 0 ); // Can also be ADC2
172 case C4: return TO_MUX( ADC_CHANNEL_IN5, 1 );
173 case C5: return TO_MUX( ADC_CHANNEL_IN11, 1 );
174 case D8: return TO_MUX( ADC_CHANNEL_IN12, 3 );
175 case D9: return TO_MUX( ADC_CHANNEL_IN13, 3 );
176 case D10: return TO_MUX( ADC_CHANNEL_IN7, 2 ); // Can also be ADC4
177 case D11: return TO_MUX( ADC_CHANNEL_IN8, 2 ); // Can also be ADC4
178 case D12: return TO_MUX( ADC_CHANNEL_IN9, 2 ); // Can also be ADC4
179 case D13: return TO_MUX( ADC_CHANNEL_IN10, 2 ); // Can also be ADC4
180 case D14: return TO_MUX( ADC_CHANNEL_IN11, 2 ); // Can also be ADC4
181 case E7: return TO_MUX( ADC_CHANNEL_IN13, 2 );
182 case E8: return TO_MUX( ADC_CHANNEL_IN6, 2 ); // Can also be ADC4
183 case E9: return TO_MUX( ADC_CHANNEL_IN2, 2 );
184 case E10: return TO_MUX( ADC_CHANNEL_IN14, 2 );
185 case E11: return TO_MUX( ADC_CHANNEL_IN15, 2 );
186 case E12: return TO_MUX( ADC_CHANNEL_IN16, 2 );
187 case E13: return TO_MUX( ADC_CHANNEL_IN3, 2 );
188 case E14: return TO_MUX( ADC_CHANNEL_IN1, 3 );
189 case E15: return TO_MUX( ADC_CHANNEL_IN2, 3 );
190 case F2: return TO_MUX( ADC_CHANNEL_IN10, 0 ); // Can also be ADC2
191 case F4: return TO_MUX( ADC_CHANNEL_IN5, 0 );
192#elif defined(STM32F4XX) // TODO: add all pins
193 case A0: return TO_MUX( ADC_CHANNEL_IN0, 0 );
194 //case A1: return TO_MUX( ADC_CHANNEL_IN1, 0 );
195#elif defined(STM32F1XX) // TODO: add all pins
196 case A0: return TO_MUX( ADC_CHANNEL_IN0, 0 );
79#endif 197#endif
80}; 198 }
81 199
82static inline ADCDriver* intToADCDriver(uint8_t adcInt) { 200 // return an adc that would never be used so intToADCDriver will bail out
83 ADCDriver* target; 201 return TO_MUX(0, 0xFF);
202}
203// clang-format on
84 204
205static inline ADCDriver* intToADCDriver(uint8_t adcInt) {
85 switch (adcInt) { 206 switch (adcInt) {
86 // clang-format off
87#if STM32_ADC_USE_ADC1 207#if STM32_ADC_USE_ADC1
88 case 0: target = &ADCD1; break; 208 case 0:
209 return &ADCD1;
89#endif 210#endif
90#if STM32_ADC_USE_ADC2 211#if STM32_ADC_USE_ADC2
91 case 1: target = &ADCD2; break; 212 case 1:
213 return &ADCD2;
92#endif 214#endif
93#if STM32_ADC_USE_ADC3 215#if STM32_ADC_USE_ADC3
94 case 2: target = &ADCD3; break; 216 case 2:
217 return &ADCD3;
95#endif 218#endif
96#if STM32_ADC_USE_ADC4 219#if STM32_ADC_USE_ADC4
97 case 3: target = &ADCD4; break; 220 case 3:
221 return &ADCD4;
98#endif 222#endif
99 default: target = NULL; break;
100 // clang-format on
101 } 223 }
102 224
103 return target; 225 return NULL;
104} 226}
105 227
106static inline void manageAdcInitializationDriver(uint8_t adc, ADCDriver* adcDriver) { 228static inline void manageAdcInitializationDriver(uint8_t adc, ADCDriver* adcDriver) {
@@ -110,98 +232,45 @@ static inline void manageAdcInitializationDriver(uint8_t adc, ADCDriver* adcDriv
110 } 232 }
111} 233}
112 234
113static inline void manageAdcInitialization(uint8_t adc) { manageAdcInitializationDriver(adc, intToADCDriver(adc)); } 235int16_t analogReadPin(pin_t pin) {
236 palSetLineMode(pin, PAL_MODE_INPUT_ANALOG);
114 237
115pin_and_adc pinToMux(pin_t pin) { 238 return adc_read(pinToMux(pin));
116 switch (pin) {
117 // clang-format off
118#if defined(STM32F0XX)
119 case A0: return (pin_and_adc){ ADC_CHANNEL_IN0, 0 };
120 case A1: return (pin_and_adc){ ADC_CHANNEL_IN1, 0 };
121 case A2: return (pin_and_adc){ ADC_CHANNEL_IN2, 0 };
122 case A3: return (pin_and_adc){ ADC_CHANNEL_IN3, 0 };
123 case A4: return (pin_and_adc){ ADC_CHANNEL_IN4, 0 };
124 case A5: return (pin_and_adc){ ADC_CHANNEL_IN5, 0 };
125 case A6: return (pin_and_adc){ ADC_CHANNEL_IN6, 0 };
126 case A7: return (pin_and_adc){ ADC_CHANNEL_IN7, 0 };
127 case B0: return (pin_and_adc){ ADC_CHANNEL_IN8, 0 };
128 case B1: return (pin_and_adc){ ADC_CHANNEL_IN9, 0 };
129 case C0: return (pin_and_adc){ ADC_CHANNEL_IN10, 0 };
130 case C1: return (pin_and_adc){ ADC_CHANNEL_IN11, 0 };
131 case C2: return (pin_and_adc){ ADC_CHANNEL_IN12, 0 };
132 case C3: return (pin_and_adc){ ADC_CHANNEL_IN13, 0 };
133 case C4: return (pin_and_adc){ ADC_CHANNEL_IN14, 0 };
134 case C5: return (pin_and_adc){ ADC_CHANNEL_IN15, 0 };
135#elif defined(STM32F3XX)
136 case A0: return (pin_and_adc){ ADC_CHANNEL_IN1, 0 };
137 case A1: return (pin_and_adc){ ADC_CHANNEL_IN2, 0 };
138 case A2: return (pin_and_adc){ ADC_CHANNEL_IN3, 0 };
139 case A3: return (pin_and_adc){ ADC_CHANNEL_IN4, 0 };
140 case A4: return (pin_and_adc){ ADC_CHANNEL_IN1, 1 };
141 case A5: return (pin_and_adc){ ADC_CHANNEL_IN2, 1 };
142 case A6: return (pin_and_adc){ ADC_CHANNEL_IN3, 1 };
143 case A7: return (pin_and_adc){ ADC_CHANNEL_IN4, 1 };
144 case B0: return (pin_and_adc){ ADC_CHANNEL_IN12, 2 };
145 case B1: return (pin_and_adc){ ADC_CHANNEL_IN1, 2 };
146 case B2: return (pin_and_adc){ ADC_CHANNEL_IN12, 1 };
147 case B12: return (pin_and_adc){ ADC_CHANNEL_IN2, 3 };
148 case B13: return (pin_and_adc){ ADC_CHANNEL_IN3, 3 };
149 case B14: return (pin_and_adc){ ADC_CHANNEL_IN4, 3 };
150 case B15: return (pin_and_adc){ ADC_CHANNEL_IN5, 3 };
151 case C0: return (pin_and_adc){ ADC_CHANNEL_IN6, 0 }; // Can also be ADC2
152 case C1: return (pin_and_adc){ ADC_CHANNEL_IN7, 0 }; // Can also be ADC2
153 case C2: return (pin_and_adc){ ADC_CHANNEL_IN8, 0 }; // Can also be ADC2
154 case C3: return (pin_and_adc){ ADC_CHANNEL_IN9, 0 }; // Can also be ADC2
155 case C4: return (pin_and_adc){ ADC_CHANNEL_IN5, 1 };
156 case C5: return (pin_and_adc){ ADC_CHANNEL_IN11, 1 };
157 case D8: return (pin_and_adc){ ADC_CHANNEL_IN12, 3 };
158 case D9: return (pin_and_adc){ ADC_CHANNEL_IN13, 3 };
159 case D10: return (pin_and_adc){ ADC_CHANNEL_IN7, 2 }; // Can also be ADC4
160 case D11: return (pin_and_adc){ ADC_CHANNEL_IN8, 2 }; // Can also be ADC4
161 case D12: return (pin_and_adc){ ADC_CHANNEL_IN9, 2 }; // Can also be ADC4
162 case D13: return (pin_and_adc){ ADC_CHANNEL_IN10, 2 }; // Can also be ADC4
163 case D14: return (pin_and_adc){ ADC_CHANNEL_IN11, 2 }; // Can also be ADC4
164 case E7: return (pin_and_adc){ ADC_CHANNEL_IN13, 2 };
165 case E8: return (pin_and_adc){ ADC_CHANNEL_IN6, 2 }; // Can also be ADC4
166 case E9: return (pin_and_adc){ ADC_CHANNEL_IN2, 2 };
167 case E10: return (pin_and_adc){ ADC_CHANNEL_IN14, 2 };
168 case E11: return (pin_and_adc){ ADC_CHANNEL_IN15, 2 };
169 case E12: return (pin_and_adc){ ADC_CHANNEL_IN16, 2 };
170 case E13: return (pin_and_adc){ ADC_CHANNEL_IN3, 2 };
171 case E14: return (pin_and_adc){ ADC_CHANNEL_IN1, 3 };
172 case E15: return (pin_and_adc){ ADC_CHANNEL_IN2, 3 };
173 case F2: return (pin_and_adc){ ADC_CHANNEL_IN10, 0 }; // Can also be ADC2
174 case F4: return (pin_and_adc){ ADC_CHANNEL_IN5, 0 };
175#else
176#error "An ADC pin-to-mux configuration has not been specified for this microcontroller."
177#endif
178 default: return (pin_and_adc){ 0, 0 };
179 // clang-format on
180 }
181} 239}
182 240
183adcsample_t analogReadPin(pin_t pin) { return adc_read(pinToMux(pin)); } 241int16_t analogReadPinAdc(pin_t pin, uint8_t adc) {
242 palSetLineMode(pin, PAL_MODE_INPUT_ANALOG);
184 243
185adcsample_t analogReadPinAdc(pin_t pin, uint8_t adc) { 244 adc_mux target = pinToMux(pin);
186 pin_and_adc target = pinToMux(pin); 245 target.adc = adc;
187 target.adc = adc;
188 return adc_read(target); 246 return adc_read(target);
189} 247}
190 248
191adcsample_t adc_read(pin_and_adc mux) { 249int16_t adc_read(adc_mux mux) {
192#if defined(STM32F0XX) 250#if defined(USE_ADCV1)
193 adcConversionGroup.sqr = ADC_CHSELR_CHSEL1; 251 // TODO: fix previous assumption of only 1 input...
194#elif defined(STM32F3XX) 252 adcConversionGroup.chselr = 1 << mux.input; /*no macro to convert N to ADC_CHSELR_CHSEL1*/
195 adcConversionGroup.sqr[0] = ADC_SQR1_SQ1_N(mux.pin); 253#elif defined(USE_ADCV2)
254 adcConversionGroup.sqr3 = ADC_SQR3_SQ1_N(mux.input);
196#else 255#else
197# error "adc_read has not been updated to support this ARM microcontroller." 256 adcConversionGroup.sqr[0] = ADC_SQR1_SQ1_N(mux.input);
198#endif 257#endif
199 258
200 ADCDriver* targetDriver = intToADCDriver(mux.adc); 259 ADCDriver* targetDriver = intToADCDriver(mux.adc);
201 manageAdcInitializationDriver(mux.adc, targetDriver); 260 if (!targetDriver) {
261 return 0;
262 }
202 263
203 adcConvert(targetDriver, &adcConversionGroup, &sampleBuffer[0], ADC_BUFFER_DEPTH); 264 manageAdcInitializationDriver(mux.adc, targetDriver);
204 adcsample_t* result = sampleBuffer; 265 if (adcConvert(targetDriver, &adcConversionGroup, &sampleBuffer[0], ADC_BUFFER_DEPTH) != MSG_OK) {
266 return 0;
267 }
205 268
206 return *result; 269#ifdef USE_ADCV2
270 // fake 12-bit -> N-bit scale
271 return (*sampleBuffer) >> (12 - ADC_RESOLUTION);
272#else
273 // already handled as part of adcConvert
274 return *sampleBuffer;
275#endif
207} 276}
diff --git a/drivers/arm/analog.h b/drivers/arm/analog.h
index ab592ada3..2818e9dcb 100644
--- a/drivers/arm/analog.h
+++ b/drivers/arm/analog.h
@@ -16,42 +16,26 @@
16 16
17#pragma once 17#pragma once
18 18
19#include <stdint.h>
19#include "quantum.h" 20#include "quantum.h"
20#include "ch.h"
21#include <hal.h>
22 21
23#if !defined(STM32F0XX) && !defined(STM32F3XX) 22#ifdef __cplusplus
24# error "Only STM23F0 and STM32F3 devices have ADC support in QMK at this time." 23extern "C" {
25#endif
26
27#if !HAL_USE_ADC
28# error "You need to set HAL_USE_ADC to TRUE in your halconf.h to use the ADC."
29#endif
30
31#if !STM32_ADC_USE_ADC1 && !STM32_ADC_USE_ADC2 && !STM32_ADC_USE_ADC3 && !STM32_ADC_USE_ADC4
32# error "You need to set one of the 'STM32_ADC_USE_ADCx' settings to TRUE in your mcuconf.h to use the ADC."
33#endif
34
35#if STM32_ADC_DUAL_MODE
36# error "STM32 ADC Dual Mode is not supported at this time."
37#endif
38
39#if STM32_ADCV3_OVERSAMPLING
40# error "STM32 ADCV3 Oversampling is not supported at this time."
41#endif 24#endif
42 25
43typedef struct { 26typedef struct {
44 pin_t pin; 27 uint16_t input;
45 uint8_t adc; 28 uint8_t adc;
46} pin_and_adc; 29} adc_mux;
47#define PIN_AND_ADC(p, a) \ 30#define TO_MUX(i, a) \
48 (pin_and_adc) { p, a } 31 (adc_mux) { i, a }
49 32
50// analogReference has been left un-defined for ARM devices. 33int16_t analogReadPin(pin_t pin);
51// void analogReference(uint8_t mode); 34int16_t analogReadPinAdc(pin_t pin, uint8_t adc);
35adc_mux pinToMux(pin_t pin);
52 36
53adcsample_t analogReadPin(pin_t pin); 37int16_t adc_read(adc_mux mux);
54adcsample_t analogReadPinAdc(pin_t pin, uint8_t adc);
55pin_and_adc pinToMux(pin_t pin);
56 38
57adcsample_t adc_read(pin_and_adc mux); 39#ifdef __cplusplus
40}
41#endif
diff --git a/keyboards/handwired/onekey/keymaps/adc/config.h b/keyboards/handwired/onekey/keymaps/adc/config.h
new file mode 100644
index 000000000..6f70f09be
--- /dev/null
+++ b/keyboards/handwired/onekey/keymaps/adc/config.h
@@ -0,0 +1 @@
#pragma once
diff --git a/keyboards/handwired/onekey/keymaps/adc/keymap.c b/keyboards/handwired/onekey/keymaps/adc/keymap.c
new file mode 100644
index 000000000..c5294bbc3
--- /dev/null
+++ b/keyboards/handwired/onekey/keymaps/adc/keymap.c
@@ -0,0 +1,38 @@
1#include QMK_KEYBOARD_H
2#include "analog.h"
3#include <stdio.h>
4
5#ifndef ADC_PIN
6# define ADC_PIN A0
7#endif
8
9enum custom_keycodes {
10 ADC_SAMPLE = SAFE_RANGE,
11};
12
13const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
14 LAYOUT(ADC_SAMPLE) //
15};
16
17bool process_record_user(uint16_t keycode, keyrecord_t *record) {
18 switch (keycode) {
19 case ADC_SAMPLE:
20 if (record->event.pressed) {
21 int16_t val = analogReadPin(ADC_PIN);
22
23 char buffer [50];
24 sprintf(buffer, "ADC:%u\n", val);
25#ifdef CONSOLE_ENABLE
26 printf(buffer);
27#else
28 SEND_STRING(buffer);
29#endif
30 }
31 break;
32 }
33 return false;
34};
35
36// adc_mux pinToMux(pin_t pin) {
37// return TO_MUX( ADC_CHANNEL_IN1, 0 );
38// };
diff --git a/keyboards/handwired/onekey/keymaps/adc/rules.mk b/keyboards/handwired/onekey/keymaps/adc/rules.mk
new file mode 100644
index 000000000..a691d5488
--- /dev/null
+++ b/keyboards/handwired/onekey/keymaps/adc/rules.mk
@@ -0,0 +1,3 @@
1SRC += analog.c
2
3CONSOLE_ENABLE = yes