improve pattern generation for the SPI for the WS2812b LED
This commit is contained in:
parent
b4cda407e2
commit
e50ab14626
|
@ -34,7 +34,7 @@
|
||||||
#include <libopencmsis/core_cm3.h> // Cortex M3 utilities
|
#include <libopencmsis/core_cm3.h> // Cortex M3 utilities
|
||||||
|
|
||||||
#include "led_ws2812b.h" // LED WS2812b library API
|
#include "led_ws2812b.h" // LED WS2812b library API
|
||||||
#include "global.h" // global definitions
|
#include "global.h" // common methods
|
||||||
|
|
||||||
/** peripheral configuration */
|
/** peripheral configuration */
|
||||||
/** @defgroup led_ws2812b_spi SPI peripheral used to control the WS2812b LEDs
|
/** @defgroup led_ws2812b_spi SPI peripheral used to control the WS2812b LEDs
|
||||||
|
@ -72,12 +72,11 @@
|
||||||
* The first SPI bit is the high start of the WS2812b bit frame.
|
* The first SPI bit is the high start of the WS2812b bit frame.
|
||||||
* The second SPI bit determines if the WS2812b bit is a 0 or 1.
|
* The second SPI bit determines if the WS2812b bit is a 0 or 1.
|
||||||
* The third SPI bit is the last part of the WS2812b bit frame, which is always low.
|
* The third SPI bit is the last part of the WS2812b bit frame, which is always low.
|
||||||
* Only the first 24 bits (3*8) are used.
|
* The binary pattern is 0b100100100100100100100100
|
||||||
* The binary pattern is 0b10010010010010010010010000000000
|
|
||||||
*/
|
*/
|
||||||
#define WS2812B_SPI_TEMPLATE 0x92492400
|
#define WS2812B_SPI_TEMPLATE 0x924924
|
||||||
|
|
||||||
uint8_t ws2812b_data[WS2812B_LEDS*3*3+40*3/8] = {0}; /**< data encoded to be shifted out by SPI for the WS2812b, pulse the 50us reset */
|
uint8_t ws2812b_data[WS2812B_LEDS*3*3+40*3/8+1] = {0}; /**< data encoded to be shifted out by SPI for the WS2812b, plus the 50us reset (~40 data bits) */
|
||||||
static volatile bool transmit_flag = false; /**< flag set in software when transmission started, clear by interrupt when transmission completed */
|
static volatile bool transmit_flag = false; /**< flag set in software when transmission started, clear by interrupt when transmission completed */
|
||||||
|
|
||||||
void ws2812b_set_rgb(uint16_t led, uint8_t red, uint8_t green, uint8_t blue)
|
void ws2812b_set_rgb(uint16_t led, uint8_t red, uint8_t green, uint8_t blue)
|
||||||
|
@ -91,18 +90,18 @@ void ws2812b_set_rgb(uint16_t led, uint8_t red, uint8_t green, uint8_t blue)
|
||||||
__WFI();
|
__WFI();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t colors[] = {green, red, blue};
|
const uint8_t colors[] = {green, red, blue}; // color order for the WS2812b
|
||||||
|
const uint8_t pattern_bit[] = {0x02, 0x10, 0x80, 0x04, 0x20, 0x01, 0x08, 0x40}; // which bit to change in the pattern
|
||||||
// generate the pattern
|
const uint8_t pattern_byte[] = {2,2,2,1,1,0,0,0}; // in which byte in the pattern to write the pattern bit
|
||||||
for (uint8_t color=0; color<LENGTH(colors); color++) {
|
for (uint8_t color=0; color<LENGTH(colors); color++) { // colors are encoded similarly
|
||||||
uint32_t bits_color = WS2812B_SPI_TEMPLATE; // template to encode the bits in
|
// fill the middle bit (fixed is faster than calculating it)
|
||||||
for (uint8_t bit=0; bit<8; bit++) {
|
for (uint8_t bit=0; bit<8; bit++) { // bit from the color to set/clear
|
||||||
bits_color |= ((colors[color]>>bit)&0x1)<<(bit*3+9); // encode the data bits in the pattern
|
if (colors[color]&(1<<bit)) { // setting bit
|
||||||
|
ws2812b_data[led*3*3+color*3+pattern_byte[bit]] |= pattern_bit[bit]; // setting bit is pattern
|
||||||
|
} else { // clear bit
|
||||||
|
ws2812b_data[led*3*3+color*3+pattern_byte[bit]] &= ~pattern_bit[bit]; // clearing bit is pattern
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// store pattern
|
|
||||||
ws2812b_data[led*3*3+color*3+0] = (bits_color>>24);
|
|
||||||
ws2812b_data[led*3*3+color*3+1] = (bits_color>>16);
|
|
||||||
ws2812b_data[led*3*3+color*3+2] = (bits_color>>8);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,9 +166,15 @@ void ws2812b_setup(void)
|
||||||
dma_set_priority(WS2812B_DMA, WS2812B_DMA_CH, DMA_CCR_PL_HIGH); // set priority to high since time is crucial for the peripheral
|
dma_set_priority(WS2812B_DMA, WS2812B_DMA_CH, DMA_CCR_PL_HIGH); // set priority to high since time is crucial for the peripheral
|
||||||
nvic_enable_irq(WS2812B_DMA_IRQ); // enable interrupts for this DMA channel
|
nvic_enable_irq(WS2812B_DMA_IRQ); // enable interrupts for this DMA channel
|
||||||
|
|
||||||
// reset color
|
// fill buffer with bit pattern
|
||||||
for (uint16_t led=0; led<WS2812B_LEDS; led++) {
|
for (uint16_t i=0; i<WS2812B_LEDS*3; i++) {
|
||||||
ws2812b_set_rgb(led, 0x00, 0x00, 0x00); // switch off (set to black)
|
ws2812b_data[i*3+0] = (uint8_t)(WS2812B_SPI_TEMPLATE>>16);
|
||||||
|
ws2812b_data[i*3+1] = (uint8_t)(WS2812B_SPI_TEMPLATE>>8);
|
||||||
|
ws2812b_data[i*3+2] = (uint8_t)(WS2812B_SPI_TEMPLATE>>0);
|
||||||
|
}
|
||||||
|
// fill remaining with with 0 to encode the reset code
|
||||||
|
for (uint16_t i=WS2812B_LEDS*3*3; i<LENGTH(ws2812b_data); i++) {
|
||||||
|
ws2812b_data[i] = 0;
|
||||||
}
|
}
|
||||||
ws2812b_transmit(); // set LEDs
|
ws2812b_transmit(); // set LEDs
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue