summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/ws2812_driver.md19
-rw-r--r--drivers/chibios/ws2812_spi.c44
2 files changed, 59 insertions, 4 deletions
diff --git a/docs/ws2812_driver.md b/docs/ws2812_driver.md
index fa14f02fdb..e69400364c 100644
--- a/docs/ws2812_driver.md
+++ b/docs/ws2812_driver.md
@@ -77,6 +77,25 @@ Configure the hardware via your config.h:
You must also turn on the SPI feature in your halconf.h and mcuconf.h
+#### Circular Buffer Mode
+Some boards may flicker while in the normal buffer mode. To fix this issue, circular buffer mode may be used to rectify the issue.
+
+By default, the circular buffer mode is disabled.
+
+To enable this alternative buffer mode, place this into your `config.h` file:
+```c
+#define WS2812_SPI_USE_CIRCULAR_BUFFER
+```
+
+#### Setting baudrate with divisor
+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.
+
+Only divisors of 2, 4, 8, 16, 32, 64, 128 and 256 are supported by hardware.
+
+|Define |Default|Description |
+|--------------------|-------|-------------------------------------|
+|`WS2812_SPI_DIVISOR`|`16` |SPI source clock peripheral divisor |
+
#### Testing Notes
While not an exhaustive list, the following table provides the scenarios that have been partially validated:
diff --git a/drivers/chibios/ws2812_spi.c b/drivers/chibios/ws2812_spi.c
index 89df2987b5..bc0a54acce 100644
--- a/drivers/chibios/ws2812_spi.c
+++ b/drivers/chibios/ws2812_spi.c
@@ -32,6 +32,37 @@
# endif
#endif
+// Define SPI config speed
+// baudrate should target 3.2MHz
+// F072 fpclk = 48MHz
+// 48/16 = 3Mhz
+#if WS2812_SPI_DIVISOR == 2
+# define WS2812_SPI_DIVISOR (0)
+#elif WS2812_SPI_DIVISOR == 4
+# define WS2812_SPI_DIVISOR (SPI_CR1_BR_0)
+#elif WS2812_SPI_DIVISOR == 8
+# define WS2812_SPI_DIVISOR (SPI_CR1_BR_1)
+#elif WS2812_SPI_DIVISOR == 16 //same as default
+# define WS2812_SPI_DIVISOR (SPI_CR1_BR_1 | SPI_CR1_BR_0)
+#elif WS2812_SPI_DIVISOR == 32
+# define WS2812_SPI_DIVISOR (SPI_CR1_BR_2)
+#elif WS2812_SPI_DIVISOR == 64
+# define WS2812_SPI_DIVISOR (SPI_CR1_BR_2 | SPI_CR1_BR_0)
+#elif WS2812_SPI_DIVISOR == 128
+# define WS2812_SPI_DIVISOR (SPI_CR1_BR_2 | SPI_CR1_BR_1)
+#elif WS2812_SPI_DIVISOR == 256
+# define WS2812_SPI_DIVISOR (SPI_CR1_BR_2 | SPI_CR1_BR_1 | SPI_CR1_BR_0)
+#else
+# define WS2812_SPI_DIVISOR (SPI_CR1_BR_1 | SPI_CR1_BR_0) //default
+#endif
+
+// Use SPI circular buffer
+#ifdef WS2812_SPI_USE_CIRCULAR_BUFFER
+# define WS2812_SPI_BUFFER_MODE 1 //circular buffer
+#else
+# define WS2812_SPI_BUFFER_MODE 0 //normal buffer
+#endif
+
#define BYTES_FOR_LED_BYTE 4
#define NB_COLORS 3
#define BYTES_FOR_LED (BYTES_FOR_LED_BYTE * NB_COLORS)
@@ -82,13 +113,16 @@ void ws2812_init(void) {
// TODO: more dynamic baudrate
static const SPIConfig spicfg = {
- 0, NULL, PAL_PORT(RGB_DI_PIN), PAL_PAD(RGB_DI_PIN),
- SPI_CR1_BR_1 | SPI_CR1_BR_0 // baudrate : fpclk / 8 => 1tick is 0.32us (2.25 MHz)
+ WS2812_SPI_BUFFER_MODE, NULL, PAL_PORT(RGB_DI_PIN), PAL_PAD(RGB_DI_PIN),
+ WS2812_SPI_DIVISOR
};
spiAcquireBus(&WS2812_SPI); /* Acquire ownership of the bus. */
spiStart(&WS2812_SPI, &spicfg); /* Setup transfer parameters. */
spiSelect(&WS2812_SPI); /* Slave Select assertion. */
+#ifdef WS2812_SPI_USE_CIRCULAR_BUFFER
+ spiStartSend(&WS2812_SPI, sizeof(txbuf) / sizeof(txbuf[0]), txbuf);
+#endif
}
void ws2812_setleds(LED_TYPE* ledarray, uint16_t leds) {
@@ -104,9 +138,11 @@ void ws2812_setleds(LED_TYPE* ledarray, uint16_t leds) {
// Send async - each led takes ~0.03ms, 50 leds ~1.5ms, animations flushing faster than send will cause issues.
// Instead spiSend can be used to send synchronously (or the thread logic can be added back).
-#ifdef WS2812_SPI_SYNC
+#ifndef WS2812_SPI_USE_CIRCULAR_BUFFER
+# ifdef WS2812_SPI_SYNC
spiSend(&WS2812_SPI, sizeof(txbuf) / sizeof(txbuf[0]), txbuf);
-#else
+# else
spiStartSend(&WS2812_SPI, sizeof(txbuf) / sizeof(txbuf[0]), txbuf);
+# endif
#endif
}