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_BUFFERmaster
parent
f2715a0593
commit
6f7466b6dd
|
@ -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:
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue