Skip to content

Commit

Permalink
ARM WS2812 SPI config (baudrate and circular buffer) (qmk#12216)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
Xelus22 authored and nhongooi committed Dec 5, 2021
1 parent f1c9a93 commit 541e614
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 4 deletions.
19 changes: 19 additions & 0 deletions docs/ws2812_driver.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
44 changes: 40 additions & 4 deletions drivers/chibios/ws2812_spi.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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) {
Expand All @@ -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
}

0 comments on commit 541e614

Please sign in to comment.