qmk-firmware/docs/adc_driver.md
Sergey Vlasov 65c9752762
Update ADC driver for STM32F1xx, STM32F3xx, STM32F4xx (#12403)
* Fix default ADC_RESOLUTION for ADCv3 (and ADCv4)

Recent ChibiOS update removed ADC_CFGR1_RES_10BIT from the ADCv3 headers
(that macro should not have been there, because ADCv3 has CFGR instead of
CFGR1).  Fix the default value for ADC_RESOLUTION to use ADC_CFGR_RES_10BITS
if it is defined (that name is used for ADCv3 and ADCv4).

* Update ADC docs to match the actually used resolution

ADC driver for ChibiOS actually uses the 10-bit resolution by default
(probably to match AVR); fix the documentation accordingly.  Also add
both ADC_CFGR_RES_10BITS and ADC_CFGR1_RES_10BIT constants (these names
differ according to the ADC implementation in the particular MCU).

* Fix pinToMux() for B12 and B13 on STM32F3xx

Testing on STM32F303CCT6 revealed that the ADC mux values for B12 and
B13 pins were wrong.

* Add support for all possible analog pins on STM32F1xx

Added ADC mux values for pins A0...A7, B0, B1, C0...C5 on STM32F1xx
(they are the same at least for STM32F103x8 and larger F103 devices, and
also F102, F105, F107 families).  Actually tested on STM32F103C8T6
(therefore pins C0...C5 were not tested).

Pins F6...F10, which are present on STM32F103x[C-G] in 144-pin packages,
cannot be supported at the moment, because those pins are connected only
to ADC3, but the ChibiOS ADC driver for STM32F1xx supports only ADC1.

* Add support for all possible analog pins on STM32F4xx

Added ADC mux values for pins A0...A7, B0, B1, C0...C5 and optionally
F3...F10 (if STM32_ADC_USE_ADC3 is enabled).  These mux values are
apparently the same for all F4xx devices, except some smaller devices may
not have ADC3.

Actually tested on STM32F401CCU6, STM32F401CEU6, STM32F411CEU6 (using
various WeAct “Blackpill” boards); only pins A0...A7, B0, B1 were tested.

Pins F3...F10 are inside `#if STM32_ADC_USE_ADC3` because some devices
which don't have ADC3 also don't have the GPIOF port, therefore the code
which refers to Fx pins does not compile.

* Fix STM32F3xx ADC mux table in documentation

The ADC driver documentation had some errors in the mux table for STM32F3xx.
Fix this table to match the datasheet and the actual code (mux settings for
B12 and B13 were also tested on a real STM32F303CCT6 chip).

* Add STM32F1xx ADC pins to the documentation

* Add STM32F4xx ADC pins to the documentation
2021-04-25 11:15:37 +10:00

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:

SRC += analog.c

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

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 F6F10, 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 F4F10 cannot be used as ADC inputs on devices which do not have ADC3. Check the device datasheet to confirm which pin functions are supported.

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.