summaryrefslogtreecommitdiff
path: root/docs/drivers
diff options
context:
space:
mode:
authorRyan <fauxpark@gmail.com>2024-06-02 12:42:24 +1000
committerGitHub <noreply@github.com>2024-06-02 12:42:24 +1000
commit78a0adfbb4d2c4e12f93f2a62ded0020d406243e (patch)
treee6e123b36569559233025add654580e090dc0154 /docs/drivers
parentfa6d23235bf429446250cd5212e209d5fbfdbac2 (diff)
[docs] Organize driver & feature docs into subfolders (#23848)
Co-authored-by: Nick Brassel <nick@tzarc.org>
Diffstat (limited to 'docs/drivers')
-rw-r--r--docs/drivers/adc.md173
-rw-r--r--docs/drivers/apa102.md49
-rw-r--r--docs/drivers/audio.md239
-rw-r--r--docs/drivers/eeprom.md180
-rw-r--r--docs/drivers/flash.md26
-rw-r--r--docs/drivers/gpio.md44
-rw-r--r--docs/drivers/i2c.md290
-rw-r--r--docs/drivers/serial.md397
-rw-r--r--docs/drivers/spi.md167
-rw-r--r--docs/drivers/uart.md122
-rw-r--r--docs/drivers/ws2812.md253
11 files changed, 1940 insertions, 0 deletions
diff --git a/docs/drivers/adc.md b/docs/drivers/adc.md
new file mode 100644
index 0000000000..d89068c2ae
--- /dev/null
+++ b/docs/drivers/adc.md
@@ -0,0 +1,173 @@
1# ADC Driver
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](../features/encoders).
4
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
7## Usage
8
9To use this driver, add the following to your `rules.mk`:
10
11```make
12ANALOG_DRIVER_REQUIRED = yes
13```
14
15Then place this include at the top of your code:
16
17```c
18#include "analog.h"
19```
20
21## Channels
22
23### AVR
24
25|Channel|AT90USB64/128|ATmega16/32U4|ATmega32A|ATmega328/P|
26|-------|-------------|-------------|---------|----------|
27|0 |`F0` |`F0` |`A0` |`C0` |
28|1 |`F1` |`F1` |`A1` |`C1` |
29|2 |`F2` | |`A2` |`C2` |
30|3 |`F3` | |`A3` |`C3` |
31|4 |`F4` |`F4` |`A4` |`C4` |
32|5 |`F5` |`F5` |`A5` |`C5` |
33|6 |`F6` |`F6` |`A6` |* |
34|7 |`F7` |`F7` |`A7` |* |
35|8 | |`D4` | | |
36|9 | |`D6` | | |
37|10 | |`D7` | | |
38|11 | |`B4` | | |
39|12 | |`B5` | | |
40|13 | |`B6` | | |
41
42<sup>\* 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.</sup>
43
44### ARM
45
46#### STM32
47
48Note 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.
49
50Also 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.
51
52|ADC|Channel|STM32F0xx|STM32F1xx|STM32F3xx|STM32F4xx|
53|---|-------|---------|---------|---------|---------|
54|1 |0 |`A0` |`A0` | |`A0` |
55|1 |1 |`A1` |`A1` |`A0` |`A1` |
56|1 |2 |`A2` |`A2` |`A1` |`A2` |
57|1 |3 |`A3` |`A3` |`A2` |`A3` |
58|1 |4 |`A4` |`A4` |`A3` |`A4` |
59|1 |5 |`A5` |`A5` |`F4` |`A5` |
60|1 |6 |`A6` |`A6` |`C0` |`A6` |
61|1 |7 |`A7` |`A7` |`C1` |`A7` |
62|1 |8 |`B0` |`B0` |`C2` |`B0` |
63|1 |9 |`B1` |`B1` |`C3` |`B1` |
64|1 |10 |`C0` |`C0` |`F2` |`C0` |
65|1 |11 |`C1` |`C1` | |`C1` |
66|1 |12 |`C2` |`C2` | |`C2` |
67|1 |13 |`C3` |`C3` | |`C3` |
68|1 |14 |`C4` |`C4` | |`C4` |
69|1 |15 |`C5` |`C5` | |`C5` |
70|1 |16 | | | | |
71|2 |0 | |`A0`¹ | |`A0`² |
72|2 |1 | |`A1`¹ |`A4` |`A1`² |
73|2 |2 | |`A2`¹ |`A5` |`A2`² |
74|2 |3 | |`A3`¹ |`A6` |`A3`² |
75|2 |4 | |`A4`¹ |`A7` |`A4`² |
76|2 |5 | |`A5`¹ |`C4` |`A5`² |
77|2 |6 | |`A6`¹ |`C0` |`A6`² |
78|2 |7 | |`A7`¹ |`C1` |`A7`² |
79|2 |8 | |`B0`¹ |`C2` |`B0`² |
80|2 |9 | |`B1`¹ |`C3` |`B1`² |
81|2 |10 | |`C0`¹ |`F2` |`C0`² |
82|2 |11 | |`C1`¹ |`C5` |`C1`² |
83|2 |12 | |`C2`¹ |`B2` |`C2`² |
84|2 |13 | |`C3`¹ | |`C3`² |
85|2 |14 | |`C4`¹ | |`C4`² |
86|2 |15 | |`C5`¹ | |`C5`² |
87|2 |16 | | | | |
88|3 |0 | |`A0`¹ | |`A0`² |
89|3 |1 | |`A1`¹ |`B1` |`A1`² |
90|3 |2 | |`A2`¹ |`E9` |`A2`² |
91|3 |3 | |`A3`¹ |`E13` |`A3`² |
92|3 |4 | |`F6`¹ | |`F6`² |
93|3 |5 | |`F7`¹ |`B13` |`F7`² |
94|3 |6 | |`F8`¹ |`E8` |`F8`² |
95|3 |7 | |`F9`¹ |`D10` |`F9`² |
96|3 |8 | |`F10`¹ |`D11` |`F10`² |
97|3 |9 | | |`D12` |`F3`² |
98|3 |10 | |`C0`¹ |`D13` |`C0`² |
99|3 |11 | |`C1`¹ |`D14` |`C1`² |
100|3 |12 | |`C2`¹ |`B0` |`C2`² |
101|3 |13 | |`C3`¹ |`E7` |`C3`² |
102|3 |14 | | |`E10` |`F4`² |
103|3 |15 | | |`E11` |`F5`² |
104|3 |16 | | |`E12` | |
105|4 |1 | | |`E14` | |
106|4 |2 | | |`E15` | |
107|4 |3 | | |`B12` | |
108|4 |4 | | |`B14` | |
109|4 |5 | | |`B15` | |
110|4 |6 | | |`E8` | |
111|4 |7 | | |`D10` | |
112|4 |8 | | |`D11` | |
113|4 |9 | | |`D12` | |
114|4 |10 | | |`D13` | |
115|4 |11 | | |`D14` | |
116|4 |12 | | |`D8` | |
117|4 |13 | | |`D9` | |
118|4 |14 | | | | |
119|4 |15 | | | | |
120|4 |16 | | | | |
121
122<sup>¹ 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.</sup>
123
124<sup>² 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.</sup>
125
126#### RP2040
127
128RP2040 has only a single ADC (`ADCD1` in ChibiOS); in the QMK API the index for that ADC is 0.
129
130|Channel|Pin |
131|-------|-------------------|
132|0 |`GP26` |
133|1 |`GP27` |
134|2 |`GP28` |
135|3 |`GP29` |
136|4 |Temperature sensor*|
137
138
139<sup>* 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.</sup>
140
141## Functions
142
143### AVR
144
145|Function |Description |
146|----------------------------|-------------------------------------------------------------------------------------------------------------------|
147|`analogReference(mode)` |Sets the analog voltage reference source. Must be one of `ADC_REF_EXTERNAL`, `ADC_REF_POWER` or `ADC_REF_INTERNAL`.|
148|`analogReadPin(pin)` |Reads the value from the specified pin, eg. `F6` for ADC6 on the ATmega32U4. |
149|`pinToMux(pin)` |Translates a given pin to a mux value. If an unsupported pin is given, returns the mux value for "0V (GND)". |
150|`adc_read(mux)` |Reads the value from the ADC according to the specified mux. See your MCU's datasheet for more information. |
151
152### ARM
153
154|Function |Description |
155|----------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
156|`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.|
157|`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. |
158|`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)". |
159|`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. |
160
161## Configuration
162
163## ARM
164
165The 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.
166
167|`#define` |Type |Default |Description |
168|---------------------|------|----------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
169|`ADC_CIRCULAR_BUFFER`|`bool`|`false` |If `true`, then the implementation will use a circular buffer. |
170|`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`. |
171|`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.|
172|`ADC_SAMPLING_RATE` |`int` |`ADC_SMPR_SMP_1P5` |Sets the sampling rate of the ADC. By default, it is set to the fastest setting. |
173|`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. |
diff --git a/docs/drivers/apa102.md b/docs/drivers/apa102.md
new file mode 100644
index 0000000000..88868a73b5
--- /dev/null
+++ b/docs/drivers/apa102.md
@@ -0,0 +1,49 @@
1# APA102 Driver {#apa102-driver}
2
3This driver provides support for APA102 addressable RGB LEDs. They are similar to the [WS2812](ws2812) LEDs, but have increased data and refresh rates.
4
5## Usage {#usage}
6
7In most cases, the APA102 driver code is automatically included if you are using either the [RGBLight](../features/rgblight) or [RGB Matrix](../features/rgb_matrix) feature with the `apa102` driver set, and you would use those APIs instead.
8
9However, if you need to use the driver standalone, add the following to your `rules.mk`:
10
11```make
12APA102_DRIVER_REQUIRED = yes
13```
14
15You can then call the APA102 API by including `apa102.h` in your code.
16
17## Basic Configuration {#basic-configuration}
18
19Add the following to your `config.h`:
20
21|Define |Default |Description |
22|---------------------------|-------------|------------------------------------------------------------------|
23|`APA102_DI_PIN` |*Not defined*|The GPIO pin connected to the DI pin of the first LED in the chain|
24|`APA102_CI_PIN` |*Not defined*|The GPIO pin connected to the CI pin of the first LED in the chain|
25|`APA102_DEFAULT_BRIGHTNESS`|`31` |The default global brightness level of the LEDs, from 0 to 31 |
26
27## API {#api}
28
29### `void apa102_setleds(rgb_led_t *start_led, uint16_t num_leds)`
30
31Send RGB data to the APA102 LED chain.
32
33#### Arguments {#api-apa102-setleds-arguments}
34
35 - `rgb_led_t *start_led`
36 A pointer to the LED array.
37 - `uint16_t num_leds`
38 The length of the LED array.
39
40---
41
42### `void apa102_set_brightness(uint8_t brightness)`
43
44Set the global brightness.
45
46#### Arguments {#api-apa102-set-brightness-arguments}
47
48 - `uint8_t brightness`
49 The brightness level to set, from 0 to 31.
diff --git a/docs/drivers/audio.md b/docs/drivers/audio.md
new file mode 100644
index 0000000000..c764c97369
--- /dev/null
+++ b/docs/drivers/audio.md
@@ -0,0 +1,239 @@
1# Audio Driver {#audio-driver}
2
3The [Audio feature](../features/audio) breaks the hardware specifics out into separate, exchangeable driver units, with a common interface to the audio-"core" - which itself handles playing songs and notes while tracking their progress in an internal state, initializing/starting/stopping the driver as needed.
4
5Not all MCUs support every available driver, either the platform-support is not there (yet?) or the MCU simply does not have the required hardware peripheral.
6
7
8## AVR {#avr}
9
10Boards built around an Atmega32U4 can use two sets of PWM capable pins, each driving a separate speaker.
11The possible configurations are:
12
13| | Timer3 | Timer1 |
14|--------------|-------------|--------------|
15| one speaker | C4,C5 or C6 | |
16| one speaker | | B4, B5 or B7 |
17| two speakers | C4,C5 or C6 | B4, B5 or B7 |
18
19Currently there is only one/default driver for AVR based boards, which is automatically configured to:
20
21```make
22AUDIO_DRIVER = pwm_hardware
23```
24
25
26## ARM {#arm}
27
28For Arm based boards, QMK depends on ChibiOS - hence any MCU supported by the later is likely usable, as long as certain hardware peripherals are available.
29
30Supported wiring configurations, with their ChibiOS/MCU peripheral requirement are listed below;
31piezo speakers are marked with :one: for the first/primary and :two: for the secondary.
32
33 | driver | GPTD6<br>Tim6 | GPTD7<br>Tim7 | GPTD8<br>Tim8 | PWMD1<sup>1</sup><br>Tim1_Ch1 |
34 |--------------|------------------------------------------|------------------------|---------------|-------------------------------|
35 | dac_basic | A4+DACD1 = :one: | A5+DACD2 = :one: | state | |
36 | | A4+DACD1 = :one: + Gnd | A5+DACD2 = :two: + Gnd | state | |
37 | | A4+DACD1 = :two: + Gnd | A5+DACD2 = :one: + Gnd | state | |
38 | | A4+DACD1 = :one: + Gnd | | state | |
39 | | | A5+DACD2 = :one: + Gnd | state | |
40 | dac_additive | A4+DACD1 = :one: + Gnd | | | |
41 | | A5+DACD2 = :one: + Gnd | | | |
42 | | A4+DACD1 + A5+DACD2 = :one: <sup>2</sup> | | | |
43 | pwm_software | state-update | | | any = :one: |
44 | pwm hardware | state-update | | | A8 = :one: <sup>3</sup> |
45
46
47<sup>1</sup>: the routing and alternate functions for PWM differ sometimes between STM32 MCUs, if in doubt consult the data-sheet
48<sup>2</sup>: one piezo connected to A4 and A5, with AUDIO_PIN_ALT_AS_NEGATIVE set
49<sup>3</sup>: TIM1_CH1 = A8 on STM32F103C8, other combinations are possible, see Data-sheet. configured with: AUDIO_PWM_DRIVER and AUDIO_PWM_CHANNEL
50
51
52
53### DAC basic {#dac-basic}
54
55The default driver for ARM boards, in absence of an overriding configuration.
56This driver needs one Timer per enabled/used DAC channel, to trigger conversion; and a third timer to trigger state updates with the audio-core.
57
58Additionally, in the board config, you'll want to make changes to enable the DACs, GPT for Timers 6, 7 and 8:
59
60```c
61//halconf.h:
62#define HAL_USE_DAC TRUE
63#define HAL_USE_GPT TRUE
64#include_next <halconf.h>
65```
66
67```c
68// mcuconf.h:
69#include_next <mcuconf.h>
70#undef STM32_DAC_USE_DAC1_CH1
71#define STM32_DAC_USE_DAC1_CH1 TRUE
72#undef STM32_DAC_USE_DAC1_CH2
73#define STM32_DAC_USE_DAC1_CH2 TRUE
74#undef STM32_GPT_USE_TIM6
75#define STM32_GPT_USE_TIM6 TRUE
76#undef STM32_GPT_USE_TIM7
77#define STM32_GPT_USE_TIM7 TRUE
78#undef STM32_GPT_USE_TIM8
79#define STM32_GPT_USE_TIM8 TRUE
80```
81
82::: tip
83Note: DAC1 (A4) uses TIM6, DAC2 (A5) uses TIM7, and the audio state timer uses TIM8 (configurable).
84:::
85
86You can also change the timer used for the overall audio state by defining the driver. For instance:
87
88```c
89#define AUDIO_STATE_TIMER GPTD9
90```
91
92### DAC additive {#dac-additive}
93
94only needs one timer (GPTD6, Tim6) to trigger the DAC unit to do a conversion; the audio state updates are in turn triggered during the DAC callback.
95
96Additionally, in the board config, you'll want to make changes to enable the DACs, GPT for Timer 6:
97
98```c
99//halconf.h:
100#define HAL_USE_DAC TRUE
101#define HAL_USE_GPT TRUE
102#include_next <halconf.h>
103```
104
105```c
106// mcuconf.h:
107#include_next <mcuconf.h>
108#undef STM32_DAC_USE_DAC1_CH1
109#define STM32_DAC_USE_DAC1_CH1 TRUE
110#undef STM32_DAC_USE_DAC1_CH2
111#define STM32_DAC_USE_DAC1_CH2 TRUE
112#undef STM32_GPT_USE_TIM6
113#define STM32_GPT_USE_TIM6 TRUE
114```
115
116### DAC Config
117
118| Define | Defaults | Description |
119| -------------------------------- | -------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
120| `AUDIO_DAC_SAMPLE_MAX` | `4095U` | Highest value allowed. Lower value means lower volume. And 4095U is the upper limit, since this is limited to a 12 bit value. Only effects non-pregenerated samples. |
121| `AUDIO_DAC_OFF_VALUE` | `AUDIO_DAC_SAMPLE_MAX / 2` | The value of the DAC when not playing anything. Some setups may require a high (`AUDIO_DAC_SAMPLE_MAX`) or low (`0`) value here. |
122| `AUDIO_MAX_SIMULTANEOUS_TONES` | __see next table__ | The number of tones that can be played simultaneously. A value that is too high may freeze the controller or glitch out when too many tones are being played. |
123| `AUDIO_DAC_SAMPLE_RATE` | __see next table__ | Effective bit rate of the DAC (in hertz), higher limits simultaneous tones, and lower sacrifices quality. |
124| `AUDIO_DAC_BUFFER_SIZE` | __see next table__ | Number of samples generated every refill. Too few may cause excessive CPU load; too many may cause freezes, RAM or flash exhaustion or lags during matrix scanning. |
125
126There are a number of predefined quality settings that you can use, with "sane minimum" being the default. You can use custom values by simply defining the sample rate, number of simultaneous tones and buffer size, instead of using one of the listed presets.
127
128| Define | Sample Rate | Simultaneous tones | Buffer size |
129| --------------------------------- | ----------- | ------------------- | ----------- |
130| `AUDIO_DAC_QUALITY_VERY_LOW` | `11025U` | `8` | `64U` |
131| `AUDIO_DAC_QUALITY_LOW` | `22050U` | `4` | `128U` |
132| `AUDIO_DAC_QUALITY_HIGH` | `44100U` | `2` | `256U` |
133| `AUDIO_DAC_QUALITY_VERY_HIGH` | `88200U` | `1` | `256U` |
134| `AUDIO_DAC_QUALITY_SANE_MINIMUM` | `16384U` | `8` | `64U` |
135
136#### Notes on buffer size {#buffer-size}
137
138By default, the buffer size attempts to keep to these constraints:
139
140* The interval between buffer refills can't be too short, since the microcontroller would then only be servicing buffer refills and would freeze up.
141* On the additive driver, the interval between buffer refills can't be too long, since matrix scanning would suffer lengthy pauses every so often, which would delay key presses or releases or lose some short taps altogether.
142* The interval between buffer refills is kept to a minimum, which allows notes to stop as soon as possible after they should.
143* For greater compatibility, the buffer size should be a power of 2.
144* The buffer size being too large causes resource exhaustion leading to build failures or freezing at runtime: RAM usage (on the additive driver) or flash usage (on the basic driver).
145
146You can lower the buffer size if you need a bit more space in your firmware, or raise it if your keyboard freezes up.
147
148
149```c
150 /* zero crossing (or approach, whereas zero == DAC_OFF_VALUE, which can be configured to anything from 0 to DAC_SAMPLE_MAX)
151 * ============================*=*========================== AUDIO_DAC_SAMPLE_MAX
152 * * *
153 * * *
154 * ---------------------------------------------------------
155 * * * } AUDIO_DAC_SAMPLE_MAX/100
156 * --------------------------------------------------------- AUDIO_DAC_OFF_VALUE
157 * * * } AUDIO_DAC_SAMPLE_MAX/100
158 * ---------------------------------------------------------
159 * *
160 * * *
161 * * *
162 * =====*=*================================================= 0x0
163 */
164```
165
166
167### PWM hardware {#pwm-hardware}
168
169This driver uses the ChibiOS-PWM system to produce a square-wave on specific output pins that are connected to the PWM hardware.
170The hardware directly toggles the pin via its alternate function. See your MCU's data-sheet for which pin can be driven by what timer - looking for TIMx_CHy and the corresponding alternate function.
171
172A configuration example for the STM32F103C8 would be:
173```c
174//halconf.h:
175#define HAL_USE_PWM TRUE
176#define HAL_USE_PAL TRUE
177#include_next <halconf.h>
178```
179
180```c
181// mcuconf.h:
182#include_next <mcuconf.h>
183#undef STM32_PWM_USE_TIM1
184#define STM32_PWM_USE_TIM1 TRUE
185```
186
187If we now target pin A8, looking through the data-sheet of the STM32F103C8, for the timers and alternate functions
188- TIM1_CH1 = PA8 <- alternate0
189- TIM1_CH2 = PA9
190- TIM1_CH3 = PA10
191- TIM1_CH4 = PA11
192
193with all this information, the configuration would contain these lines:
194```c
195//config.h:
196#define AUDIO_PIN A8
197#define AUDIO_PWM_DRIVER PWMD1
198#define AUDIO_PWM_CHANNEL 1
199```
200
201ChibiOS uses GPIOv1 for the F103, which only knows of one alternate function.
202On 'larger' STM32s, GPIOv2 or GPIOv3 are used; with them it is also necessary to configure `AUDIO_PWM_PAL_MODE` to the correct alternate function for the selected pin, timer and timer-channel.
203
204You can also use the Complementary output (`TIMx_CHyN`) for PWM on supported controllers. To enable this functionality, you will need to make the following changes:
205```c
206// config.h:
207#define AUDIO_PWM_COMPLEMENTARY_OUTPUT
208```
209
210### PWM software {#pwm-software}
211
212This driver uses the PWM callbacks from PWMD1 with TIM1_CH1 to toggle the selected AUDIO_PIN in software.
213During the same callback, with AUDIO_PIN_ALT_AS_NEGATIVE set, the AUDIO_PIN_ALT is toggled inversely to AUDIO_PIN. This is useful for setups that drive a piezo from two pins (instead of one and Gnd).
214
215You can also change the timer used for software PWM by defining the driver. For instance:
216
217```c
218#define AUDIO_STATE_TIMER GPTD8
219```
220
221
222### Testing Notes {#testing-notes}
223
224While not an exhaustive list, the following table provides the scenarios that have been partially validated:
225
226| | DAC basic | DAC additive | PWM hardware | PWM software |
227| ------------------------ | ------------------ | ------------------ | ------------------ | ------------------ |
228| Atmega32U4 | :o: | :o: | :heavy_check_mark: | :o: |
229| RP2040 | :x: | :x: | :heavy_check_mark: | ? |
230| STM32F103C8 (bluepill) | :x: | :x: | :heavy_check_mark: | :heavy_check_mark: |
231| STM32F303CCT6 (proton-c) | :heavy_check_mark: | :heavy_check_mark: | ? | :heavy_check_mark: |
232| STM32F405VG | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
233| L0xx | :x: (no Tim8) | ? | ? | ? |
234
235:heavy_check_mark: : works and was tested
236:o: : does not apply
237:x: : not supported by MCU
238
239*Other supported ChibiOS boards and/or pins may function, it will be highly chip and configuration dependent.*
diff --git a/docs/drivers/eeprom.md b/docs/drivers/eeprom.md
new file mode 100644
index 0000000000..82630c501d
--- /dev/null
+++ b/docs/drivers/eeprom.md
@@ -0,0 +1,180 @@
1# EEPROM Driver Configuration {#eeprom-driver-configuration}
2
3The EEPROM driver can be swapped out depending on the needs of the keyboard, or whether extra hardware is present.
4
5Selecting the EEPROM driver is done in your keyboard's `rules.mk`:
6
7Driver | Description
8-----------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
9`EEPROM_DRIVER = vendor` (default) | Uses the on-chip driver provided by the chip manufacturer. For AVR, this is provided by avr-libc. This is supported on ARM for a subset of chips -- STM32F3xx, STM32F1xx, and STM32F072xB will be emulated by writing to flash. STM32L0xx and STM32L1xx will use the onboard dedicated true EEPROM. Other chips will generally act as "transient" below.
10`EEPROM_DRIVER = i2c` | Supports writing to I2C-based 24xx EEPROM chips. See the driver section below.
11`EEPROM_DRIVER = spi` | Supports writing to SPI-based 25xx EEPROM chips. See the driver section below.
12`EEPROM_DRIVER = transient` | Fake EEPROM driver -- supports reading/writing to RAM, and will be discarded when power is lost.
13`EEPROM_DRIVER = wear_leveling` | Frontend driver for the wear_leveling system, allowing for EEPROM emulation on top of flash -- both in-MCU and external SPI NOR flash.
14
15## Vendor Driver Configuration {#vendor-eeprom-driver-configuration}
16
17#### STM32 L0/L1 Configuration {#stm32l0l1-eeprom-driver-configuration}
18
19::: warning
20Resetting EEPROM using an STM32L0/L1 device takes up to 1 second for every 1kB of internal EEPROM used.
21:::
22
23`config.h` override | Description | Default Value
24------------------------------------|--------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------
25`#define STM32_ONBOARD_EEPROM_SIZE` | The size of the EEPROM to use, in bytes. Erase times can be high, so it's configurable here, if not using the default value. | Minimum required to cover base _eeconfig_ data, or `1024` if VIA is enabled.
26
27## I2C Driver Configuration {#i2c-eeprom-driver-configuration}
28
29Currently QMK supports 24xx-series chips over I2C. As such, requires a working i2c_master driver configuration. You can override the driver configuration via your config.h:
30
31`config.h` override | Description | Default Value
32------------------------------------------- | ----------------------------------------------------------------------------------- | ------------------------------------
33`#define EXTERNAL_EEPROM_I2C_BASE_ADDRESS` | Base I2C address for the EEPROM -- shifted left by 1 as per i2c_master requirements | 0b10100000
34`#define EXTERNAL_EEPROM_I2C_ADDRESS(addr)` | Calculated I2C address for the EEPROM | `(EXTERNAL_EEPROM_I2C_BASE_ADDRESS)`
35`#define EXTERNAL_EEPROM_BYTE_COUNT` | Total size of the EEPROM in bytes | 8192
36`#define EXTERNAL_EEPROM_PAGE_SIZE` | Page size of the EEPROM in bytes, as specified in the datasheet | 32
37`#define EXTERNAL_EEPROM_ADDRESS_SIZE` | The number of bytes to transmit for the memory location within the EEPROM | 2
38`#define EXTERNAL_EEPROM_WRITE_TIME` | Write cycle time of the EEPROM, as specified in the datasheet | 5
39`#define EXTERNAL_EEPROM_WP_PIN` | If defined the WP pin will be toggled appropriately when writing to the EEPROM. | _none_
40
41Some I2C EEPROM manufacturers explicitly recommend against hardcoding the WP pin to ground. This is in order to protect the eeprom memory content during power-up/power-down/brown-out conditions at low voltage where the eeprom is still operational, but the i2c master output might be unpredictable. If a WP pin is configured, then having an external pull-up on the WP pin is recommended.
42
43Default values and extended descriptions can be found in `drivers/eeprom/eeprom_i2c.h`.
44
45Alternatively, there are pre-defined hardware configurations for available chips/modules:
46
47Module | Equivalent `#define` | Source
48-----------------|---------------------------------|------------------------------------------
49CAT24C512 EEPROM | `#define EEPROM_I2C_CAT24C512` | <https://www.sparkfun.com/products/14764>
50RM24C512C EEPROM | `#define EEPROM_I2C_RM24C512C` | <https://www.sparkfun.com/products/14764>
5124LC32A EEPROM | `#define EEPROM_I2C_24LC32A` | <https://www.microchip.com/en-us/product/24LC32A>
5224LC64 EEPROM | `#define EEPROM_I2C_24LC64` | <https://www.microchip.com/en-us/product/24LC64>
5324LC128 EEPROM | `#define EEPROM_I2C_24LC128` | <https://www.microchip.com/en-us/product/24LC128>
5424LC256 EEPROM | `#define EEPROM_I2C_24LC256` | <https://www.sparkfun.com/products/525>
55MB85RC256V FRAM | `#define EEPROM_I2C_MB85RC256V` | <https://www.adafruit.com/product/1895>
56
57::: tip
58If you find that the EEPROM is not cooperating, ensure you've correctly shifted up your EEPROM address by 1. For example, the datasheet might state the address as `0b01010000` -- the correct value of `EXTERNAL_EEPROM_I2C_BASE_ADDRESS` needs to be `0b10100000`.
59:::
60
61## SPI Driver Configuration {#spi-eeprom-driver-configuration}
62
63Currently QMK supports 25xx-series chips over SPI. As such, requires a working spi_master driver configuration. You can override the driver configuration via your config.h:
64
65`config.h` override | Default Value | Description
66-----------------------------------------------|---------------|-------------------------------------------------------------------------------------
67`#define EXTERNAL_EEPROM_SPI_SLAVE_SELECT_PIN` | _none_ | SPI Slave select pin in order to inform that the EEPROM is currently being addressed
68`#define EXTERNAL_EEPROM_SPI_CLOCK_DIVISOR` | `64` | Clock divisor used to divide the peripheral clock to derive the SPI frequency
69`#define EXTERNAL_EEPROM_BYTE_COUNT` | `8192` | Total size of the EEPROM in bytes
70`#define EXTERNAL_EEPROM_PAGE_SIZE` | `32` | Page size of the EEPROM in bytes, as specified in the datasheet
71`#define EXTERNAL_EEPROM_ADDRESS_SIZE` | `2` | The number of bytes to transmit for the memory location within the EEPROM
72
73Default values and extended descriptions can be found in `drivers/eeprom/eeprom_spi.h`.
74
75Alternatively, there are pre-defined hardware configurations for available chips/modules:
76
77Module | Equivalent `#define` | Source
78-----------------|---------------------------------|------------------------------------------
79MB85RS64V FRAM | `define EEPROM_SPI_MB85RS64V` | <https://www.adafruit.com/product/1897>
80
81::: warning
82There's no way to determine if there is an SPI EEPROM actually responding. Generally, this will result in reads of nothing but zero.
83:::
84
85## Transient Driver configuration {#transient-eeprom-driver-configuration}
86
87The only configurable item for the transient EEPROM driver is its size:
88
89`config.h` override | Description | Default Value
90------------------------------- | ----------------------------------------- | -------------
91`#define TRANSIENT_EEPROM_SIZE` | Total size of the EEPROM storage in bytes | 64
92
93Default values and extended descriptions can be found in `drivers/eeprom/eeprom_transient.h`.
94
95## Wear-leveling Driver Configuration {#wear_leveling-eeprom-driver-configuration}
96
97The wear-leveling driver uses an algorithm to minimise the number of erase cycles on the underlying MCU flash memory.
98
99There is no specific configuration for this driver, but the wear-leveling system used by this driver may need configuration. See the [wear-leveling configuration](#wear_leveling-configuration) section for more information.
100
101# Wear-leveling Configuration {#wear_leveling-configuration}
102
103The wear-leveling driver has a few possible _backing stores_ that may be used by adding to your keyboard's `rules.mk` file:
104
105Driver | Description
106----------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
107`WEAR_LEVELING_DRIVER = embedded_flash` | This driver is used for emulating EEPROM by writing to embedded flash on the MCU.
108`WEAR_LEVELING_DRIVER = spi_flash` | This driver is used to address external SPI NOR Flash peripherals.
109`WEAR_LEVELING_DRIVER = rp2040_flash` | This driver is used to write to the same storage the RP2040 executes code from.
110`WEAR_LEVELING_DRIVER = legacy` | This driver is the "legacy" emulated EEPROM provided in historical revisions of QMK. Currently used for STM32F0xx and STM32F4x1, but slated for deprecation and removal once `embedded_flash` support for those MCU families is complete.
111
112::: warning
113All wear-leveling drivers require an amount of RAM equivalent to the selected logical EEPROM size. Increasing the size to 32kB of EEPROM requires 32kB of RAM, which a significant number of MCUs simply do not have.
114:::
115
116## Wear-leveling Embedded Flash Driver Configuration {#wear_leveling-efl-driver-configuration}
117
118This driver performs writes to the embedded flash storage embedded in the MCU. In most circumstances, the last few of sectors of flash are used in order to minimise the likelihood of collision with program code.
119
120Configurable options in your keyboard's `config.h`:
121
122`config.h` override | Default | Description
123-----------------------------------------|-------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
124`#define WEAR_LEVELING_EFL_FIRST_SECTOR` | _unset_ | The first sector on the MCU to use. By default this is not defined and calculated at runtime based on the MCU. However, different flash sizes on MCUs may require custom configuration.
125`#define WEAR_LEVELING_EFL_FLASH_SIZE` | _unset_ | Allows overriding the flash size available for use for wear-leveling. Under normal circumstances this is automatically calculated and should not need to be overridden. Specifying a size larger than the amount actually available in flash will usually prevent the MCU from booting.
126`#define WEAR_LEVELING_LOGICAL_SIZE` | `(backing_size/2)` | Number of bytes "exposed" to the rest of QMK and denotes the size of the usable EEPROM.
127`#define WEAR_LEVELING_BACKING_SIZE` | `2048` | Number of bytes used by the wear-leveling algorithm for its underlying storage, and needs to be a multiple of the logical size.
128`#define BACKING_STORE_WRITE_SIZE` | _automatic_ | The byte width of the underlying write used on the MCU, and is usually automatically determined from the selected MCU family. If an error occurs in the auto-detection, you'll need to consult the MCU's datasheet and determine this value, specifying it directly.
129
130::: warning
131If your MCU does not boot after swapping to the EFL wear-leveling driver, it's likely that the flash size is incorrectly detected, usually as an MCU with larger flash and may require overriding.
132:::
133
134## Wear-leveling SPI Flash Driver Configuration {#wear_leveling-flash_spi-driver-configuration}
135
136This driver performs writes to an external SPI NOR Flash peripheral. It also requires a working configuration for the SPI NOR Flash peripheral -- see the [flash driver](flash) documentation for more information.
137
138Configurable options in your keyboard's `config.h`:
139
140`config.h` override | Default | Description
141----------------------------------------------------|--------------------------------|--------------------------------------------------------------------------------------------------------------------------------
142`#define WEAR_LEVELING_EXTERNAL_FLASH_BLOCK_COUNT` | `1` | Number of blocks in the external flash used by the wear-leveling algorithm.
143`#define WEAR_LEVELING_EXTERNAL_FLASH_BLOCK_OFFSET` | `0` | The index first block in the external flash used by the wear-leveling algorithm.
144`#define WEAR_LEVELING_LOGICAL_SIZE` | `((block_count*block_size)/2)` | Number of bytes "exposed" to the rest of QMK and denotes the size of the usable EEPROM. Result must be <= 64kB.
145`#define WEAR_LEVELING_BACKING_SIZE` | `(block_count*block_size)` | Number of bytes used by the wear-leveling algorithm for its underlying storage, and needs to be a multiple of the logical size.
146`#define BACKING_STORE_WRITE_SIZE` | `8` | The write width used whenever a write is performed on the external flash peripheral.
147
148::: warning
149There is currently a limit of 64kB for the EEPROM subsystem within QMK, so using a larger flash is not going to be beneficial as the logical size cannot be increased beyond 65536. The backing size may be increased to a larger value, but erase timing may suffer as a result.
150:::
151
152## Wear-leveling RP2040 Driver Configuration {#wear_leveling-rp2040-driver-configuration}
153
154This driver performs writes to the same underlying storage that the RP2040 executes its code.
155
156Configurable options in your keyboard's `config.h`:
157
158`config.h` override | Default | Description
159------------------------------------------|----------------------------|--------------------------------------------------------------------------------------------------------------------------------
160`#define WEAR_LEVELING_RP2040_FLASH_SIZE` | `PICO_FLASH_SIZE_BYTES` | Number of bytes of flash on the board.
161`#define WEAR_LEVELING_RP2040_FLASH_BASE` | `(flash_size-sector_size)` | The byte-wise location that the backing storage should be located.
162`#define WEAR_LEVELING_LOGICAL_SIZE` | `(backing_size/2)` | Number of bytes "exposed" to the rest of QMK and denotes the size of the usable EEPROM.
163`#define WEAR_LEVELING_BACKING_SIZE` | `8192` | Number of bytes used by the wear-leveling algorithm for its underlying storage, and needs to be a multiple of the logical size as well as the sector size.
164`#define BACKING_STORE_WRITE_SIZE` | `2` | The write width used whenever a write is performed on the external flash peripheral.
165
166## Wear-leveling Legacy EEPROM Emulation Driver Configuration {#wear_leveling-legacy-driver-configuration}
167
168This driver performs writes to the embedded flash storage embedded in the MCU much like the normal Embedded Flash Driver, and is only for use with STM32F0xx and STM32F4x1 devices. This flash implementation is still currently provided as the EFL driver is currently non-functional for the previously mentioned families.
169
170By default, `1024` bytes of emulated EEPROM is provided:
171
172MCU | EEPROM Provided | Flash Used
173----------|-----------------|--------------
174STM32F042 | `1024` bytes | `2048` bytes
175STM32F070 | `1024` bytes | `2048` bytes
176STM32F072 | `1024` bytes | `2048` bytes
177STM32F401 | `1024` bytes | `16384` bytes
178STM32F411 | `1024` bytes | `16384` bytes
179
180Under normal circumstances configuration of this driver requires intimate knowledge of the MCU's flash structure -- reconfiguration is at your own risk and will require referring to the code.
diff --git a/docs/drivers/flash.md b/docs/drivers/flash.md
new file mode 100644
index 0000000000..4160721350
--- /dev/null
+++ b/docs/drivers/flash.md
@@ -0,0 +1,26 @@
1# FLASH Driver Configuration {#flash-driver-configuration}
2
3The FLASH driver can be swapped out depending on the needs of the keyboard, or whether extra hardware is present.
4
5Driver | Description
6-----------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
7`FLASH_DRIVER = spi` | Supports writing to almost all NOR Flash chips. See the driver section below.
8
9
10## SPI FLASH Driver Configuration {#spi-flash-driver-configuration}
11
12Currently QMK supports almost all NOR Flash chips over SPI. As such, requires a working spi_master driver configuration. You can override the driver configuration via your config.h:
13
14`config.h` override | Description | Default Value
15-----------------------------------------------|--------------------------------------------------------------------------------------|-----------------
16`#define EXTERNAL_FLASH_SPI_SLAVE_SELECT_PIN` | SPI Slave select pin in order to inform that the FLASH is currently being addressed | _none_
17`#define EXTERNAL_FLASH_SPI_CLOCK_DIVISOR` | Clock divisor used to divide the peripheral clock to derive the SPI frequency | `8`
18`#define EXTERNAL_FLASH_PAGE_SIZE` | The Page size of the FLASH in bytes, as specified in the datasheet | `256`
19`#define EXTERNAL_FLASH_SECTOR_SIZE` | The sector size of the FLASH in bytes, as specified in the datasheet | `(4 * 1024)`
20`#define EXTERNAL_FLASH_BLOCK_SIZE` | The block size of the FLASH in bytes, as specified in the datasheet | `(64 * 1024)`
21`#define EXTERNAL_FLASH_SIZE` | The total size of the FLASH in bytes, as specified in the datasheet | `(512 * 1024)`
22`#define EXTERNAL_FLASH_ADDRESS_SIZE` | The Flash address size in bytes, as specified in datasheet | `3`
23
24::: warning
25All the above default configurations are based on MX25L4006E NOR Flash.
26:::
diff --git a/docs/drivers/gpio.md b/docs/drivers/gpio.md
new file mode 100644
index 0000000000..9ce4f2aa20
--- /dev/null
+++ b/docs/drivers/gpio.md
@@ -0,0 +1,44 @@
1# GPIO Control {#gpio-control}
2
3QMK has a GPIO control abstraction layer which is microcontroller agnostic. This is done to allow easy access to pin control across different platforms.
4
5## Macros {#macros}
6
7The following macros provide basic control of GPIOs and are found in `platforms/<platform>/gpio.h`.
8
9|Macro |Description |
10|-------------------------------------|---------------------------------------------------------------------|
11|`gpio_set_pin_input(pin)` |Set pin as input with high impedance (High-Z) |
12|`gpio_set_pin_input_high(pin)` |Set pin as input with builtin pull-up resistor |
13|`gpio_set_pin_input_low(pin)` |Set pin as input with builtin pull-down resistor (unavailable on AVR)|
14|`gpio_set_pin_output(pin)` |Set pin as output (alias of `gpio_set_pin_output_push_pull`) |
15|`gpio_set_pin_output_push_pull(pin)` |Set pin as output, push/pull mode |
16|`gpio_set_pin_output_open_drain(pin)`|Set pin as output, open-drain mode (unavailable on AVR and ATSAM) |
17|`gpio_write_pin_high(pin)` |Set pin level as high, assuming it is an output |
18|`gpio_write_pin_low(pin)` |Set pin level as low, assuming it is an output |
19|`gpio_write_pin(pin, level)` |Set pin level, assuming it is an output |
20|`gpio_read_pin(pin)` |Returns the level of the pin |
21|`gpio_toggle_pin(pin)` |Invert pin level, assuming it is an output |
22
23## Advanced Settings {#advanced-settings}
24
25Each microcontroller can have multiple advanced settings regarding its GPIO. This abstraction layer does not limit the use of architecture-specific functions. Advanced users should consult the datasheet of their desired device. For AVR, the standard `avr/io.h` library is used; for STM32, the ChibiOS [PAL library](https://chibios.sourceforge.net/docs3/hal/group___p_a_l.html) is used.
26
27## Atomic Operation {#atomic-operation}
28
29The above functions are not always guaranteed to work atomically. Therefore, if you want to prevent interruptions in the middle of operations when using multiple combinations of the above functions, use the following `ATOMIC_BLOCK_FORCEON` macro.
30
31eg.
32```c
33void some_function(void) {
34 // some process
35 ATOMIC_BLOCK_FORCEON {
36 // Atomic Processing
37 }
38 // some process
39}
40```
41
42`ATOMIC_BLOCK_FORCEON` forces interrupts to be disabled before the block is executed, without regard to whether they are enabled or disabled. Then, after the block is executed, the interrupt is enabled.
43
44Note that `ATOMIC_BLOCK_FORCEON` can therefore be used if you know that interrupts are enabled before the execution of the block, or if you know that it is OK to enable interrupts at the completion of the block.
diff --git a/docs/drivers/i2c.md b/docs/drivers/i2c.md
new file mode 100644
index 0000000000..10949ed59e
--- /dev/null
+++ b/docs/drivers/i2c.md
@@ -0,0 +1,290 @@
1# I2C Master Driver {#i2c-master-driver}
2
3The I2C Master drivers used in QMK have a set of common functions to allow portability between MCUs.
4
5## Usage {#usage}
6
7In most cases, the I2C Master driver code is automatically included if you are using a feature or driver which requires it, such as [OLED](../features/oled_driver).
8
9However, if you need to use the driver standalone, add the following to your `rules.mk`:
10
11```make
12I2C_DRIVER_REQUIRED = yes
13```
14
15You can then call the I2C API by including `i2c_master.h` in your code.
16
17## I2C Addressing {#note-on-i2c-addresses}
18
19All of the addresses expected by this driver should be pushed to the upper 7 bits of the address byte. Setting
20the lower bit (indicating read/write) will be done by the respective functions. Almost all I2C addresses listed
21on datasheets and the internet will be represented as 7 bits occupying the lower 7 bits and will need to be
22shifted to the left (more significant) by one bit. This is easy to do via the bitwise shift operator `<< 1`.
23
24You can either do this on each call to the functions below, or once in your definition of the address. For example, if your device has an address of `0x18`:
25
26```c
27#define MY_I2C_ADDRESS (0x18 << 1)
28```
29
30See https://www.robot-electronics.co.uk/i2c-tutorial for more information about I2C addressing and other technical details.
31
32## AVR Configuration {#avr-configuration}
33
34The following defines can be used to configure the I2C master driver:
35
36|`config.h` Override|Description |Default |
37|-------------------|---------------------|--------|
38|`F_SCL` |Clock frequency in Hz|`400000`|
39
40No further setup is required - just connect the `SDA` and `SCL` pins of your I2C devices to the matching pins on the MCU:
41
42|MCU |`SCL`|`SDA`|
43|------------------|-----|-----|
44|ATmega16/32U4 |`D0` |`D1` |
45|AT90USB64/128 |`D0` |`D1` |
46|ATmega32A |`C0` |`C1` |
47|ATmega328/P |`C5` |`C4` |
48
49::: tip
50The ATmega16/32U2 does not possess I2C functionality, and so cannot use this driver.
51:::
52
53## ChibiOS/ARM Configuration {#arm-configuration}
54
55You'll need to determine which pins can be used for I2C -- a an example, STM32 parts generally have multiple I2C peripherals, labeled I2C1, I2C2, I2C3 etc.
56
57To enable I2C, modify your board's `halconf.h` to enable I2C:
58
59```c
60#define HAL_USE_I2C TRUE
61```
62
63Then, modify your board's `mcuconf.h` to enable the peripheral you've chosen, for example:
64
65```c
66#undef STM32_I2C_USE_I2C2
67#define STM32_I2C_USE_I2C2 TRUE
68```
69
70|`mcuconf.h` Setting |Description |Default|
71|----------------------------|----------------------------------------------------------------------------------|-------|
72|`STM32_I2C_BUSY_TIMEOUT` |Time in milliseconds until the I2C command is aborted if no response is received |`50` |
73|`STM32_I2C_XXX_IRQ_PRIORITY`|Interrupt priority for hardware driver XXX (THIS IS AN EXPERT SETTING) |`10` |
74|`STM32_I2C_USE_DMA` |Enable/Disable the ability of the MCU to offload the data transfer to the DMA unit|`TRUE` |
75|`STM32_I2C_XXX_DMA_PRIORITY`|Priority of DMA unit for hardware driver XXX (THIS IS AN EXPERT SETTING) |`1` |
76
77Configuration-wise, you'll need to set up the peripheral as per your MCU's datasheet -- the defaults match the pins for a Proton-C, i.e. STM32F303.
78
79|`config.h` Overrride |Description |Default|
80|------------------------|--------------------------------------------------------------|-------|
81|`I2C_DRIVER` |I2C peripheral to use - I2C1 -> `I2CD1`, I2C2 -> `I2CD2` etc. |`I2CD1`|
82|`I2C1_SCL_PIN` |The pin definition for SCL |`B6` |
83|`I2C1_SCL_PAL_MODE` |The alternate function mode for SCL |`4` |
84|`I2C1_SDA_PIN` |The pin definition for SDA |`B7` |
85|`I2C1_SDA_PAL_MODE` |The alternate function mode for SDA |`4` |
86
87The following configuration values depend on the specific MCU in use.
88
89### I2Cv1 {#arm-configuration-i2cv1}
90
91* STM32F1xx
92* STM32F2xx
93* STM32F4xx
94* STM32L0xx
95* STM32L1xx
96
97See [this page](https://www.playembedded.org/blog/stm32-i2c-chibios/#7_I2Cv1_configuration_structure) for the I2Cv1 configuration structure.
98
99|`config.h` Override|Default |
100|-------------------|----------------|
101|`I2C1_OPMODE` |`OPMODE_I2C` |
102|`I2C1_CLOCK_SPEED` |`100000` |
103|`I2C1_DUTY_CYCLE` |`STD_DUTY_CYCLE`|
104
105### I2Cv2 {#arm-configuration-i2cv2}
106
107* STM32F0xx
108* STM32F3xx
109* STM32F7xx
110* STM32L4xx
111
112See [this page](https://www.playembedded.org/blog/stm32-i2c-chibios/#8_I2Cv2_I2Cv3_configuration_structure) for the I2Cv2 configuration structure.
113
114|`config.h` Override |Default|
115|---------------------|-------|
116|`I2C1_TIMINGR_PRESC` |`0U` |
117|`I2C1_TIMINGR_SCLDEL`|`7U` |
118|`I2C1_TIMINGR_SDADEL`|`0U` |
119|`I2C1_TIMINGR_SCLH` |`38U` |
120|`I2C1_TIMINGR_SCLL` |`129U` |
121
122## API {#api}
123
124### `void i2c_init(void)` {#api-i2c-init}
125
126Initialize the I2C driver. This function must be called only once, before any of the below functions can be called.
127
128This function is weakly defined, meaning it can be overridden if necessary for your particular use case:
129
130```c
131void i2c_init(void) {
132 gpio_set_pin_input(B6); // Try releasing special pins for a short time
133 gpio_set_pin_input(B7);
134 wait_ms(10); // Wait for the release to happen
135
136 palSetPadMode(GPIOB, 6, PAL_MODE_ALTERNATE(4) | PAL_STM32_OTYPE_OPENDRAIN | PAL_STM32_PUPDR_PULLUP); // Set B6 to I2C function
137 palSetPadMode(GPIOB, 7, PAL_MODE_ALTERNATE(4) | PAL_STM32_OTYPE_OPENDRAIN | PAL_STM32_PUPDR_PULLUP); // Set B7 to I2C function
138}
139```
140
141---
142
143### `i2c_status_t i2c_transmit(uint8_t address, uint8_t *data, uint16_t length, uint16_t timeout)` {#api-i2c-transmit}
144
145Send multiple bytes to the selected I2C device.
146
147#### Arguments {#api-i2c-transmit-arguments}
148
149 - `uint8_t address`
150 The 7-bit I2C address of the device.
151 - `uint8_t *data`
152 A pointer to the data to transmit.
153 - `uint16_t length`
154 The number of bytes to write. Take care not to overrun the length of `data`.
155 - `uint16_t timeout`
156 The time in milliseconds to wait for a response from the target device.
157
158#### Return Value {#api-i2c-transmit-return}
159
160`I2C_STATUS_TIMEOUT` if the timeout period elapses, `I2C_STATUS_ERROR` if some other error occurs, otherwise `I2C_STATUS_SUCCESS`.
161
162---
163
164### `i2c_status_t i2c_receive(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout)` {#api-i2c-receive}
165
166Receive multiple bytes from the selected I2C device.
167
168#### Arguments {#api-i2c-receive-arguments}
169
170 - `uint8_t address`
171 The 7-bit I2C address of the device.
172 - `uint8_t *data`
173 A pointer to the buffer to read into.
174 - `uint16_t length`
175 The number of bytes to read. Take care not to overrun the length of `data`.
176 - `uint16_t timeout`
177 The time in milliseconds to wait for a response from the target device.
178
179#### Return Value {#api-i2c-receive-return}
180
181`I2C_STATUS_TIMEOUT` if the timeout period elapses, `I2C_STATUS_ERROR` if some other error occurs, otherwise `I2C_STATUS_SUCCESS`.
182
183---
184
185### `i2c_status_t i2c_write_register(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout)` {#api-i2c-write-register}
186
187Writes to a register with an 8-bit address on the I2C device.
188
189#### Arguments {#api-i2c-write-register-arguments}
190
191 - `uint8_t devaddr`
192 The 7-bit I2C address of the device.
193 - `uint8_t regaddr`
194 The register address to write to.
195 - `uint8_t *data`
196 A pointer to the data to transmit.
197 - `uint16_t length`
198 The number of bytes to write. Take care not to overrun the length of `data`.
199 - `uint16_t timeout`
200 The time in milliseconds to wait for a response from the target device.
201
202#### Return Value {#api-i2c-write-register-return}
203
204`I2C_STATUS_TIMEOUT` if the timeout period elapses, `I2C_STATUS_ERROR` if some other error occurs, otherwise `I2C_STATUS_SUCCESS`.
205
206---
207
208### `i2c_status_t i2c_write_register16(uint8_t devaddr, uint16_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout)` {#api-i2c-write-register16}
209
210Writes to a register with a 16-bit address (big endian) on the I2C device.
211
212#### Arguments {#api-i2c-write-register16-arguments}
213
214 - `uint8_t devaddr`
215 The 7-bit I2C address of the device.
216 - `uint16_t regaddr`
217 The register address to write to.
218 - `uint8_t *data`
219 A pointer to the data to transmit.
220 - `uint16_t length`
221 The number of bytes to write. Take care not to overrun the length of `data`.
222 - `uint16_t timeout`
223 The time in milliseconds to wait for a response from the target device.
224
225#### Return Value {#api-i2c-write-register16-return}
226
227`I2C_STATUS_TIMEOUT` if the timeout period elapses, `I2C_STATUS_ERROR` if some other error occurs, otherwise `I2C_STATUS_SUCCESS`.
228
229---
230
231### `i2c_status_t i2c_read_register(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout)` {#api-i2c-read-register}
232
233Reads from a register with an 8-bit address on the I2C device.
234
235#### Arguments {#api-i2c-read-register-arguments}
236
237 - `uint8_t devaddr`
238 The 7-bit I2C address of the device.
239 - `uint8_t regaddr`
240 The register address to read from.
241 - `uint16_t length`
242 The number of bytes to read. Take care not to overrun the length of `data`.
243 - `uint16_t timeout`
244 The time in milliseconds to wait for a response from the target device.
245
246#### Return Value {#api-i2c-read-register-return}
247
248`I2C_STATUS_TIMEOUT` if the timeout period elapses, `I2C_STATUS_ERROR` if some other error occurs, otherwise `I2C_STATUS_SUCCESS`.
249
250---
251
252### `i2c_status_t i2c_read_register16(uint8_t devaddr, uint16_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout)` {#api-i2c-read-register16}
253
254Reads from a register with a 16-bit address (big endian) on the I2C device.
255
256#### Arguments {#api-i2c-read-register16-arguments}
257
258 - `uint8_t devaddr`
259 The 7-bit I2C address of the device.
260 - `uint16_t regaddr`
261 The register address to read from.
262 - `uint16_t length`
263 The number of bytes to read. Take care not to overrun the length of `data`.
264 - `uint16_t timeout`
265 The time in milliseconds to wait for a response from the target device.
266
267#### Return Value {#api-i2c-read-register16-return}
268
269`I2C_STATUS_TIMEOUT` if the timeout period elapses, `I2C_STATUS_ERROR` if some other error occurs, otherwise `I2C_STATUS_SUCCESS`.
270
271---
272
273### `i2c_status_t i2c_ping_address(uint8_t address, uint16_t timeout)` {#api-i2c-ping-address}
274
275Pings the I2C bus for a specific address.
276
277On ChibiOS a "best effort" attempt is made by reading a single byte from register 0 at the requested address. This should generally work except for I2C devices that do not not respond to a register 0 read request, which will result in a false negative result (unsucessful response to ping attempt).
278
279This function is weakly defined, meaning it can be overridden if necessary for your particular use case:
280
281#### Arguments
282
283 - `uint8_t address`
284 The 7-bit I2C address of the device (ie. without the read/write bit - this will be set automatically).
285 - `uint16_t timeout`
286 The time in milliseconds to wait for a response from the target device.
287
288#### Return Value
289
290`I2C_STATUS_TIMEOUT` if the timeout period elapses, `I2C_STATUS_ERROR` if some other error occurs, otherwise `I2C_STATUS_SUCCESS`.
diff --git a/docs/drivers/serial.md b/docs/drivers/serial.md
new file mode 100644
index 0000000000..364e951b86
--- /dev/null
+++ b/docs/drivers/serial.md
@@ -0,0 +1,397 @@
1# 'serial' Driver
2
3The Serial driver powers the [Split Keyboard](../features/split_keyboard) feature. Several implementations are available that cater to the platform and capabilites of MCU in use. Note that none of the drivers support split keyboards with more than two halves.
4
5| Driver | AVR | ARM | Connection between halves |
6| --------------------------------------- | ------------------ | ------------------ | --------------------------------------------------------------------------------------------- |
7| [Bitbang](#bitbang) | :heavy_check_mark: | :heavy_check_mark: | Single wire communication. One wire is used for reception and transmission. |
8| [USART Half-duplex](#usart-half-duplex) | | :heavy_check_mark: | Efficient single wire communication. One wire is used for reception and transmission. |
9| [USART Full-duplex](#usart-full-duplex) | | :heavy_check_mark: | Efficient two wire communication. Two distinct wires are used for reception and transmission. |
10
11::: tip
12Serial in this context should be read as **sending information one bit at a time**, rather than implementing UART/USART/RS485/RS232 standards.
13:::
14
15<hr>
16
17## Bitbang
18
19This is the Default driver, absence of configuration assumes this driver. It works by [bit banging](https://en.wikipedia.org/wiki/Bit_banging) a GPIO pin using the CPU. It is therefore not as efficient as a dedicated hardware peripheral, which the Half-duplex and Full-duplex drivers use.
20
21::: warning
22On ARM platforms the bitbang driver causes connection issues when using it together with the bitbang WS2812 driver. Choosing alternate drivers for both serial and WS2812 (instead of bitbang) is strongly recommended.
23:::
24
25### Pin configuration
26
27```
28 LEFT RIGHT
29+-------+ SERIAL +-------+
30| SSP |-----------------| SSP |
31| | VDD | |
32| |-----------------| |
33| | GND | |
34| |-----------------| |
35+-------+ +-------+
36```
37
38One GPIO pin is needed for the bitbang driver, as only one wire is used for receiving and transmitting data. This pin is referred to as the `SOFT_SERIAL_PIN` (SSP) in the configuration. A TRS or USB cable provides enough conductors for this driver to function.
39
40### Setup
41
42To use the bitbang driver follow these steps to activate it.
43
441. Change the `SERIAL_DRIVER` to `bitbang` in your keyboards `rules.mk` file:
45
46```make
47SERIAL_DRIVER = bitbang
48```
49
502. Configure the GPIO pin of your keyboard via the `config.h` file:
51
52```c
53#define SOFT_SERIAL_PIN D0 // or D1, D2, D3, E6
54```
55
563. On ARM platforms you must turn on ChibiOS `PAL_USE_CALLBACKS` feature:
57
58* In `halconf.h` add the line `#define PAL_USE_CALLBACKS TRUE`.
59
60<hr>
61
62## USART Half-duplex
63
64Targeting ARM boards based on ChibiOS, where communication is offloaded to a USART hardware device that supports Half-duplex operation. The advantages over bitbanging are fast, accurate timings and reduced CPU usage. Therefore it is advised to choose Half-duplex over Bitbang if MCU is capable of utilising Half-duplex, and Full-duplex can't be used instead (e.g. lack of available GPIO pins, or imcompatible PCB design).
65
66### Pin configuration
67
68```
69 LEFT RIGHT
70+-------+ | | +-------+
71| | R R | |
72| | | SERIAL | | |
73| TX |-----------------| TX |
74| | VDD | |
75| |-----------------| |
76| | GND | |
77| |-----------------| |
78+-------+ +-------+
79```
80
81Only one GPIO pin is needed for the Half-duplex driver, as only one wire is used for receiving and transmitting data. This pin is referred to as the `SERIAL_USART_TX_PIN` in the configuration. Ensure that the pin chosen for split communication can operate as the TX pin of the contoller's USART peripheral. A TRS or USB cable provides enough conductors for this driver to function. As the split connection is configured to operate in open-drain mode, an **external pull-up resistor is needed to keep the line high**. Resistor values of 1.5kΩ to 8.2kΩ are known to work.
82
83::: warning
84***Note:*** A pull-up resistor isn't required for RP2040 controllers configured with PIO subsystem.
85:::
86
87### Setup
88
89To use the Half-duplex driver follow these steps to activate it. If you target the Raspberry Pi RP2040 PIO implementation, start at step 2.
90
911. Change the `SERIAL_DRIVER` to `usart` in your keyboards `rules.mk` file:
92
93```make
94SERIAL_DRIVER = usart
95```
96
97Skip to step 3.
98
992. (RP2040 + PIO only!) Change the `SERIAL_DRIVER` to `vendor` in your keyboards `rules.mk` file:
100
101```make
102SERIAL_DRIVER = vendor
103```
104
1053. Configure the hardware of your keyboard via the `config.h` file:
106
107```c
108#define SERIAL_USART_TX_PIN B6 // The GPIO pin that is used split communication.
109```
110
111For STM32 MCUs several GPIO configuration options can be changed as well. See the section ["Alternate Functions for selected STM32 MCUs"](#alternate-functions-for-selected-stm32-mcus).
112
113```c
114#define USART1_REMAP // Remap USART TX and RX pins on STM32F103 MCUs, see table below.
115#define SERIAL_USART_TX_PAL_MODE 7 // Pin "alternate function", see the respective datasheet for the appropriate values for your MCU. default: 7
116```
117
1184. Decide either for `SERIAL`, `SIO`, or `PIO` subsystem. See section ["Choosing a driver subsystem"](#choosing-a-driver-subsystem).
119
120<hr>
121
122## USART Full-duplex
123
124Targeting ARM boards based on ChibiOS where communication is offloaded to an USART hardware device. The advantages over bitbanging are fast, accurate timings and reduced CPU usage; therefore it is advised to choose this driver over all others where possible. Due to its internal design Full-duplex is slightly more efficient than the Half-duplex driver, but Full-duplex should be primarily chosen if Half-duplex operation is not supported by the controller's USART peripheral.
125
126### Pin configuration
127
128```
129 LEFT RIGHT
130+-------+ +-------+
131| | SERIAL | |
132| TX |-----------------| RX |
133| | SERIAL | |
134| RX |-----------------| TX |
135| | VDD | |
136| |-----------------| |
137| | GND | |
138| |-----------------| |
139+-------+ +-------+
140```
141
142Two GPIO pins are needed for the Full-duplex driver, as two distinct wires are used for receiving and transmitting data. The pin transmitting data is the `TX` pin and refereed to as the `SERIAL_USART_TX_PIN`, the pin receiving data is the `RX` pin and refereed to as the `SERIAL_USART_RX_PIN` in this configuration. Please note that `TX` pin of the master half has to be connected with the `RX` pin of the slave half and the `RX` pin of the master half has to be connected with the `TX` pin of the slave half! Usually this pin swap has to be done outside of the MCU e.g. with cables or on the PCB. Some MCUs like the STM32F303 used on the Proton-C allow this pin swap directly inside the MCU. A TRRS or USB cable provides enough conductors for this driver to function.
143
144To use this driver the USART peripherals `TX` and `RX` pins must be configured with the correct Alternate-functions. If you are using a Proton-C development board everything is already setup, same is true for STM32F103 MCUs. For MCUs which are using a modern flexible GPIO configuration you have to specify these by setting `SERIAL_USART_TX_PAL_MODE` and `SERIAL_USART_RX_PAL_MODE`. Refer to the corresponding datasheets of your MCU or find those settings in the section ["Alternate Functions for selected STM32 MCUs"](#alternate-functions-for-selected-stm32-mcus).
145
146### Setup
147
148To use the Full-duplex driver follow these steps to activate it. If you target the Raspberry Pi RP2040 PIO implementation, start at step 2
149
1501. Change the `SERIAL_DRIVER` to `usart` in your keyboards `rules.mk` file:
151
152```make
153SERIAL_DRIVER = usart
154```
155
156Skip to step 3
157
1582. (RP2040 + PIO only!) Change the `SERIAL_DRIVER` to `vendor` in your keyboards `rules.mk` file:
159
160```make
161SERIAL_DRIVER = vendor
162```
163
1643. Configure the hardware of your keyboard via the `config.h` file:
165
166```c
167#define SERIAL_USART_FULL_DUPLEX // Enable full duplex operation mode.
168#define SERIAL_USART_TX_PIN B6 // USART TX pin
169#define SERIAL_USART_RX_PIN B7 // USART RX pin
170```
171
172For STM32 MCUs several GPIO configuration options, including the ability for `TX` to `RX` pin swapping, can be changed as well. See the section ["Alternate Functions for selected STM32 MCUs"](#alternate-functions-for-selected-stm32-mcus).
173
174```c
175#define SERIAL_USART_PIN_SWAP // Swap TX and RX pins if keyboard is master halve. (Only available on some MCUs)
176#define USART1_REMAP // Remap USART TX and RX pins on STM32F103 MCUs, see table below.
177#define SERIAL_USART_TX_PAL_MODE 7 // Pin "alternate function", see the respective datasheet for the appropriate values for your MCU. default: 7
178```
179
1804. Decide either for `SERIAL`, `SIO`, or `PIO` subsystem. See section ["Choosing a driver subsystem"](#choosing-a-driver-subsystem).
181
182<hr>
183
184## Choosing a driver subsystem
185
186### The `SERIAL` driver
187
188The `SERIAL` Subsystem is supported for the majority of ChibiOS MCUs and should be used whenever supported. Follow these steps in order to activate it:
189
1901. In your keyboards `halconf.h` add:
191
192```c
193#define HAL_USE_SERIAL TRUE
194```
195
1962. In your keyboards `mcuconf.h`: activate the USART peripheral that is used on your MCU. The shown example is for an STM32 MCU, so this will not work on MCUs by other manufacturers. You can find the correct names in the `mcuconf.h` files of your MCU that ship with ChibiOS.
197
198Just below `#include_next <mcuconf.h>` add:
199
200```c
201#include_next <mcuconf.h>
202
203#undef STM32_SERIAL_USE_USARTn
204#define STM32_SERIAL_USE_USARTn TRUE
205```
206
207Where 'n' matches the peripheral number of your selected USART on the MCU.
208
2093. In you keyboards `config.h`: override the default USART `SERIAL` driver if you use a USART peripheral that does not belong to the default selected `SD1` driver. For instance, if you selected `STM32_SERIAL_USE_USART3` the matching driver would be `SD3`.
210
211```c
212 #define SERIAL_USART_DRIVER SD3
213 ```
214
215### The `SIO` driver
216
217The `SIO` Subsystem was added to ChibiOS with the 21.11 release and is only supported on selected MCUs. It should only be chosen when the `SERIAL` subsystem is not supported by your MCU.
218
219Follow these steps in order to activate it:
220
2211. In your keyboards `halconf.h` add:
222
223```c
224#define HAL_USE_SIO TRUE
225```
226
2272. In your keyboards `mcuconf.h:` activate the USART peripheral that is used on your MCU. The shown example is for an STM32 MCU, so this will not work on MCUs by other manufacturers. You can find the correct names in the `mcuconf.h` files of your MCU that ship with ChibiOS.
228
229Just below `#include_next <mcuconf.h>` add:
230
231```c
232#include_next <mcuconf.h>
233
234#undef STM32_SIO_USE_USARTn
235#define STM32_SIO_USE_USARTn TRUE
236```
237
238Where 'n' matches the peripheral number of your selected USART on the MCU.
239
2403. In the keyboard's `config.h` file: override the default USART `SIO` driver if you use a USART peripheral that does not belong to the default selected `SIOD1` driver. For instance, if you selected `STM32_SERIAL_USE_USART3` the matching driver would be `SIOD3`.
241
242```c
243 #define SERIAL_USART_DRIVER SIOD3
244 ```
245
246### The `PIO` driver
247
248The `PIO` subsystem is a Raspberry Pi RP2040 specific implementation, using an integrated PIO peripheral and is therefore only available on this MCU. Because of the flexible nature of PIO peripherals, **any** GPIO pin can be used as a `TX` or `RX` pin. Half-duplex and Full-duplex operation modes are fully supported with this driver. Half-duplex uses the built-in pull-ups and GPIO manipulation of the RP2040 to drive the line high by default, thus an external pull-up resistor **is not required**.
249
250Optionally, the PIO peripheral utilized for split communication can be changed with the following define in config.h:
251```c
252#define SERIAL_PIO_USE_PIO1 // Force the usage of PIO1 peripheral, by default the Serial implementation uses the PIO0 peripheral
253```
254
255The Serial PIO program uses 2 state machines, 13 instructions and the complete interrupt handler of the PIO peripheral it is running on.
256
257<hr>
258
259## Advanced Configuration
260
261There are several advanced configuration options that can be defined in your keyboards `config.h` file:
262
263### Baudrate
264
265If you're having issues or need a higher baudrate with serial communication, you can change the baudrate which in turn controls the communication speed for serial. You want to lower the baudrate if you experience failed transactions.
266
267```c
268#define SELECT_SOFT_SERIAL_SPEED {#}
269```
270
271| Speed | Bitbang | Half-duplex and Full-duplex |
272| ----- | -------------------------- | --------------------------- |
273| `0` | 189000 baud (experimental) | 460800 baud |
274| `1` | 137000 baud (default) | 230400 baud (default) |
275| `2` | 75000 baud | 115200 baud |
276| `3` | 39000 baud | 57600 baud |
277| `4` | 26000 baud | 38400 baud |
278| `5` | 20000 baud | 19200 baud |
279
280Alternatively you can specify the baudrate directly by defining `SERIAL_USART_SPEED`.
281
282### Timeout
283
284This is the default time window in milliseconds in which a successful communication has to complete. Usually you don't want to change this value. But you can do so anyways by defining an alternate one in your keyboards `config.h` file:
285
286```c
287#define SERIAL_USART_TIMEOUT 20 // USART driver timeout. default 20
288```
289
290<hr>
291
292## Troubleshooting
293
294If you're having issues withe serial communication, you can enable debug messages that will give you insights which part of the communication failed. The enable these messages add to your keyboards `config.h` file:
295
296```c
297#define SERIAL_DEBUG
298```
299
300::: tip
301The messages will be printed out to the `CONSOLE` output. For additional information, refer to [Debugging/Troubleshooting QMK](../faq_debug).
302:::
303
304## Alternate Functions for selected STM32 MCUs
305
306Pins for USART Peripherals with
307
308### STM32F303 / Proton-C [Datasheet](https://www.st.com/resource/en/datasheet/stm32f303cc.pdf)
309
310Pin Swap available: :heavy_check_mark:
311
312| Pin | Function | Mode |
313| ---------- | -------- | ---- |
314| **USART1** | | |
315| PA9 | TX | AF7 |
316| PA10 | RX | AF7 |
317| PB6 | TX | AF7 |
318| PB7 | RX | AF7 |
319| PC4 | TX | AF7 |
320| PC5 | RX | AF7 |
321| PE0 | TX | AF7 |
322| PE1 | RX | AF7 |
323| **USART2** | | |
324| PA2 | TX | AF7 |
325| PA3 | RX | AF7 |
326| PA14 | TX | AF7 |
327| PA15 | RX | AF7 |
328| PB3 | TX | AF7 |
329| PB4 | RX | AF7 |
330| PD5 | TX | AF7 |
331| PD6 | RX | AF7 |
332| **USART3** | | |
333| PB10 | TX | AF7 |
334| PB11 | RX | AF7 |
335| PC10 | TX | AF7 |
336| PC11 | RX | AF7 |
337| PD8 | TX | AF7 |
338| PD9 | RX | AF7 |
339
340### STM32F072 [Datasheet](https://www.st.com/resource/en/datasheet/stm32f072c8.pdf)
341
342Pin Swap available: :heavy_check_mark:
343
344| Pin | Function | Mode |
345| ------ | -------- | ---- |
346| USART1 | | |
347| PA9 | TX | AF1 |
348| PA10 | RX | AF1 |
349| PB6 | TX | AF0 |
350| PB7 | RX | AF0 |
351| USART2 | | |
352| PA2 | TX | AF1 |
353| PA3 | RX | AF1 |
354| PA14 | TX | AF1 |
355| PA15 | RX | AF1 |
356| USART3 | | |
357| PB10 | TX | AF4 |
358| PB11 | RX | AF4 |
359| PC4 | TX | AF1 |
360| PC5 | RX | AF1 |
361| PC10 | TX | AF1 |
362| PC11 | RX | AF1 |
363| PD8 | TX | AF0 |
364| PD9 | RX | AF0 |
365| USART4 | | |
366| PA0 | TX | AF4 |
367| PA1 | RX | AF4 |
368
369### STM32F103 Medium Density (C8-CB) [Datasheet](https://www.st.com/resource/en/datasheet/stm32f103c8.pdf)
370
371Pin Swap available: N/A
372
373TX Pin is always Alternate Function Push-Pull, RX Pin is always regular input pin for any USART peripheral. **For STM32F103 no additional Alternate Function configuration is necessary. QMK is already configured.**
374
375Pin remapping:
376
377The pins of USART Peripherals use default Pins that can be remapped to use other pins using the AFIO registers. Default pins are marked **bold**. Add the appropriate defines to your config.h file.
378
379| Pin | Function | Mode | USART_REMAP |
380| ---------- | -------- | ---- | ------------------- |
381| **USART1** | | | |
382| **PA9** | TX | AFPP | |
383| **PA10** | RX | IN | |
384| PB6 | TX | AFPP | USART1_REMAP |
385| PB7 | RX | IN | USART1_REMAP |
386| **USART2** | | | |
387| **PA2** | TX | AFPP | |
388| **PA3** | RX | IN | |
389| PD5 | TX | AFPP | USART2_REMAP |
390| PD6 | RX | IN | USART2_REMAP |
391| **USART3** | | | |
392| **PB10** | TX | AFPP | |
393| **PB11** | RX | IN | |
394| PC10 | TX | AFPP | USART3_PARTIALREMAP |
395| PC11 | RX | IN | USART3_PARTIALREMAP |
396| PD8 | TX | AFPP | USART3_FULLREMAP |
397| PD9 | RX | IN | USART3_FULLREMAP |
diff --git a/docs/drivers/spi.md b/docs/drivers/spi.md
new file mode 100644
index 0000000000..ddc35de851
--- /dev/null
+++ b/docs/drivers/spi.md
@@ -0,0 +1,167 @@
1# SPI Master Driver {#spi-master-driver}
2
3The SPI Master drivers used in QMK have a set of common functions to allow portability between MCUs.
4
5## Usage {#usage}
6
7In most cases, the SPI Master driver code is automatically included if you are using a feature or driver which requires it, such as [OLED](../features/oled_driver).
8
9However, if you need to use the driver standalone, add the following to your `rules.mk`:
10
11```make
12SPI_DRIVER_REQUIRED = yes
13```
14
15You can then call the SPI API by including `spi_master.h` in your code.
16
17## AVR Configuration {#avr-configuration}
18
19No special setup is required - just connect the `SS`, `SCK`, `MOSI` and `MISO` pins of your SPI devices to the matching pins on the MCU:
20
21|MCU |`SS`|`SCK`|`MOSI`|`MISO`|
22|-----------------|----|-----|------|------|
23|ATmega16/32U2/4 |`B0`|`B1` |`B2` |`B3` |
24|AT90USB64/128/162|`B0`|`B1` |`B2` |`B3` |
25|ATmega32A |`B4`|`B7` |`B5` |`B6` |
26|ATmega328/P |`B2`|`B5` |`B3` |`B4` |
27
28You may use more than one slave select pin, not just the `SS` pin. This is useful when you have multiple devices connected and need to communicate with them individually.
29`SPI_SS_PIN` can be passed to `spi_start()` to refer to `SS`.
30
31## ChibiOS/ARM Configuration {#arm-configuration}
32
33You'll need to determine which pins can be used for SPI -- as an example, STM32 parts generally have multiple SPI peripherals, labeled SPI1, SPI2, SPI3 etc.
34
35To enable SPI, modify your board's `halconf.h` to enable SPI:
36
37```c
38#define HAL_USE_SPI TRUE
39#define SPI_USE_WAIT TRUE
40#define SPI_SELECT_MODE SPI_SELECT_MODE_PAD
41```
42
43Then, modify your board's `mcuconf.h` to enable the peripheral you've chosen, for example:
44
45```c
46#undef STM32_SPI_USE_SPI2
47#define STM32_SPI_USE_SPI2 TRUE
48```
49
50Configuration-wise, you'll need to set up the peripheral as per your MCU's datasheet -- the defaults match the pins for a Proton-C, i.e. STM32F303.
51
52|`config.h` Override|Description |Default|
53|-------------------|-------------------------------------------------------------|-------|
54|`SPI_DRIVER` |SPI peripheral to use - SPI1 -> `SPID1`, SPI2 -> `SPID2` etc.|`SPID2`|
55|`SPI_SCK_PIN` |The pin to use for SCK |`B13` |
56|`SPI_SCK_PAL_MODE` |The alternate function mode for SCK |`5` |
57|`SPI_MOSI_PIN` |The pin to use for MOSI |`B15` |
58|`SPI_MOSI_PAL_MODE`|The alternate function mode for MOSI |`5` |
59|`SPI_MISO_PIN` |The pin to use for MISO |`B14` |
60|`SPI_MISO_PAL_MODE`|The alternate function mode for MISO |`5` |
61
62As per the AVR configuration, you may choose any other standard GPIO as a slave select pin, which should be supplied to `spi_start()`.
63
64If a complete SPI interface is not required, then the following can be done to disable certain SPI pins, so they don't occupy a GPIO unnecessarily:
65 - in `config.h`: `#define SPI_MISO_PIN NO_PIN`
66 - in `config.h`: `#define SPI_MOSI_PIN NO_PIN`
67 - in `mcuconf.h`: `#define SPI_SELECT_MODE SPI_SELECT_MODE_NONE`, in this case the `slavePin` argument passed to `spi_start()` may be `NO_PIN` if the slave select pin is not used.
68
69## API {#api}
70
71### `void spi_init(void)` {#api-spi-init}
72
73Initialize the SPI driver. This function must be called only once, before any of the below functions can be called.
74
75---
76
77### `bool spi_start(pin_t slavePin, bool lsbFirst, uint8_t mode, uint16_t divisor)` {#api-spi-start}
78
79Start an SPI transaction.
80
81#### Arguments {#api-spi-start-arguments}
82
83 - `pin_t slavePin`
84 The QMK pin to assert as the slave select pin, eg. `B4`.
85 - `bool lsbFirst`
86 Determines the endianness of the transmission. If `true`, the least significant bit of each byte is sent first.
87 - `uint8_t mode`
88 The SPI mode to use:
89
90 |Mode|Clock Polarity |Clock Phase |
91 |----|--------------------|-----------------------|
92 |`0` |Leading edge rising |Sample on leading edge |
93 |`1` |Leading edge rising |Sample on trailing edge|
94 |`2` |Leading edge falling|Sample on leading edge |
95 |`3` |Leading edge falling|Sample on trailing edge|
96
97 - `uint16_t divisor`
98 The SPI clock divisor, will be rounded up to the nearest power of two. This number can be calculated by dividing the MCU's clock speed by the desired SPI clock speed. For example, an MCU running at 8 MHz wanting to talk to an SPI device at 4 MHz would set the divisor to `2`.
99
100#### Return Value {#api-spi-start-return}
101
102`false` if the supplied parameters are invalid or the SPI peripheral is already in use, or `true`.
103
104---
105
106### `spi_status_t spi_write(uint8_t data)` {#api-spi-write}
107
108Write a byte to the selected SPI device.
109
110#### Arguments {#api-spi-write-arguments}
111
112 - `uint8_t data`
113 The byte to write.
114
115#### Return Value {#api-spi-write-return}
116
117`SPI_STATUS_TIMEOUT` if the timeout period elapses, or `SPI_STATUS_SUCCESS`.
118
119---
120
121### `spi_status_t spi_read(void)` {#api-spi-read}
122
123Read a byte from the selected SPI device.
124
125#### Return Value {#api-spi-read-return}
126
127`SPI_STATUS_TIMEOUT` if the timeout period elapses, or the byte read from the device.
128
129---
130
131### `spi_status_t spi_transmit(const uint8_t *data, uint16_t length)` {#api-spi-transmit}
132
133Send multiple bytes to the selected SPI device.
134
135#### Arguments {#api-spi-transmit-arguments}
136
137 - `const uint8_t *data`
138 A pointer to the data to write from.
139 - `uint16_t length`
140 The number of bytes to write. Take care not to overrun the length of `data`.
141
142#### Return Value {#api-spi-transmit-return}
143
144`SPI_STATUS_TIMEOUT` if the timeout period elapses, `SPI_STATUS_ERROR` if some other error occurs, otherwise `SPI_STATUS_SUCCESS`.
145
146---
147
148### `spi_status_t spi_receive(uint8_t *data, uint16_t length)` {#api-spi-receive}
149
150Receive multiple bytes from the selected SPI device.
151
152#### Arguments {#api-spi-receive-arguments}
153
154 - `uint8_t *data`
155 A pointer to the buffer to read into.
156 - `uint16_t length`
157 The number of bytes to read. Take care not to overrun the length of `data`.
158
159#### Return Value {#api-spi-receive-return}
160
161`SPI_STATUS_TIMEOUT` if the timeout period elapses, `SPI_STATUS_ERROR` if some other error occurs, otherwise `SPI_STATUS_SUCCESS`.
162
163---
164
165### `void spi_stop(void)` {#api-spi-stop}
166
167End the current SPI transaction. This will deassert the slave select pin and reset the endianness, mode and divisor configured by `spi_start()`.
diff --git a/docs/drivers/uart.md b/docs/drivers/uart.md
new file mode 100644
index 0000000000..23f5b3d6e4
--- /dev/null
+++ b/docs/drivers/uart.md
@@ -0,0 +1,122 @@
1# UART Driver {#uart-driver}
2
3The UART drivers used in QMK have a set of common functions to allow portability between MCUs.
4
5Currently, this driver does not support enabling hardware flow control (the `RTS` and `CTS` pins) if available, but may do so in future.
6
7## Usage {#usage}
8
9In most cases, the UART driver code is automatically included if you are using a feature or driver which requires it.
10
11However, if you need to use the driver standalone, add the following to your `rules.mk`:
12
13```make
14UART_DRIVER_REQUIRED = yes
15```
16
17You can then call the UART API by including `uart.h` in your code.
18
19## AVR Configuration {#avr-configuration}
20
21No special setup is required - just connect the `RX` and `TX` pins of your UART device to the opposite pins on the MCU:
22
23|MCU |`TX`|`RX`|`CTS`|`RTS`|
24|-------------|----|----|-----|-----|
25|ATmega16/32U2|`D3`|`D2`|`D7` |`D6` |
26|ATmega16/32U4|`D3`|`D2`|`D5` |`B7` |
27|AT90USB64/128|`D3`|`D2`|*n/a*|*n/a*|
28|ATmega32A |`D1`|`D0`|*n/a*|*n/a*|
29|ATmega328/P |`D1`|`D0`|*n/a*|*n/a*|
30
31## ChibiOS/ARM Configuration {#arm-configuration}
32
33You'll need to determine which pins can be used for UART -- as an example, STM32 parts generally have multiple UART peripherals, labeled USART1, USART2, USART3 etc.
34
35To enable UART, modify your board's `mcuconf.h` to enable the peripheral you've chosen, for example:
36
37```c
38#undef STM32_SERIAL_USE_USART2
39#define STM32_SERIAL_USE_USART2 TRUE
40```
41
42Configuration-wise, you'll need to set up the peripheral as per your MCU's datasheet -- the defaults match the pins for a Proton-C, i.e. STM32F303.
43
44| `config.h` override | Description | Default Value |
45| --------------------------- | --------------------------------------------------------------- | ------------- |
46| `#define UART_DRIVER` | USART peripheral to use - USART1 -> `SD1`, USART2 -> `SD2` etc. | `SD1` |
47| `#define UART_TX_PIN` | The pin to use for TX | `A9` |
48| `#define UART_TX_PAL_MODE` | The alternate function mode for TX | `7` |
49| `#define UART_RX_PIN` | The pin to use for RX | `A10` |
50| `#define UART_RX_PAL_MODE` | The alternate function mode for RX | `7` |
51| `#define UART_CTS_PIN` | The pin to use for CTS | `A11` |
52| `#define UART_CTS_PAL_MODE` | The alternate function mode for CTS | `7` |
53| `#define UART_RTS_PIN` | The pin to use for RTS | `A12` |
54| `#define UART_RTS_PAL_MODE` | The alternate function mode for RTS | `7` |
55
56## API {#api}
57
58### `void uart_init(uint32_t baud)` {#api-uart-init}
59
60Initialize the UART driver. This function must be called only once, before any of the below functions can be called.
61
62#### Arguments {#api-uart-init-arguments}
63
64 - `uint32_t baud`
65 The baud rate to transmit and receive at. This may depend on the device you are communicating with. Common values are 1200, 2400, 4800, 9600, 19200, 38400, 57600, and 115200.
66
67---
68
69### `void uart_write(uint8_t data)` {#api-uart-write}
70
71Transmit a single byte.
72
73#### Arguments {#api-uart-write-arguments}
74
75 - `uint8_t data`
76 The byte to write.
77
78---
79
80### `uint8_t uart_read(void)` {#api-uart-read}
81
82Receive a single byte.
83
84#### Return Value {#api-uart-read-return}
85
86The byte read from the receive buffer. This function will block if the buffer is empty (ie. no data to read).
87
88---
89
90### `void uart_transmit(const uint8_t *data, uint16_t length)` {#api-uart-transmit}
91
92Transmit multiple bytes.
93
94#### Arguments {#api-uart-transmit-arguments}
95
96 - `const uint8_t *data`
97 A pointer to the data to write from.
98 - `uint16_t length`
99 The number of bytes to write. Take care not to overrun the length of `data`.
100
101---
102
103### `void uart_receive(char *data, uint16_t length)` {#api-uart-receive}
104
105Receive multiple bytes.
106
107#### Arguments {#api-uart-receive-arguments}
108
109 - `uint8_t *data`
110 A pointer to the buffer to read into.
111 - `uint16_t length`
112 The number of bytes to read. Take care not to overrun the length of `data`.
113
114---
115
116### `bool uart_available(void)` {#api-uart-available}
117
118Return whether the receive buffer contains data. Call this function to determine if `uart_read()` will return data immediately.
119
120#### Return Value {#api-uart-available-return}
121
122`true` if the receive buffer length is non-zero.
diff --git a/docs/drivers/ws2812.md b/docs/drivers/ws2812.md
new file mode 100644
index 0000000000..61addf1917
--- /dev/null
+++ b/docs/drivers/ws2812.md
@@ -0,0 +1,253 @@
1# WS2812 Driver {#ws2812-driver}
2
3This driver provides support for WorldSemi addressable RGB(W) LEDs, and compatible equivalents:
4
5 * WS2811, WS2812, WS2812B, WS2812C, etc.
6 * SK6812, SK6812MINI, SK6805
7
8These LEDs are often called "addressable" because instead of using a wire per color (and per LED), each LED contains a small microchip that understands a special protocol sent over a single wire.
9The LEDs can be chained together, and the remaining data is passed on to the next. In this way, you can easily control the color of many LEDs using a single GPIO.
10
11## Usage {#usage}
12
13In most cases, the WS2812 driver code is automatically included if you are using either the [RGBLight](../features/rgblight) or [RGB Matrix](../features/rgb_matrix) feature with the `ws2812` driver set, and you would use those APIs instead.
14
15However, if you need to use the driver standalone, add the following to your `rules.mk`:
16
17```make
18WS2812_DRIVER_REQUIRED = yes
19```
20
21You can then call the WS2812 API by including `ws2812.h` in your code.
22
23## Basic Configuration {#basic-configuration}
24
25Add the following to your `config.h`:
26
27|Define |Default |Description |
28|-------------------|-----------------------|------------------------------------------------------------------------------------------------|
29|`WS2812_DI_PIN` |*Not defined* |The GPIO pin connected to the DI pin of the first LED in the chain |
30|`WS2812_LED_COUNT` |*Not defined* |Number of LEDs in the WS2812 chain - automatically set when RGBLight or RGB Matrix is configured|
31|`WS2812_TIMING` |`1250` |The total length of a bit (TH+TL) in nanoseconds |
32|`WS2812_T1H` |`900` |The length of a "1" bit's high phase in nanoseconds |
33|`WS2812_T0H` |`350` |The length of a "0" bit's high phase in nanoseconds |
34|`WS2812_TRST_US` |`280` |The length of the reset phase in microseconds |
35|`WS2812_BYTE_ORDER`|`WS2812_BYTE_ORDER_GRB`|The byte order of the RGB data |
36|`WS2812_RGBW` |*Not defined* |Enables RGBW support (except `i2c` driver) |
37
38### Timing Adjustment {#timing-adjustment}
39
40The WS2812 LED communication protocol works by encoding a "1" bit with a long high pulse (T<sub>1</sub>H), and a "0" bit with a shorter pulse (T<sub>0</sub>H). The total cycle length of a bit is the same.
41The "reset" pulse (T<sub>RST</sub>) latches the sent RGB data to all of the LEDs and denotes a completed "frame".
42
43Some WS2812 variants have slightly different timing parameter requirements, which can be accounted for if necessary using the above `#define`s in your `config.h`.
44
45### Byte Order {#byte-order}
46
47Some WS2812 variants may have their color components in a different physical or logical order. For example, the WS2812B-2020 has physically swapped red and green LEDs, which causes the wrong color to be displayed, because the default order of the bytes sent over the wire is defined as GRB.
48If you find your LED colors are consistently swapped, you may need to change the byte order by adding the following to your `config.h`:
49
50```c
51#define WS2812_BYTE_ORDER WS2812_BYTE_ORDER_GRB
52```
53
54Where the byte order may be one of:
55
56|Byte Order|Known Devices |
57|----------|----------------------------|
58|`GRB` |Most WS2812s, SK6812, SK6805|
59|`RGB` |WS2812B-2020 |
60|`BGR` |TM1812 |
61
62### RGBW Support {#rgbw-support}
63
64Rendering the color white with RGB LEDs is typically inconsistent due to inherent variations between each individual LED die. However, some WS2812 variants (such as SK6812RGBW) also possess a white LED along with the red, green, and blue channels, which allows for a more accurate white to be displayed.
65
66QMK can automatically convert the RGB data to be sent to the LEDs to mix in the white channel:
67
68```
69w = min(r, g, b)
70r -= w
71g -= w
72b -= w
73```
74
75Thus, an RGB triplet of `255,255,255` will simply turn on the white LED fully (`0,0,0,255`).
76
77To enable RGBW conversion, add the following to your `config.h`:
78
79```c
80#define WS2812_RGBW
81```
82
83## Driver Configuration {#driver-configuration}
84
85Driver selection can be configured in `rules.mk` as `WS2812_DRIVER`, or in `info.json` as `ws2812.driver`. Valid values are `bitbang` (default), `i2c`, `spi`, `pwm`, `vendor`, or `custom`. See below for information on individual drivers.
86
87### Bitbang Driver {#bitbang-driver}
88
89This is the default WS2812 driver. It operates by "bit-banging" ie. directly toggling the GPIO.
90
91Please note that on AVR devices, due to the tight timing requirements longer chains and/or heavy CPU loads may cause visible lag. Unfortunately this driver is usually the only option for AVR.
92
93```make
94WS2812_DRIVER = bitbang
95```
96
97### I2C Driver {#i2c-driver}
98
99A specialized driver mainly used for PS2AVRGB (Bootmapper Client) boards, which possess an ATtiny85 that handles the WS2812 LEDs.
100
101```make
102WS2812_DRIVER = i2c
103```
104
105The following `#define`s apply only to the `i2c` driver:
106
107|Define |Default|Description |
108|--------------------|-------|---------------------------------|
109|`WS2812_I2C_ADDRESS`|`0xB0` |The I2C address of the ATtiny85. |
110|`WS2812_I2C_TIMEOUT`|`100` |The I2C timeout, in milliseconds.|
111
112### PIO Driver {#pio-driver}
113
114This driver is RP2040-only, and leverages the onboard PIO (programmable I/O) system and DMA to offload processing from the CPU.
115
116The WS2812 PIO program uses one state machine, six instructions and one DMA interrupt handler callback. Due to the implementation the time resolution for this driver is 50 ns - any value not specified in this interval will be rounded to the next matching interval.
117
118```make
119WS2812_DRIVER = vendor
120```
121
122### PWM Driver {#pwm-driver}
123
124This driver is ARM-only, and leverages the onboard PWM peripheral and DMA to offload processing from the CPU.
125
126```make
127WS2812_DRIVER = pwm
128```
129
130### SPI Driver {#spi-driver}
131
132This driver is ARM-only, and leverages the onboard SPI peripheral and DMA to offload processing from the CPU. The DI pin **must** be connected to the MOSI pin on the MCU, and all other SPI pins **must** be left unused. This is also very dependent on your MCU's SPI peripheral clock speed, and may or may not be possible depending on the MCU selected.
133
134```make
135WS2812_DRIVER = spi
136```
137
138## ChibiOS/ARM Configuration {#arm-configuration}
139
140The following defines apply only to ARM devices:
141
142|Define |Default |Description |
143|------------|------------------------------|---------------------------------------------------------------------------------|
144|`WS2812_T1L`|`(WS2812_TIMING - WS2812_T1H)`|The length of a "1" bit's low phase in nanoseconds (bitbang and PIO drivers only)|
145|`WS2812_T0L`|`(WS2812_TIMING - WS2812_T0H)`|The length of a "0" bit's low phase in nanoseconds (bitbang and PIO drivers only)|
146
147### Push-Pull and Open Drain {#push-pull-open-drain}
148
149By default, the GPIO used for data transmission is configured as a *push-pull* output, meaning the pin is effectively always driven either to VCC or to ground.
150
151For situations where the logic level voltage is lower than the power supply voltage, however, this can pose an issue. The solution is to configure the pin for *open drain* mode instead, and use a pullup resistor between the DI pin and VCC. In this mode, the MCU can only pull the GPIO *low*, or leave it floating. The pullup resistor is then responsible for pulling the line high, when the MCU is not driving the GPIO.
152
153To configure the DI pin for open drain configuration, add the following to your `config.h`:
154
155```c
156#define WS2812_EXTERNAL_PULLUP
157```
158
159### SPI Driver {#arm-spi-driver}
160
161Depending on the ChibiOS board configuration, you may need to enable SPI at the keyboard level. For STM32, this would look like:
162
163`halconf.h`:
164```c
165#define HAL_USE_SPI TRUE
166```
167`mcuconf.h`:
168```c
169#undef STM32_SPI_USE_SPI1
170#define STM32_SPI_USE_SPI1 TRUE
171```
172
173The following `define`s apply only to the `spi` driver:
174
175|Define |Default |Description |
176|--------------------------------|-------------|-------------------------------------------------------------------------------|
177|`WS2812_SPI_DRIVER` |`SPID1` |The SPI driver to use |
178|`WS2812_SPI_MOSI_PAL_MODE` |`5` |The MOSI pin alternative function to use |
179|`WS2812_SPI_SCK_PIN` |*Not defined*|The SCK pin - required for F072 and possibly others |
180|`WS2812_SPI_SCK_PAL_MODE` |`5` |The SCK pin alternative function to use - required for F072 and possibly others|
181|`WS2812_SPI_DIVISOR` |`16` |The divisor used to adjust the baudrate |
182|`WS2812_SPI_USE_CIRCULAR_BUFFER`|*Not defined*|Enable a circular buffer for improved rendering |
183
184#### Setting the Baudrate {#arm-spi-baudrate}
185
186To adjust the SPI baudrate, you will need to derive the target baudrate from the clock tree provided by STM32CubeMX, and add the following to your `config.h`:
187
188```c
189#define WS2812_SPI_DIVISOR 16
190```
191
192Only divisors of 2, 4, 8, 16, 32, 64, 128 and 256 are supported on STM32 devices. Other MCUs may have similar constraints -- check the reference manual for your respective MCU for specifics.
193
194#### Circular Buffer {#arm-spi-circular-buffer}
195
196A circular buffer can be enabled if you experience flickering.
197
198To enable the circular buffer, add the following to your `config.h`:
199
200```c
201#define WS2812_SPI_USE_CIRCULAR_BUFFER
202```
203
204### PIO Driver {#arm-pio-driver}
205
206The following `#define`s apply only to the PIO driver:
207
208|Define |Default |Description |
209|---------------------|-------------|---------------------------------------|
210|`WS2812_PIO_USE_PIO1`|*Not defined*|Use the PIO1 peripheral instead of PIO0|
211
212### PWM Driver {#arm-pwm-driver}
213
214Depending on the ChibiOS board configuration, you may need to enable PWM at the keyboard level. For STM32, this would look like:
215
216`halconf.h`:
217```c
218#define HAL_USE_PWM TRUE
219```
220`mcuconf.h`:
221```c
222#undef STM32_PWM_USE_TIM2
223#define STM32_PWM_USE_TIM2 TRUE
224```
225
226The following `#define`s apply only to the `pwm` driver:
227
228|Define |Default |Description |
229|---------------------------------|--------------------|------------------------------------------------------------------------------------------|
230|`WS2812_PWM_DRIVER` |`PWMD2` |The PWM driver to use |
231|`WS2812_PWM_CHANNEL` |`2` |The PWM channel to use |
232|`WS2812_PWM_PAL_MODE` |`2` |The pin alternative function to use |
233|`WS2812_PWM_DMA_STREAM` |`STM32_DMA1_STREAM2`|The DMA Stream for `TIMx_UP` |
234|`WS2812_PWM_DMA_CHANNEL` |`2` |The DMA Channel for `TIMx_UP` |
235|`WS2812_PWM_DMAMUX_ID` |*Not defined* |The DMAMUX configuration for `TIMx_UP` - only required if your MCU has a DMAMUX peripheral|
236|`WS2812_PWM_COMPLEMENTARY_OUTPUT`|*Not defined* |Whether the PWM output is complementary (`TIMx_CHyN`) |
237
238::: tip
239Using a complementary timer output (`TIMx_CHyN`) is possible only for advanced-control timers (1, 8 and 20 on STM32), and the `STM32_PWM_USE_ADVANCED` option in `mcuconf.h` must be set to `TRUE`. Complementary outputs of general-purpose timers are not supported due to ChibiOS limitations.
240:::
241
242## API {#api}
243
244### `void ws2812_setleds(rgb_led_t *ledarray, uint16_t number_of_leds)` {#api-ws2812-setleds}
245
246Send RGB data to the WS2812 LED chain.
247
248#### Arguments {#api-ws2812-setleds-arguments}
249
250 - `rgb_led_t *ledarray`
251 A pointer to the LED array.
252 - `uint16_t number_of_leds`
253 The length of the LED array.