dRonin  adbada4
dRonin firmware
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
pios_ws2811.c
Go to the documentation of this file.
1 
17 /*
18  * This program is free software; you can redistribute it and/or modify
19  * it under the terms of the GNU General Public License as published by
20  * the Free Software Foundation; either version 3 of the License, or
21  * (at your option) any later version.
22  *
23  * This program is distributed in the hope that it will be useful, but
24  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
25  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
26  * for more details.
27  *
28  * You should have received a copy of the GNU General Public License along
29  * with this program; if not, see <http://www.gnu.org/licenses/>
30  *
31  * Additional note on redistribution: The copyright and license notices above
32  * must be maintained in each individual source file that is a derivative work
33  * of this source file; otherwise redistribution is prohibited.
34  */
35 
36 #include "pios_config.h"
37 
38 #if defined(PIOS_INCLUDE_WS2811)
39 
40 #include "pios.h"
41 #include <pios_stm32.h>
42 #include "stm32f4xx_tim.h"
43 #include "pios_tim_priv.h"
44 
45 #include "pios_ws2811.h"
46 
47 struct ws2811_pixel_data_s {
48  uint8_t g;
49  uint8_t r;
50  uint8_t b;
51 };
52 
53 // Each DMA side is 6 LEDs, 24 bits per pixel, 2 bytes per bit, for 288
54 // bytes.
55 //
56 // This corresponds to 300us worth of pixel data on each side, or an
57 // interrupt rate of 3.33KHz.
58 #define WS2811_DMA_BUFSIZE (6*24*2)
59 
60 struct ws2811_dev_s {
61 #define WS2811_MAGIC 0x31313832 /* '2811' */
62  uint32_t magic;
63 
64  const struct pios_ws2811_cfg *cfg;
65 
66  uint16_t max_leds;
67 
68  // This gets clocked out at timer update event to BSRRH
69  uint32_t lame_dma_buf[1];
70 
71  // These are the buffers. We clock out a byte to BSRRL at each
72  // of the two times that the value can fall. Every odd value of this
73  // is always the gpio bit index. For a '0', the corresponding even
74  // value is the gpio bit index.
75  //
76  // We fill both buffers initially, and then when one has been clocked
77  // out, we fill the other half in the interrupt handler.
78  uint32_t dma_buf_0[WS2811_DMA_BUFSIZE / 4];
79  uint32_t dma_buf_1[WS2811_DMA_BUFSIZE / 4];
80 
81  // These get fixed up to point to the top half of the port halfword
82  // if necessary.
83  volatile uint8_t *gpio_bsrrh_address;
84  volatile uint8_t *gpio_bsrrl_address;
85 
86  // And this gets fixed up to be a shifted right image, etc.
87  uint8_t gpio_bit;
88 
89  bool cur_buf;
90  bool eof;
91 
92  volatile bool in_progress;
93 
94  uint8_t *pixel_data_pos;
95  uint8_t *pixel_data_end;
96 
97  struct ws2811_pixel_data_s pixel_data[0];
98 };
99 
100 int PIOS_WS2811_init(ws2811_dev_t *dev_out, const struct pios_ws2811_cfg *cfg,
101  int max_leds)
102 {
103  PIOS_Assert(max_leds > 0);
104  PIOS_Assert(max_leds <= 1024);
105 
106  ws2811_dev_t dev = PIOS_malloc(sizeof(*dev) +
107  sizeof(struct ws2811_pixel_data_s) * max_leds);
108 
109  if (!dev) {
110  return -1;
111  }
112 
113  dev->magic = WS2811_MAGIC;
114  dev->cfg = cfg;
115  dev->max_leds = max_leds;
116 
117  dev->pixel_data_end = (uint8_t *)(&dev->pixel_data[max_leds]);
118 
119  dev->gpio_bsrrh_address = (volatile uint8_t *)(&cfg->led_gpio->BSRRH);
120  dev->gpio_bsrrl_address = (volatile uint8_t *)(&cfg->led_gpio->BSRRL);
121 
122  if (cfg->gpio_pin & 0xff00) {
123  // It really should only be one bit set, but no matter
124  // what it has to be in only one byte (half of the halfword)
125  // to make sense.
126  PIOS_Assert(!(cfg->gpio_pin & 0xff));
127 
128  // Fixup --- store to a byte later (little endian), an
129  // adjusted value.
130  dev->gpio_bit = cfg->gpio_pin >> 8;
131 
132  dev->gpio_bsrrh_address++;
133  dev->gpio_bsrrl_address++;
134  } else {
135  dev->gpio_bit = cfg->gpio_pin;
136  }
137 
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);
143  }
144 
145  dev->lame_dma_buf[0] = (dev->gpio_bit) |
146  (dev->gpio_bit << 8) |
147  (dev->gpio_bit << 16) |
148  (dev->gpio_bit << 24);
149 
150  PIOS_WS2811_set_all(dev, 0, 0, 0);
151 
152  GPIO_InitTypeDef gpio_cfg = {
153  .GPIO_Pin = cfg->gpio_pin,
154  .GPIO_Mode = GPIO_Mode_OUT,
155  .GPIO_Speed = GPIO_Fast_Speed,
156  .GPIO_OType = GPIO_OType_PP,
157  .GPIO_PuPd = GPIO_PuPd_NOPULL
158  };
159 
160  GPIO_Init(cfg->led_gpio, &gpio_cfg);
161 
162  TIM_DeInit(cfg->timer);
163  TIM_Cmd(cfg->timer, DISABLE);
164 
165  TIM_TimeBaseInit(cfg->timer,
166  (TIM_TimeBaseInitTypeDef *) &cfg->clock_cfg);
167 
168  TIM_SelectOCxM(cfg->timer, TIM_Channel_1, TIM_OCMode_Active);
169  TIM_SelectOCxM(cfg->timer, TIM_Channel_2, TIM_OCMode_Active);
170 
171  TIM_SetCompare4(cfg->timer, 1);
172  TIM_SetCompare1(cfg->timer, cfg->fall_time_l);
173  TIM_SetCompare2(cfg->timer, cfg->fall_time_h);
174 
175  // Disable all timer interrupts, in case someone inited this timer
176  // before.
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);
180 
181  NVIC_Init((NVIC_InitTypeDef *)(&dev->cfg->interrupt));
182 
183  dev->in_progress = false;
184 
185  /* Drive the GPIO low, stall for 45 us */
186  GPIO_ResetBits(dev->cfg->led_gpio, dev->cfg->gpio_pin);
187  PIOS_DELAY_WaituS(45);
188 
189  *dev_out = dev;
190 
191  return 0;
192 }
193 
194 DONT_BUILD_IF((WS2811_DMA_BUFSIZE % 16) != 0, DMABufIntegralBytes);
195 
196 // Updates pixel_data_ptr to where we are. returns true if we've reached
197 // the end.
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) {
200  // Our local shadow of this, for efficient blitting.
201  uint8_t * restrict p_d_p = *pixel_data_ptr;
202 
203  if (p_d_p >= pixel_data_end) {
204  // No pixel data filled. So next interrupt we should stop
205  // timers and dmas
206  return true;
207  }
208 
209  for (int i = 0; i < WS2811_DMA_BUFSIZE; i += 16) {
210  if (p_d_p >= pixel_data_end) break;
211 
212  uint8_t p = *(p_d_p++);
213 
214  for (int j = 0; j < 8; j++) {
215  if (!(p & 0x80)) {
216  // It's zero-- therefore the pin has to fall
217  // early.
218  dma_buf[i + j*2] = gpio_val;
219  } else {
220  // It's one. Therefore we let the prefilled
221  // bit in the odd position clear it; we do
222  // nothing.
223  dma_buf[i + j*2] = 0;
224  }
225 
226  // We clock out most significant bit first.
227  p = p << 1;
228  }
229  }
230  *pixel_data_ptr = p_d_p;
231 
232  return false;
233 }
234 
235 static void ws2811_cue_dma(ws2811_dev_t dev) {
236  // ensure timer stopped
237  TIM_Cmd(dev->cfg->timer, DISABLE);
238  // and reset
239  TIM_SetCounter(dev->cfg->timer, 0);
240 
241  // and no pending DMA events
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);
245 
246  DMA_Cmd(dev->cfg->bit_set_dma_stream, DISABLE);
247  DMA_Cmd(dev->cfg->bit_clear_dma_stream, DISABLE);
248 
249  DMA_DeInit(dev->cfg->bit_set_dma_stream);
250  DMA_DeInit(dev->cfg->bit_clear_dma_stream);
251 
252  DMA_InitTypeDef dma_init;
253 
254  DMA_StructInit(&dma_init);
255 
256  /* First set up the single-buffered repeating of the BSRRL */
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;
266 
267  // Limited to 65535. In turn this limits us to 2730 LEDs before
268  // overflow. ;)
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;
276 
277  DMA_Init(dev->cfg->bit_set_dma_stream, &dma_init);
278 
279  /* Now the tricky one-- set up the double-buffered DMA, to blit to
280  * BSRRH and clear bits at the appropriate time */
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;
287 
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,
291  DMA_Memory_0);
292  DMA_DoubleBufferModeCmd(dev->cfg->bit_clear_dma_stream, ENABLE);
293 
294  DMA_ClearITPendingBit(dev->cfg->bit_clear_dma_stream,
295  dev->cfg->bit_clear_dma_tcif);
296 
297  DMA_ITConfig(dev->cfg->bit_clear_dma_stream,
298  DMA_IT_TC, ENABLE);
299 
300  DMA_Cmd(dev->cfg->bit_set_dma_stream, ENABLE);
301 
302  while (DMA_GetCmdStatus(dev->cfg->bit_set_dma_stream) == DISABLE);
303 
304  DMA_Cmd(dev->cfg->bit_clear_dma_stream, ENABLE);
305 
306  while (DMA_GetCmdStatus(dev->cfg->bit_clear_dma_stream) == DISABLE);
307 
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);
311 
312  TIM_Cmd(dev->cfg->timer, ENABLE);
313 }
314 
316 {
317  PIOS_Assert(dev->magic == WS2811_MAGIC);
318 
319  if (dev->in_progress) {
320  // XXX really need to ensure dead time here too
321  return;
322  }
323 
324  dev->in_progress = true;
325 
326  dev->eof = false;
327 
328  dev->pixel_data_pos = (uint8_t *) dev->pixel_data;
329 
330  // Current one to blit is the first
331  dev->cur_buf = false;
332 
333  fill_dma_buf((uint8_t *) dev->dma_buf_0, &dev->pixel_data_pos,
334  dev->pixel_data_end, dev->gpio_bit);
335 
336  dev->eof = fill_dma_buf((uint8_t *) dev->dma_buf_1, &dev->pixel_data_pos,
337  dev->pixel_data_end, dev->gpio_bit);
338 
339  ws2811_cue_dma(dev);
340 }
341 
343 {
345 
346  DMA_ClearITPendingBit(dev->cfg->bit_clear_dma_stream,
347  dev->cfg->bit_clear_dma_tcif);
348 
349  if (!dev->in_progress) {
350  /* OK, have we already disabled DMA? */
351  if (!(dev->cfg->bit_set_dma_stream->CR & (uint32_t)DMA_SxCR_EN)) {
352  /* If so, this is our last interrupt, disable all things
353  * and ensure GPIO is low */
354 
355  TIM_Cmd(dev->cfg->timer, DISABLE);
356 
357  // Ensure the thing rests low during this time
358  GPIO_ResetBits(dev->cfg->led_gpio, dev->cfg->gpio_pin);
359 
360  goto epilogue;
361  }
362 
363  /* Otherwise, disable DMA */
364 
365  DMA_Cmd(dev->cfg->bit_set_dma_stream, DISABLE);
366 
367  // Will generate one more transmit complete interrupt.
368  DMA_Cmd(dev->cfg->bit_clear_dma_stream, DISABLE);
369 
370  goto epilogue;
371  }
372 
373  if (dev->eof) {
374  dev->in_progress = false;
375  /* OK, we have nothing else to fill in, but the last buffer
376  * needs to get clocked out */
377 
378  goto epilogue;
379  }
380 
381  dev->cur_buf = !dev->cur_buf;
382 
383  // If cur_buf is true, we're currently blitting 1, so we should
384  // be updating 0.
385 
386  uint8_t *buf = (uint8_t *)
387  (dev->cur_buf ? dev->dma_buf_0 : dev->dma_buf_1);
388 
389  dev->eof = fill_dma_buf(buf, &dev->pixel_data_pos,
390  dev->pixel_data_end, dev->gpio_bit);
391 
392 epilogue:
394 }
395 
396 void PIOS_WS2811_set(ws2811_dev_t dev, int idx, uint8_t r, uint8_t g,
397  uint8_t b)
398 {
399  PIOS_Assert(dev->magic == WS2811_MAGIC);
400 
401  if (idx >= dev->max_leds) {
402  return;
403  }
404 
405  dev->pixel_data[idx] = (struct ws2811_pixel_data_s)
406  { .r = r, .g = g, .b = b };
407 }
408 
409 void PIOS_WS2811_set_all(ws2811_dev_t dev, uint8_t r, uint8_t g,
410  uint8_t b)
411 {
412  PIOS_Assert(dev->magic == WS2811_MAGIC);
413 
414  for (int i = 0; i < dev->max_leds; i++) {
415  PIOS_WS2811_set(dev, i, r, g, b);
416  }
417 }
418 
420 {
421  PIOS_Assert(dev->magic == WS2811_MAGIC);
422 
423  return dev->max_leds;
424 }
425 
426 #endif /* PIOS_INCLUDE_WS2811 */
int PIOS_WS2811_get_num_leds(ws2811_dev_t dev)
Find out how many LEDs are configured on an interface.
Definition: pios_ws2811.c:227
Types that are specific to the STM32 peripherals.
Main PiOS header to include all the compiled in PiOS options.
GPIO_TypeDef * led_gpio
uint32_t magic
Definition: pios_ws2811.c:53
#define PIOS_IRQ_Epilogue()
Definition: pios_irq.h:46
volatile int j
Definition: loadabletest.c:12
void * PIOS_malloc(size_t size)
Definition: pios_heap.c:125
int PIOS_WS2811_init(ws2811_dev_t *dev_out, const struct pios_ws2811_cfg *cfg, int max_leds)
Allocate and initialise WS2811 device.
Definition: pios_ws2811.c:64
static struct flyingpicmd_cfg_fa cfg
Definition: main.c:49
#define restrict
Definition: unittest.cpp:41
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.
Definition: pios_ws2811.c:219
uint8_t i
Definition: msp_messages.h:97
TIM_TypeDef * timer
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.
Definition: pios_ws2811.c:176
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)
Definition: morsel.c:206
void PIOS_WS2811_trigger_update(ws2811_dev_t dev)
Trigger an update of the LED strand.
Definition: pios_ws2811.c:197
#define PIOS_IRQ_Prologue()
Definition: pios_irq.h:45
uint8_t p
Definition: msp_messages.h:96
#define PIOS_Assert(test)
Definition: pios_debug.h:52
TIM_TimeBaseInitTypeDef clock_cfg
int32_t PIOS_DELAY_WaituS(uint32_t uS)
Definition: pios_delay.c:116