diff options
author | Joel Challis <git@zvecr.com> | 2020-03-21 05:20:04 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-03-21 16:20:04 +1100 |
commit | d96380e65496912e0f68e6531565f4b45efd1623 (patch) | |
tree | 63e903f65b4fdc44c75c7eff21e076fdb200dca7 /drivers/chibios/ws2812_spi.c | |
parent | 7e80686f1e400010a8a800cc73c4896936f337de (diff) | |
download | qmk_firmware-d96380e65496912e0f68e6531565f4b45efd1623.tar.gz qmk_firmware-d96380e65496912e0f68e6531565f4b45efd1623.zip |
Initial arm->chibios pass - simplify some platform logic (#8450)
Diffstat (limited to 'drivers/chibios/ws2812_spi.c')
-rw-r--r-- | drivers/chibios/ws2812_spi.c | 90 |
1 files changed, 90 insertions, 0 deletions
diff --git a/drivers/chibios/ws2812_spi.c b/drivers/chibios/ws2812_spi.c new file mode 100644 index 000000000..36e08e39e --- /dev/null +++ b/drivers/chibios/ws2812_spi.c | |||
@@ -0,0 +1,90 @@ | |||
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 | |||
26 | static 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 | */ | ||
33 | static 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 | |||
46 | static 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 | |||
54 | void 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 | 0, 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 | |||
72 | void 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 | } | ||