Skip to content

Commit 6f7466b

Browse files
authored
ARM WS2812 SPI config (baudrate and circular buffer) (#12216)
* initial commit * include circular buffer command * add endif * circular buffer mode * remove untrue comment * revamp and add documentation * do not allow WS2812_SPI_SYNC & CIRCULAR_BUFFER
1 parent f2715a0 commit 6f7466b

File tree

2 files changed

+59
-4
lines changed

2 files changed

+59
-4
lines changed

docs/ws2812_driver.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,25 @@ Configure the hardware via your config.h:
7777
7878
You must also turn on the SPI feature in your halconf.h and mcuconf.h
7979
80+
#### Circular Buffer Mode
81+
Some boards may flicker while in the normal buffer mode. To fix this issue, circular buffer mode may be used to rectify the issue.
82+
83+
By default, the circular buffer mode is disabled.
84+
85+
To enable this alternative buffer mode, place this into your `config.h` file:
86+
```c
87+
#define WS2812_SPI_USE_CIRCULAR_BUFFER
88+
```
89+
90+
#### Setting baudrate with divisor
91+
To adjust the baudrate at which the SPI peripheral is configured, users will need to derive the target baudrate from the clock tree provided by STM32CubeMX.
92+
93+
Only divisors of 2, 4, 8, 16, 32, 64, 128 and 256 are supported by hardware.
94+
95+
|Define |Default|Description |
96+
|--------------------|-------|-------------------------------------|
97+
|`WS2812_SPI_DIVISOR`|`16` |SPI source clock peripheral divisor |
98+
8099
#### Testing Notes
81100

82101
While not an exhaustive list, the following table provides the scenarios that have been partially validated:

drivers/chibios/ws2812_spi.c

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,37 @@
3232
# endif
3333
#endif
3434

35+
// Define SPI config speed
36+
// baudrate should target 3.2MHz
37+
// F072 fpclk = 48MHz
38+
// 48/16 = 3Mhz
39+
#if WS2812_SPI_DIVISOR == 2
40+
# define WS2812_SPI_DIVISOR (0)
41+
#elif WS2812_SPI_DIVISOR == 4
42+
# define WS2812_SPI_DIVISOR (SPI_CR1_BR_0)
43+
#elif WS2812_SPI_DIVISOR == 8
44+
# define WS2812_SPI_DIVISOR (SPI_CR1_BR_1)
45+
#elif WS2812_SPI_DIVISOR == 16 //same as default
46+
# define WS2812_SPI_DIVISOR (SPI_CR1_BR_1 | SPI_CR1_BR_0)
47+
#elif WS2812_SPI_DIVISOR == 32
48+
# define WS2812_SPI_DIVISOR (SPI_CR1_BR_2)
49+
#elif WS2812_SPI_DIVISOR == 64
50+
# define WS2812_SPI_DIVISOR (SPI_CR1_BR_2 | SPI_CR1_BR_0)
51+
#elif WS2812_SPI_DIVISOR == 128
52+
# define WS2812_SPI_DIVISOR (SPI_CR1_BR_2 | SPI_CR1_BR_1)
53+
#elif WS2812_SPI_DIVISOR == 256
54+
# define WS2812_SPI_DIVISOR (SPI_CR1_BR_2 | SPI_CR1_BR_1 | SPI_CR1_BR_0)
55+
#else
56+
# define WS2812_SPI_DIVISOR (SPI_CR1_BR_1 | SPI_CR1_BR_0) //default
57+
#endif
58+
59+
// Use SPI circular buffer
60+
#ifdef WS2812_SPI_USE_CIRCULAR_BUFFER
61+
# define WS2812_SPI_BUFFER_MODE 1 //circular buffer
62+
#else
63+
# define WS2812_SPI_BUFFER_MODE 0 //normal buffer
64+
#endif
65+
3566
#define BYTES_FOR_LED_BYTE 4
3667
#define NB_COLORS 3
3768
#define BYTES_FOR_LED (BYTES_FOR_LED_BYTE * NB_COLORS)
@@ -82,13 +113,16 @@ void ws2812_init(void) {
82113

83114
// TODO: more dynamic baudrate
84115
static const SPIConfig spicfg = {
85-
0, NULL, PAL_PORT(RGB_DI_PIN), PAL_PAD(RGB_DI_PIN),
86-
SPI_CR1_BR_1 | SPI_CR1_BR_0 // baudrate : fpclk / 8 => 1tick is 0.32us (2.25 MHz)
116+
WS2812_SPI_BUFFER_MODE, NULL, PAL_PORT(RGB_DI_PIN), PAL_PAD(RGB_DI_PIN),
117+
WS2812_SPI_DIVISOR
87118
};
88119

89120
spiAcquireBus(&WS2812_SPI); /* Acquire ownership of the bus. */
90121
spiStart(&WS2812_SPI, &spicfg); /* Setup transfer parameters. */
91122
spiSelect(&WS2812_SPI); /* Slave Select assertion. */
123+
#ifdef WS2812_SPI_USE_CIRCULAR_BUFFER
124+
spiStartSend(&WS2812_SPI, sizeof(txbuf) / sizeof(txbuf[0]), txbuf);
125+
#endif
92126
}
93127

94128
void ws2812_setleds(LED_TYPE* ledarray, uint16_t leds) {
@@ -104,9 +138,11 @@ void ws2812_setleds(LED_TYPE* ledarray, uint16_t leds) {
104138

105139
// Send async - each led takes ~0.03ms, 50 leds ~1.5ms, animations flushing faster than send will cause issues.
106140
// Instead spiSend can be used to send synchronously (or the thread logic can be added back).
107-
#ifdef WS2812_SPI_SYNC
141+
#ifndef WS2812_SPI_USE_CIRCULAR_BUFFER
142+
# ifdef WS2812_SPI_SYNC
108143
spiSend(&WS2812_SPI, sizeof(txbuf) / sizeof(txbuf[0]), txbuf);
109-
#else
144+
# else
110145
spiStartSend(&WS2812_SPI, sizeof(txbuf) / sizeof(txbuf[0]), txbuf);
146+
# endif
111147
#endif
112148
}

0 commit comments

Comments
 (0)