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
This commit is contained in:
Xelus22 2021-03-19 08:29:18 +00:00 committed by GitHub
parent f2715a0593
commit 6f7466b6dd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 59 additions and 4 deletions

View File

@ -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 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 #### Testing Notes
While not an exhaustive list, the following table provides the scenarios that have been partially validated: While not an exhaustive list, the following table provides the scenarios that have been partially validated:

View File

@ -32,6 +32,37 @@
# endif # endif
#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 BYTES_FOR_LED_BYTE 4
#define NB_COLORS 3 #define NB_COLORS 3
#define BYTES_FOR_LED (BYTES_FOR_LED_BYTE * NB_COLORS) #define BYTES_FOR_LED (BYTES_FOR_LED_BYTE * NB_COLORS)
@ -82,13 +113,16 @@ void ws2812_init(void) {
// TODO: more dynamic baudrate // TODO: more dynamic baudrate
static const SPIConfig spicfg = { static const SPIConfig spicfg = {
0, NULL, PAL_PORT(RGB_DI_PIN), PAL_PAD(RGB_DI_PIN), WS2812_SPI_BUFFER_MODE, 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_DIVISOR
}; };
spiAcquireBus(&WS2812_SPI); /* Acquire ownership of the bus. */ spiAcquireBus(&WS2812_SPI); /* Acquire ownership of the bus. */
spiStart(&WS2812_SPI, &spicfg); /* Setup transfer parameters. */ spiStart(&WS2812_SPI, &spicfg); /* Setup transfer parameters. */
spiSelect(&WS2812_SPI); /* Slave Select assertion. */ 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) { 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. // 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). // 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); spiSend(&WS2812_SPI, sizeof(txbuf) / sizeof(txbuf[0]), txbuf);
#else # else
spiStartSend(&WS2812_SPI, sizeof(txbuf) / sizeof(txbuf[0]), txbuf); spiStartSend(&WS2812_SPI, sizeof(txbuf) / sizeof(txbuf[0]), txbuf);
# endif
#endif #endif
} }