4 /* Adapted from https://github.com/gamazeps/ws2812b-chibios-SPIDMA/ */
7 # error "RGBW not supported"
10 // Define the spi your LEDs are plugged to here
12 # define WS2812_SPI SPID1
15 #ifndef WS2812_SPI_MOSI_PAL_MODE
16 # define WS2812_SPI_MOSI_PAL_MODE 5
19 #define BYTES_FOR_LED_BYTE 4
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
26 static uint8_t txbuf
[PREAMBLE_SIZE
+ DATA_SIZE
+ RESET_SIZE
] = {0};
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).
33 static uint8_t get_protocol_eq(uint8_t data
, int pos
) {
35 if (data
& (1 << (2 * (3 - pos
))))
39 if (data
& (2 << (2 * (3 - pos
))))
46 static void set_led_color_rgb(LED_TYPE color
, int pos
) {
47 uint8_t* tx_start
= &txbuf
[PREAMBLE_SIZE
];
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
);
54 void ws2812_init(void) {
55 #if defined(USE_GPIOV1)
56 palSetLineMode(RGB_DI_PIN
, PAL_MODE_STM32_ALTERNATE_PUSHPULL
);
58 palSetLineMode(RGB_DI_PIN
, PAL_MODE_ALTERNATE(WS2812_SPI_MOSI_PAL_MODE
) | PAL_STM32_OTYPE_PUSHPULL
);
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)
67 spiAcquireBus(&WS2812_SPI
); /* Acquire ownership of the bus. */
68 spiStart(&WS2812_SPI
, &spicfg
); /* Setup transfer parameters. */
69 spiSelect(&WS2812_SPI
); /* Slave Select assertion. */
72 void ws2812_setleds(LED_TYPE
* ledarray
, uint16_t leds
) {
73 static bool s_init
= false;
79 for (uint8_t i
= 0; i
< leds
; i
++) {
80 set_led_color_rgb(ledarray
[i
], i
);
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
);
88 spiStartSend(&WS2812_SPI
, sizeof(txbuf
) / sizeof(txbuf
[0]), txbuf
);