aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoel Challis <git@zvecr.com>2019-12-31 17:26:40 +0000
committerGitHub <noreply@github.com>2019-12-31 17:26:40 +0000
commit680ebef0869b7860017a80bd601faac61227cd28 (patch)
tree4915395331bac5952a17d9e8a2912433f4c5b916
parent7ba6456c0b2e041bb9f97dbed265c5b8b4b12192 (diff)
downloadqmk_firmware-680ebef0869b7860017a80bd601faac61227cd28.tar.gz
qmk_firmware-680ebef0869b7860017a80bd601faac61227cd28.zip
SPI DMA based RGB Underglow for STM32 (#7674)
* Initial stash of ws2812 spi driver * Update comment, add sync backup plan * Add testing notes to spi ws2812 driver * Align RGBW error messages
-rw-r--r--docs/ws2812_driver.md29
-rw-r--r--drivers/arm/ws2812_spi.c91
2 files changed, 118 insertions, 2 deletions
diff --git a/docs/ws2812_driver.md b/docs/ws2812_driver.md
index 67481c458..80b694858 100644
--- a/docs/ws2812_driver.md
+++ b/docs/ws2812_driver.md
@@ -14,7 +14,7 @@ These LEDs are called "addressable" because instead of using a wire per color, e
14|----------|--------------------|--------------------| 14|----------|--------------------|--------------------|
15| bit bang | :heavy_check_mark: | :heavy_check_mark: | 15| bit bang | :heavy_check_mark: | :heavy_check_mark: |
16| I2C | :heavy_check_mark: | | 16| I2C | :heavy_check_mark: | |
17| SPI | | Soon™ | 17| SPI | | :heavy_check_mark: |
18| PWM | | Soon™ | 18| PWM | | Soon™ |
19 19
20## Driver configuration 20## Driver configuration
@@ -40,3 +40,30 @@ Configure the hardware via your config.h:
40#define WS2812_ADDRESS 0xb0 // default: 0xb0 40#define WS2812_ADDRESS 0xb0 // default: 0xb0
41#define WS2812_TIMEOUT 100 // default: 100 41#define WS2812_TIMEOUT 100 // default: 100
42``` 42```
43
44### SPI
45Targeting STM32 boards where WS2812 support is offloaded to an SPI hardware device. The advantage is that the use of DMA offloads processing of the WS2812 protocol from the MCU. `RGB_DI_PIN` for this driver is the configured SPI MOSI pin. Due to the nature of repurposing SPI to drive the LEDs, the other SPI pins, MISO and SCK, **must** remain unused. To configure it, add this to your rules.mk:
46
47```make
48WS2812_DRIVER = spi
49```
50
51Configure the hardware via your config.h:
52```c
53#define WS2812_SPI SPID1 // default: SPID1
54#define WS2812_SPI_MOSI_PAL_MODE 5 // Pin "alternate function", see the respective datasheet for the appropriate values for your MCU. default: 5
55```
56
57You must also turn on the SPI feature in your halconf.h and mcuconf.h
58
59#### Testing Notes
60
61While not an exhaustive list, the following table provides the scenarios that have been partially validated:
62
63| | SPI1 | SPI2 | SPI3 |
64|-|-|-|-|
65| f072 | ? | B15 :heavy_check_mark: | N/A |
66| f103 | A7 :heavy_check_mark: | B15 :heavy_check_mark: | N/A |
67| f303 | A7 :heavy_check_mark: B5 :heavy_check_mark: | B15 :heavy_check_mark: | B5 :heavy_check_mark: |
68
69*Other supported ChibiOS boards and/or pins may function, it will be highly chip and configuration dependent.* \ No newline at end of file
diff --git a/drivers/arm/ws2812_spi.c b/drivers/arm/ws2812_spi.c
index 2094e5009..0e954ec50 100644
--- a/drivers/arm/ws2812_spi.c
+++ b/drivers/arm/ws2812_spi.c
@@ -1 +1,90 @@
1#error("NOT SUPPORTED") \ No newline at end of file 1#include "quantum.h"
2#include "ws2812.h"
3
4/* Adapted from https://github.com/gamazeps/ws2812b-chibios-SPIDMA/ */
5
6#ifdef RGBW
7# error "RGBW not supported"
8#endif
9
10// Define the spi your LEDs are plugged to here
11#ifndef WS2812_SPI
12# define WS2812_SPI SPID1
13#endif
14
15#ifndef WS2812_SPI_MOSI_PAL_MODE
16# define WS2812_SPI_MOSI_PAL_MODE 5
17#endif
18
19#define BYTES_FOR_LED_BYTE 4
20#define NB_COLORS 3
21#define BYTES_FOR_LED (BYTES_FOR_LED_BYTE * NB_COLORS)
22#define DATA_SIZE (BYTES_FOR_LED * RGBLED_NUM)
23#define RESET_SIZE 200
24#define PREAMBLE_SIZE 4
25
26static uint8_t txbuf[PREAMBLE_SIZE + DATA_SIZE + RESET_SIZE] = {0};
27
28/*
29 * As the trick here is to use the SPI to send a huge pattern of 0 and 1 to
30 * the ws2812b protocol, we use this helper function to translate bytes into
31 * 0s and 1s for the LED (with the appropriate timing).
32 */
33static uint8_t get_protocol_eq(uint8_t data, int pos) {
34 uint8_t eq = 0;
35 if (data & (1 << (2 * (3 - pos))))
36 eq = 0b1110;
37 else
38 eq = 0b1000;
39 if (data & (2 << (2 * (3 - pos))))
40 eq += 0b11100000;
41 else
42 eq += 0b10000000;
43 return eq;
44}
45
46static void set_led_color_rgb(LED_TYPE color, int pos) {
47 uint8_t* tx_start = &txbuf[PREAMBLE_SIZE];
48
49 for (int j = 0; j < 4; j++) tx_start[BYTES_FOR_LED * pos + j] = get_protocol_eq(color.g, j);
50 for (int j = 0; j < 4; j++) tx_start[BYTES_FOR_LED * pos + BYTES_FOR_LED_BYTE + j] = get_protocol_eq(color.r, j);
51 for (int j = 0; j < 4; j++) tx_start[BYTES_FOR_LED * pos + BYTES_FOR_LED_BYTE * 2 + j] = get_protocol_eq(color.b, j);
52}
53
54void ws2812_init(void) {
55#if defined(USE_GPIOV1)
56 palSetLineMode(RGB_DI_PIN, PAL_MODE_STM32_ALTERNATE_PUSHPULL);
57#else
58 palSetLineMode(RGB_DI_PIN, PAL_MODE_ALTERNATE(WS2812_SPI_MOSI_PAL_MODE) | PAL_STM32_OTYPE_PUSHPULL);
59#endif
60
61 // TODO: more dynamic baudrate
62 static const SPIConfig spicfg = {
63 NULL, PAL_PORT(RGB_DI_PIN), PAL_PAD(RGB_DI_PIN),
64 SPI_CR1_BR_1 | SPI_CR1_BR_0 // baudrate : fpclk / 8 => 1tick is 0.32us (2.25 MHz)
65 };
66
67 spiAcquireBus(&WS2812_SPI); /* Acquire ownership of the bus. */
68 spiStart(&WS2812_SPI, &spicfg); /* Setup transfer parameters. */
69 spiSelect(&WS2812_SPI); /* Slave Select assertion. */
70}
71
72void ws2812_setleds(LED_TYPE* ledarray, uint16_t leds) {
73 static bool s_init = false;
74 if (!s_init) {
75 ws2812_init();
76 s_init = true;
77 }
78
79 for (uint8_t i = 0; i < leds; i++) {
80 set_led_color_rgb(ledarray[i], i);
81 }
82
83 // Send async - each led takes ~0.03ms, 50 leds ~1.5ms, animations flushing faster than send will cause issues.
84 // Instead spiSend can be used to send synchronously (or the thread logic can be added back).
85#ifdef WS2812_SPI_SYNC
86 spiSend(&WS2812_SPI, sizeof(txbuf) / sizeof(txbuf[0]), txbuf);
87#else
88 spiStartSend(&WS2812_SPI, sizeof(txbuf) / sizeof(txbuf[0]), txbuf);
89#endif
90}