Browse Source

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
Xelus22 4 years ago
parent
commit
6f7466b6dd
2 changed files with 59 additions and 4 deletions
  1. 19 0
      docs/ws2812_driver.md
  2. 40 4
      drivers/chibios/ws2812_spi.c

+ 19 - 0
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:

+ 40 - 4
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
 }