36 #include "pios_config.h"
38 #if defined(PIOS_INCLUDE_WS2811)
42 #include "stm32f4xx_tim.h"
47 struct ws2811_pixel_data_s {
58 #define WS2811_DMA_BUFSIZE (6*24*2)
61 #define WS2811_MAGIC 0x31313832
69 uint32_t lame_dma_buf[1];
78 uint32_t dma_buf_0[WS2811_DMA_BUFSIZE / 4];
79 uint32_t dma_buf_1[WS2811_DMA_BUFSIZE / 4];
83 volatile uint8_t *gpio_bsrrh_address;
84 volatile uint8_t *gpio_bsrrl_address;
92 volatile bool in_progress;
94 uint8_t *pixel_data_pos;
95 uint8_t *pixel_data_end;
97 struct ws2811_pixel_data_s pixel_data[0];
107 sizeof(
struct ws2811_pixel_data_s) * max_leds);
113 dev->
magic = WS2811_MAGIC;
117 dev->pixel_data_end = (uint8_t *)(&dev->pixel_data[max_leds]);
119 dev->gpio_bsrrh_address = (
volatile uint8_t *)(&cfg->
led_gpio->BSRRH);
120 dev->gpio_bsrrl_address = (
volatile uint8_t *)(&cfg->
led_gpio->BSRRL);
132 dev->gpio_bsrrh_address++;
133 dev->gpio_bsrrl_address++;
138 for (
int i = 0;
i <
sizeof(dev->dma_buf_0)/4;
i ++) {
139 dev->dma_buf_0[
i] = (dev->gpio_bit << 8) |
140 (dev->gpio_bit << 24);
141 dev->dma_buf_1[
i] = (dev->gpio_bit << 8) |
142 (dev->gpio_bit << 24);
145 dev->lame_dma_buf[0] = (dev->gpio_bit) |
146 (dev->gpio_bit << 8) |
147 (dev->gpio_bit << 16) |
148 (dev->gpio_bit << 24);
152 GPIO_InitTypeDef gpio_cfg = {
154 .GPIO_Mode = GPIO_Mode_OUT,
155 .GPIO_Speed = GPIO_Fast_Speed,
156 .GPIO_OType = GPIO_OType_PP,
157 .GPIO_PuPd = GPIO_PuPd_NOPULL
160 GPIO_Init(cfg->
led_gpio, &gpio_cfg);
162 TIM_DeInit(cfg->
timer);
163 TIM_Cmd(cfg->
timer, DISABLE);
165 TIM_TimeBaseInit(cfg->
timer,
166 (TIM_TimeBaseInitTypeDef *) &cfg->
clock_cfg);
168 TIM_SelectOCxM(cfg->
timer, TIM_Channel_1, TIM_OCMode_Active);
169 TIM_SelectOCxM(cfg->
timer, TIM_Channel_2, TIM_OCMode_Active);
171 TIM_SetCompare4(cfg->
timer, 1);
177 TIM_ITConfig(cfg->
timer, TIM_IT_Update | TIM_IT_CC1 | TIM_IT_CC2 |
178 TIM_IT_CC3 | TIM_IT_CC4 | TIM_IT_COM | TIM_IT_Trigger |
179 TIM_IT_Break, DISABLE);
181 NVIC_Init((NVIC_InitTypeDef *)(&dev->cfg->interrupt));
183 dev->in_progress =
false;
186 GPIO_ResetBits(dev->cfg->led_gpio, dev->cfg->gpio_pin);
194 DONT_BUILD_IF((WS2811_DMA_BUFSIZE % 16) != 0, DMABufIntegralBytes);
198 static bool fill_dma_buf(uint8_t *
restrict dma_buf, uint8_t **pixel_data_ptr,
199 uint8_t *pixel_data_end, uint8_t gpio_val) {
201 uint8_t *
restrict p_d_p = *pixel_data_ptr;
203 if (p_d_p >= pixel_data_end) {
209 for (
int i = 0;
i < WS2811_DMA_BUFSIZE;
i += 16) {
210 if (p_d_p >= pixel_data_end)
break;
212 uint8_t
p = *(p_d_p++);
214 for (
int j = 0;
j < 8;
j++) {
218 dma_buf[
i +
j*2] = gpio_val;
223 dma_buf[
i +
j*2] = 0;
230 *pixel_data_ptr = p_d_p;
237 TIM_Cmd(dev->cfg->timer, DISABLE);
239 TIM_SetCounter(dev->cfg->timer, 0);
242 TIM_DMACmd(dev->cfg->timer, TIM_DMA_CC1, DISABLE);
243 TIM_DMACmd(dev->cfg->timer, TIM_DMA_CC2, DISABLE);
244 TIM_DMACmd(dev->cfg->timer, TIM_DMA_CC4, DISABLE);
246 DMA_Cmd(dev->cfg->bit_set_dma_stream, DISABLE);
247 DMA_Cmd(dev->cfg->bit_clear_dma_stream, DISABLE);
249 DMA_DeInit(dev->cfg->bit_set_dma_stream);
250 DMA_DeInit(dev->cfg->bit_clear_dma_stream);
252 DMA_InitTypeDef dma_init;
254 DMA_StructInit(&dma_init);
257 dma_init.DMA_Channel = dev->cfg->bit_set_dma_channel;
258 dma_init.DMA_PeripheralBaseAddr = (uintptr_t) dev->gpio_bsrrl_address;
259 dma_init.DMA_Memory0BaseAddr = (uintptr_t) dev->lame_dma_buf;
260 dma_init.DMA_DIR = DMA_DIR_MemoryToPeripheral;
261 dma_init.DMA_MemoryInc = DMA_MemoryInc_Disable;
262 dma_init.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;
263 dma_init.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
264 dma_init.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
265 dma_init.DMA_MemoryInc = DMA_MemoryInc_Disable;
269 dma_init.DMA_BufferSize = dev->
max_leds * 24;
270 dma_init.DMA_Mode = DMA_Mode_Normal;
271 dma_init.DMA_Priority = DMA_Priority_VeryHigh;
272 dma_init.DMA_FIFOMode = DMA_FIFOMode_Enable;
273 dma_init.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
274 dma_init.DMA_MemoryBurst = DMA_MemoryBurst_Single;
275 dma_init.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
277 DMA_Init(dev->cfg->bit_set_dma_stream, &dma_init);
281 dma_init.DMA_Channel = dev->cfg->bit_clear_dma_channel;
282 dma_init.DMA_MemoryInc = DMA_MemoryInc_Enable;
283 dma_init.DMA_PeripheralBaseAddr = (uintptr_t) dev->gpio_bsrrh_address;
284 dma_init.DMA_Memory0BaseAddr = (uintptr_t) dev->dma_buf_0;
285 dma_init.DMA_BufferSize = WS2811_DMA_BUFSIZE;
286 dma_init.DMA_Mode = DMA_Mode_Circular;
288 DMA_Init(dev->cfg->bit_clear_dma_stream, &dma_init);
289 DMA_DoubleBufferModeConfig(dev->cfg->bit_clear_dma_stream,
290 (uintptr_t) dev->dma_buf_1,
292 DMA_DoubleBufferModeCmd(dev->cfg->bit_clear_dma_stream, ENABLE);
294 DMA_ClearITPendingBit(dev->cfg->bit_clear_dma_stream,
295 dev->cfg->bit_clear_dma_tcif);
297 DMA_ITConfig(dev->cfg->bit_clear_dma_stream,
300 DMA_Cmd(dev->cfg->bit_set_dma_stream, ENABLE);
302 while (DMA_GetCmdStatus(dev->cfg->bit_set_dma_stream) == DISABLE);
304 DMA_Cmd(dev->cfg->bit_clear_dma_stream, ENABLE);
306 while (DMA_GetCmdStatus(dev->cfg->bit_clear_dma_stream) == DISABLE);
308 TIM_DMACmd(dev->cfg->timer, TIM_DMA_CC1, ENABLE);
309 TIM_DMACmd(dev->cfg->timer, TIM_DMA_CC2, ENABLE);
310 TIM_DMACmd(dev->cfg->timer, TIM_DMA_CC4, ENABLE);
312 TIM_Cmd(dev->cfg->timer, ENABLE);
319 if (dev->in_progress) {
324 dev->in_progress =
true;
328 dev->pixel_data_pos = (uint8_t *) dev->pixel_data;
331 dev->cur_buf =
false;
333 fill_dma_buf((uint8_t *) dev->dma_buf_0, &dev->pixel_data_pos,
334 dev->pixel_data_end, dev->gpio_bit);
336 dev->eof = fill_dma_buf((uint8_t *) dev->dma_buf_1, &dev->pixel_data_pos,
337 dev->pixel_data_end, dev->gpio_bit);
346 DMA_ClearITPendingBit(dev->cfg->bit_clear_dma_stream,
347 dev->cfg->bit_clear_dma_tcif);
349 if (!dev->in_progress) {
351 if (!(dev->cfg->bit_set_dma_stream->CR & (uint32_t)DMA_SxCR_EN)) {
355 TIM_Cmd(dev->cfg->timer, DISABLE);
358 GPIO_ResetBits(dev->cfg->led_gpio, dev->cfg->gpio_pin);
365 DMA_Cmd(dev->cfg->bit_set_dma_stream, DISABLE);
368 DMA_Cmd(dev->cfg->bit_clear_dma_stream, DISABLE);
374 dev->in_progress =
false;
381 dev->cur_buf = !dev->cur_buf;
386 uint8_t *buf = (uint8_t *)
387 (dev->cur_buf ? dev->dma_buf_0 : dev->dma_buf_1);
389 dev->eof = fill_dma_buf(buf, &dev->pixel_data_pos,
390 dev->pixel_data_end, dev->gpio_bit);
405 dev->pixel_data[idx] = (
struct ws2811_pixel_data_s)
406 { .r = r, .g = g, .b = b };
int PIOS_WS2811_get_num_leds(ws2811_dev_t dev)
Find out how many LEDs are configured on an interface.
Types that are specific to the STM32 peripherals.
Main PiOS header to include all the compiled in PiOS options.
#define PIOS_IRQ_Epilogue()
void * PIOS_malloc(size_t size)
int PIOS_WS2811_init(ws2811_dev_t *dev_out, const struct pios_ws2811_cfg *cfg, int max_leds)
Allocate and initialise WS2811 device.
static struct flyingpicmd_cfg_fa cfg
void PIOS_WS2811_set_all(ws2811_dev_t dev, uint8_t r, uint8_t g, uint8_t b)
Sets all LEDs to a color value.
void PIOS_WS2811_set(ws2811_dev_t dev, int idx, uint8_t r, uint8_t g, uint8_t b)
Set a given LED to a color value.
void PIOS_WS2811_dma_interrupt_handler(ws2811_dev_t dev)
Handles a DMA completion interrupt on bit_clear_dma_stream.
#define DONT_BUILD_IF(COND, MSG)
void PIOS_WS2811_trigger_update(ws2811_dev_t dev)
Trigger an update of the LED strand.
#define PIOS_IRQ_Prologue()
#define PIOS_Assert(test)
TIM_TimeBaseInitTypeDef clock_cfg
int32_t PIOS_DELAY_WaituS(uint32_t uS)