12 KiB
ADC Driver
QMK 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.
This 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
#defines if you need more precision.
Usage
To use this driver, add the following to your
rules.mk:
ANALOG_DRIVER_REQUIRED = yes
Then place this include at the top of your code:
#include "analog.h"Channels
AVR
| Channel | AT90USB64/128 | ATmega16/32U4 | ATmega32A | ATmega328/P |
|---|---|---|---|---|
| 0 | F0 |
F0 |
A0 |
C0 |
| 1 | F1 |
F1 |
A1 |
C1 |
| 2 | F2 |
A2 |
C2 |
|
| 3 | F3 |
A3 |
C3 |
|
| 4 | F4 |
F4 |
A4 |
C4 |
| 5 | F5 |
F5 |
A5 |
C5 |
| 6 | F6 |
F6 |
A6 |
* |
| 7 | F7 |
F7 |
A7 |
* |
| 8 | D4 |
|||
| 9 | D6 |
|||
| 10 | D7 |
|||
| 11 | B4 |
|||
| 12 | B5 |
|||
| 13 | B6 |
* The ATmega328/P possesses two extra ADC channels; however,
they are not present on the DIP pinout, and are not shared with GPIO
pins. You can use adc_read() directly to gain access to
these.
ARM
STM32
Note that some of these pins are doubled-up on ADCs with the same channel. This is because the pins can be used for either ADC.
Also note that the F0 and F3 use different numbering schemes. The F0
has a single ADC and the channels are 0-indexed, whereas the F3 has 4
ADCs and the channels are 1-indexed. This is because the F0 uses the
ADCv1 implementation of the ADC, whereas the F3 uses the
ADCv3 implementation.
| ADC | Channel | STM32F0xx | STM32F1xx | STM32F3xx | STM32F4xx |
|---|---|---|---|---|---|
| 1 | 0 | A0 |
A0 |
A0 |
|
| 1 | 1 | A1 |
A1 |
A0 |
A1 |
| 1 | 2 | A2 |
A2 |
A1 |
A2 |
| 1 | 3 | A3 |
A3 |
A2 |
A3 |
| 1 | 4 | A4 |
A4 |
A3 |
A4 |
| 1 | 5 | A5 |
A5 |
F4 |
A5 |
| 1 | 6 | A6 |
A6 |
C0 |
A6 |
| 1 | 7 | A7 |
A7 |
C1 |
A7 |
| 1 | 8 | B0 |
B0 |
C2 |
B0 |
| 1 | 9 | B1 |
B1 |
C3 |
B1 |
| 1 | 10 | C0 |
C0 |
F2 |
C0 |
| 1 | 11 | C1 |
C1 |
C1 |
|
| 1 | 12 | C2 |
C2 |
C2 |
|
| 1 | 13 | C3 |
C3 |
C3 |
|
| 1 | 14 | C4 |
C4 |
C4 |
|
| 1 | 15 | C5 |
C5 |
C5 |
|
| 1 | 16 | ||||
| 2 | 0 | A0¹ |
A0² |
||
| 2 | 1 | A1¹ |
A4 |
A1² |
|
| 2 | 2 | A2¹ |
A5 |
A2² |
|
| 2 | 3 | A3¹ |
A6 |
A3² |
|
| 2 | 4 | A4¹ |
A7 |
A4² |
|
| 2 | 5 | A5¹ |
C4 |
A5² |
|
| 2 | 6 | A6¹ |
C0 |
A6² |
|
| 2 | 7 | A7¹ |
C1 |
A7² |
|
| 2 | 8 | B0¹ |
C2 |
B0² |
|
| 2 | 9 | B1¹ |
C3 |
B1² |
|
| 2 | 10 | C0¹ |
F2 |
C0² |
|
| 2 | 11 | C1¹ |
C5 |
C1² |
|
| 2 | 12 | C2¹ |
B2 |
C2² |
|
| 2 | 13 | C3¹ |
C3² |
||
| 2 | 14 | C4¹ |
C4² |
||
| 2 | 15 | C5¹ |
C5² |
||
| 2 | 16 | ||||
| 3 | 0 | A0¹ |
A0² |
||
| 3 | 1 | A1¹ |
B1 |
A1² |
|
| 3 | 2 | A2¹ |
E9 |
A2² |
|
| 3 | 3 | A3¹ |
E13 |
A3² |
|
| 3 | 4 | F6¹ |
F6² |
||
| 3 | 5 | F7¹ |
B13 |
F7² |
|
| 3 | 6 | F8¹ |
E8 |
F8² |
|
| 3 | 7 | F9¹ |
D10 |
F9² |
|
| 3 | 8 | F10¹ |
D11 |
F10² |
|
| 3 | 9 | D12 |
F3² |
||
| 3 | 10 | C0¹ |
D13 |
C0² |
|
| 3 | 11 | C1¹ |
D14 |
C1² |
|
| 3 | 12 | C2¹ |
B0 |
C2² |
|
| 3 | 13 | C3¹ |
E7 |
C3² |
|
| 3 | 14 | E10 |
F4² |
||
| 3 | 15 | E11 |
F5² |
||
| 3 | 16 | E12 |
|||
| 4 | 1 | E14 |
|||
| 4 | 2 | E15 |
|||
| 4 | 3 | B12 |
|||
| 4 | 4 | B14 |
|||
| 4 | 5 | B15 |
|||
| 4 | 6 | E8 |
|||
| 4 | 7 | D10 |
|||
| 4 | 8 | D11 |
|||
| 4 | 9 | D12 |
|||
| 4 | 10 | D13 |
|||
| 4 | 11 | D14 |
|||
| 4 | 12 | D8 |
|||
| 4 | 13 | D9 |
|||
| 4 | 14 | ||||
| 4 | 15 | ||||
| 4 | 16 |
¹ As of ChibiOS 20.3.4, the ADC driver for STM32F1xx devices
supports only ADC1, therefore any configurations involving ADC2 or ADC3
cannot actually be used. In particular, pins
F6…F10, which are present at least on some
STM32F103x[C-G] devices, cannot be used as ADC inputs because of this
driver limitation.
² Not all STM32F4xx devices have ADC2 and/or ADC3, therefore
some configurations shown in this table may be unavailable; in
particular, pins F4…F10 cannot be used as ADC
inputs on devices which do not have ADC3. Check the device datasheet to
confirm which pin functions are supported.
RP2040
RP2040 has only a single ADC (ADCD1 in ChibiOS); in the
QMK API the index for that ADC is 0.
| Channel | Pin |
|---|---|
| 0 | GP26 |
| 1 | GP27 |
| 2 | GP28 |
| 3 | GP29 |
| 4 | Temperature sensor* |
* The temperature sensor is disabled by default and needs to be
enabled by the RP2040-specific function:
adcRPEnableTS(&ADCD1). The ADC must be initialized
before calling that function; an easy way to ensure that is to perform a
dummy conversion.
Functions
AVR
| Function | Description |
|---|---|
analogReference(mode) |
Sets the analog voltage reference source. Must be one of
ADC_REF_EXTERNAL, ADC_REF_POWER or
ADC_REF_INTERNAL. |
analogReadPin(pin) |
Reads the value from the specified pin, eg. F6 for ADC6
on the ATmega32U4. |
pinToMux(pin) |
Translates a given pin to a mux value. If an unsupported pin is given, returns the mux value for “0V (GND)”. |
adc_read(mux) |
Reads the value from the ADC according to the specified mux. See your MCU’s datasheet for more information. |
ARM
| Function | Description |
|---|---|
analogReadPin(pin) |
Reads the value from the specified pin, eg. A0 for
channel 0 on the STM32F0 and ADC1 channel 1 on the STM32F3. Note that if
a pin can be used for multiple ADCs, it will pick the lower numbered ADC
for this function. eg. C0 will be channel 6 of ADC 1 when
it could be used for ADC 2 as well. |
analogReadPinAdc(pin, adc) |
Reads the value from the specified pin and ADC, eg.
C0, 1 will read from channel 6, ADC 2 instead of ADC 1.
Note that the ADCs are 0-indexed for this function. |
pinToMux(pin) |
Translates a given pin to a channel and ADC combination. If an unsupported pin is given, returns the mux value for “0V (GND)”. |
adc_read(mux) |
Reads the value from the ADC according to the specified pin and ADC combination. See your MCU’s datasheet for more information. |
Configuration
ARM
The ARM implementation of the ADC has a few additional options that
you can override in your own keyboards and keymaps to change how it
operates. Please consult the corresponding hal_adc_lld.h in
ChibiOS for your specific microcontroller for further documentation on
your available options.
#define |
Type | Default | Description |
|---|---|---|---|
ADC_CIRCULAR_BUFFER |
bool |
false |
If true, then the implementation will use a circular
buffer. |
ADC_NUM_CHANNELS |
int |
1 |
Sets the number of channels that will be scanned as part of an ADC
operation. The current implementation only supports 1. |
ADC_BUFFER_DEPTH |
int |
2 |
Sets the depth of each result. Since we are only getting a 10-bit result by default, we set this to 2 bytes so we can contain our one value. This could be set to 1 if you opt for an 8-bit or lower result. |
ADC_SAMPLING_RATE |
int |
ADC_SMPR_SMP_1P5 |
Sets the sampling rate of the ADC. By default, it is set to the fastest setting. |
ADC_RESOLUTION |
int |
ADC_CFGR1_RES_10BIT or
ADC_CFGR_RES_10BITS |
The resolution of your result. We choose 10 bit by default, but you can opt for 12, 10, 8, or 6 bit. Different MCUs use slightly different names for the resolution constants. |