Firmware SDK
 All Data Structures Functions Variables Typedefs Enumerations Enumerator Groups Pages
bc_ws2812b.c
1 #include "stm32l0xx.h"
2 #include <bc_ws2812b.h>
3 #include <bc_scheduler.h>
4 #include <bc_dma.h>
5 #include <bc_system.h>
6 
7 #define _BC_WS2812_TIMER_PERIOD 40 // 32000000 / 800000 = 20; 0,125us period (10 times lower the 1,25us period to have fixed math below)
8 #define _BC_WS2812_TIMER_RESET_PULSE_PERIOD 1666 // 60us just to be sure = (32000000 / (320 * 60))
9 #define _BC_WS2812_COMPARE_PULSE_LOGIC_0 11 //(10 * timer_period) / 36
10 #define _BC_WS2812_COMPARE_PULSE_LOGIC_1 26 //(10 * timer_period) / 15;
11 
12 #define _BC_WS2812_BC_WS2812_RESET_PERIOD 100
13 #define _BC_WS2812_BC_WS2812B_PORT GPIOA
14 #define _BC_WS2812_BC_WS2812B_PIN GPIO_PIN_1
15 
16 static struct ws2812b_t
17 {
18  uint32_t *dma_bit_buffer;
19  const bc_led_strip_buffer_t *buffer;
20 
21  bool transfer;
22  bc_scheduler_task_id_t task_id;
23  void (*event_handler)(bc_ws2812b_event_t, void *);
24  void *event_param;
25 
26 } _bc_ws2812b;
27 
28 static bc_dma_channel_config_t _bc_ws2812b_dma_config =
29 {
31  .direction = BC_DMA_DIRECTION_TO_PERIPHERAL,
32  .data_size_memory = BC_DMA_SIZE_1,
33  .data_size_peripheral = BC_DMA_SIZE_2,
34  .mode = BC_DMA_MODE_STANDARD,
35  .address_peripheral = (void *)&(TIM2->CCR2),
36  .priority = BC_DMA_PRIORITY_VERY_HIGH
37 };
38 
39 TIM_HandleTypeDef _bc_ws2812b_timer2_handle;
40 TIM_OC_InitTypeDef _bc_ws2812b_timer2_oc1;
41 
42 const uint32_t _bc_ws2812b_pulse_tab[] =
43 {
44  _BC_WS2812_COMPARE_PULSE_LOGIC_0 << 24 | _BC_WS2812_COMPARE_PULSE_LOGIC_0 << 16 | _BC_WS2812_COMPARE_PULSE_LOGIC_0 << 8 | _BC_WS2812_COMPARE_PULSE_LOGIC_0,
45  _BC_WS2812_COMPARE_PULSE_LOGIC_1 << 24 | _BC_WS2812_COMPARE_PULSE_LOGIC_0 << 16 | _BC_WS2812_COMPARE_PULSE_LOGIC_0 << 8 | _BC_WS2812_COMPARE_PULSE_LOGIC_0,
46  _BC_WS2812_COMPARE_PULSE_LOGIC_0 << 24 | _BC_WS2812_COMPARE_PULSE_LOGIC_1 << 16 | _BC_WS2812_COMPARE_PULSE_LOGIC_0 << 8 | _BC_WS2812_COMPARE_PULSE_LOGIC_0,
47  _BC_WS2812_COMPARE_PULSE_LOGIC_1 << 24 | _BC_WS2812_COMPARE_PULSE_LOGIC_1 << 16 | _BC_WS2812_COMPARE_PULSE_LOGIC_0 << 8 | _BC_WS2812_COMPARE_PULSE_LOGIC_0,
48  _BC_WS2812_COMPARE_PULSE_LOGIC_0 << 24 | _BC_WS2812_COMPARE_PULSE_LOGIC_0 << 16 | _BC_WS2812_COMPARE_PULSE_LOGIC_1 << 8 | _BC_WS2812_COMPARE_PULSE_LOGIC_0,
49  _BC_WS2812_COMPARE_PULSE_LOGIC_1 << 24 | _BC_WS2812_COMPARE_PULSE_LOGIC_0 << 16 | _BC_WS2812_COMPARE_PULSE_LOGIC_1 << 8 | _BC_WS2812_COMPARE_PULSE_LOGIC_0,
50  _BC_WS2812_COMPARE_PULSE_LOGIC_0 << 24 | _BC_WS2812_COMPARE_PULSE_LOGIC_1 << 16 | _BC_WS2812_COMPARE_PULSE_LOGIC_1 << 8 | _BC_WS2812_COMPARE_PULSE_LOGIC_0,
51  _BC_WS2812_COMPARE_PULSE_LOGIC_1 << 24 | _BC_WS2812_COMPARE_PULSE_LOGIC_1 << 16 | _BC_WS2812_COMPARE_PULSE_LOGIC_1 << 8 | _BC_WS2812_COMPARE_PULSE_LOGIC_0,
52  _BC_WS2812_COMPARE_PULSE_LOGIC_0 << 24 | _BC_WS2812_COMPARE_PULSE_LOGIC_0 << 16 | _BC_WS2812_COMPARE_PULSE_LOGIC_0 << 8 | _BC_WS2812_COMPARE_PULSE_LOGIC_1,
53  _BC_WS2812_COMPARE_PULSE_LOGIC_1 << 24 | _BC_WS2812_COMPARE_PULSE_LOGIC_0 << 16 | _BC_WS2812_COMPARE_PULSE_LOGIC_0 << 8 | _BC_WS2812_COMPARE_PULSE_LOGIC_1,
54  _BC_WS2812_COMPARE_PULSE_LOGIC_0 << 24 | _BC_WS2812_COMPARE_PULSE_LOGIC_1 << 16 | _BC_WS2812_COMPARE_PULSE_LOGIC_0 << 8 | _BC_WS2812_COMPARE_PULSE_LOGIC_1,
55  _BC_WS2812_COMPARE_PULSE_LOGIC_1 << 24 | _BC_WS2812_COMPARE_PULSE_LOGIC_1 << 16 | _BC_WS2812_COMPARE_PULSE_LOGIC_0 << 8 | _BC_WS2812_COMPARE_PULSE_LOGIC_1,
56  _BC_WS2812_COMPARE_PULSE_LOGIC_0 << 24 | _BC_WS2812_COMPARE_PULSE_LOGIC_0 << 16 | _BC_WS2812_COMPARE_PULSE_LOGIC_1 << 8 | _BC_WS2812_COMPARE_PULSE_LOGIC_1,
57  _BC_WS2812_COMPARE_PULSE_LOGIC_1 << 24 | _BC_WS2812_COMPARE_PULSE_LOGIC_0 << 16 | _BC_WS2812_COMPARE_PULSE_LOGIC_1 << 8 | _BC_WS2812_COMPARE_PULSE_LOGIC_1,
58  _BC_WS2812_COMPARE_PULSE_LOGIC_0 << 24 | _BC_WS2812_COMPARE_PULSE_LOGIC_1 << 16 | _BC_WS2812_COMPARE_PULSE_LOGIC_1 << 8 | _BC_WS2812_COMPARE_PULSE_LOGIC_1,
59  _BC_WS2812_COMPARE_PULSE_LOGIC_1 << 24 | _BC_WS2812_COMPARE_PULSE_LOGIC_1 << 16 | _BC_WS2812_COMPARE_PULSE_LOGIC_1 << 8 | _BC_WS2812_COMPARE_PULSE_LOGIC_1,
60 };
61 
62 static void _bc_ws2812b_dma_event_handler(bc_dma_channel_t channel, bc_dma_event_t event, void *event_param);
63 
64 static void _bc_ws2812b_task(void *param);
65 
66 bool bc_ws2812b_init(const bc_led_strip_buffer_t *led_strip)
67 {
68  memset(&_bc_ws2812b, 0, sizeof(_bc_ws2812b));
69 
70  _bc_ws2812b.buffer = led_strip;
71 
72  _bc_ws2812b.dma_bit_buffer = led_strip->buffer;
73 
74  size_t dma_bit_buffer_size = _bc_ws2812b.buffer->count * _bc_ws2812b.buffer->type * 8;
75 
76  memset(_bc_ws2812b.dma_bit_buffer, _BC_WS2812_COMPARE_PULSE_LOGIC_0, dma_bit_buffer_size);
77 
78  __HAL_RCC_GPIOA_CLK_ENABLE();
79 
80  //Init pin
81  GPIO_InitTypeDef GPIO_InitStruct;
82  GPIO_InitStruct.Pin = _BC_WS2812_BC_WS2812B_PIN;
83  GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
84  GPIO_InitStruct.Alternate = GPIO_AF2_TIM2;
85  GPIO_InitStruct.Pull = GPIO_NOPULL;
86  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
87  HAL_GPIO_Init(_BC_WS2812_BC_WS2812B_PORT, &GPIO_InitStruct);
88 
89  bc_dma_init();
90  bc_dma_set_event_handler(BC_DMA_CHANNEL_2, _bc_ws2812b_dma_event_handler, NULL);
91 
92  // TIM2 Periph clock enable
93  __HAL_RCC_TIM2_CLK_ENABLE();
94 
95  _bc_ws2812b_timer2_handle.Instance = TIM2;
96  _bc_ws2812b_timer2_handle.Init.Period = _BC_WS2812_TIMER_PERIOD;
97  _bc_ws2812b_timer2_handle.Init.Prescaler = 0x00;
98  _bc_ws2812b_timer2_handle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
99  _bc_ws2812b_timer2_handle.Init.CounterMode = TIM_COUNTERMODE_UP;
100  HAL_TIM_PWM_Init(&_bc_ws2812b_timer2_handle);
101 
102  HAL_NVIC_SetPriority(TIM2_IRQn, 0, 0);
103  HAL_NVIC_EnableIRQ(TIM2_IRQn);
104 
105  _bc_ws2812b_timer2_oc1.OCMode = TIM_OCMODE_PWM1;
106  _bc_ws2812b_timer2_oc1.OCPolarity = TIM_OCPOLARITY_HIGH;
107  _bc_ws2812b_timer2_oc1.Pulse = 0;
108  _bc_ws2812b_timer2_oc1.OCFastMode = TIM_OCFAST_DISABLE;
109  HAL_TIM_PWM_ConfigChannel(&_bc_ws2812b_timer2_handle, &_bc_ws2812b_timer2_oc1, TIM_CHANNEL_2);
110 
111  TIM2->CR1 &= ~TIM_CR1_CEN;
112 
113  TIM2->CCER |= (uint32_t)(TIM_CCx_ENABLE << TIM_CHANNEL_2);
114 
115  //HAL_TIM_PWM_Start(&_bc_ws2812b_timer2_handle, TIM_CHANNEL_2);
116 
117  TIM2->DCR = TIM_DMABASE_CCR2 | TIM_DMABURSTLENGTH_1TRANSFER;
118 
119  _bc_ws2812b.task_id = bc_scheduler_register(_bc_ws2812b_task, NULL, BC_TICK_INFINITY);
120 
121  _bc_ws2812b.transfer = false;
122 
123  return true;
124 }
125 
126 void bc_ws2812b_set_event_handler(void (*event_handler)(bc_ws2812b_event_t, void *), void *event_param)
127 {
128  _bc_ws2812b.event_handler = event_handler;
129  _bc_ws2812b.event_param = event_param;
130 }
131 
132 void bc_ws2812b_set_pixel_from_rgb(int position, uint8_t red, uint8_t green, uint8_t blue, uint8_t white)
133 {
134  uint32_t calculated_position = (position * _bc_ws2812b.buffer->type * 2);
135 
136  _bc_ws2812b.dma_bit_buffer[calculated_position++] = _bc_ws2812b_pulse_tab[(green & 0xf0) >> 4];
137  _bc_ws2812b.dma_bit_buffer[calculated_position++] = _bc_ws2812b_pulse_tab[green & 0x0f];
138 
139  _bc_ws2812b.dma_bit_buffer[calculated_position++] = _bc_ws2812b_pulse_tab[(red & 0xf0) >> 4];
140  _bc_ws2812b.dma_bit_buffer[calculated_position++] = _bc_ws2812b_pulse_tab[red & 0x0f];
141 
142  _bc_ws2812b.dma_bit_buffer[calculated_position++] = _bc_ws2812b_pulse_tab[(blue & 0xf0) >> 4];
143  _bc_ws2812b.dma_bit_buffer[calculated_position++] = _bc_ws2812b_pulse_tab[blue & 0x0f];
144 
145  if (_bc_ws2812b.buffer->type == BC_LED_STRIP_TYPE_RGBW)
146  {
147  _bc_ws2812b.dma_bit_buffer[calculated_position++] = _bc_ws2812b_pulse_tab[(white & 0xf0) >> 4];
148  _bc_ws2812b.dma_bit_buffer[calculated_position] = _bc_ws2812b_pulse_tab[white & 0x0f];
149  }
150 }
151 
152 void bc_ws2812b_set_pixel_from_uint32(int position, uint32_t color)
153 {
154  uint32_t calculated_position = (position * _bc_ws2812b.buffer->type * 2);
155 
156  _bc_ws2812b.dma_bit_buffer[calculated_position++] = _bc_ws2812b_pulse_tab[(color & 0x00f00000) >> 20];
157  _bc_ws2812b.dma_bit_buffer[calculated_position++] = _bc_ws2812b_pulse_tab[(color & 0x000f0000) >> 16];
158 
159  _bc_ws2812b.dma_bit_buffer[calculated_position++] = _bc_ws2812b_pulse_tab[(color & 0xf0000000) >> 28];
160  _bc_ws2812b.dma_bit_buffer[calculated_position++] = _bc_ws2812b_pulse_tab[(color & 0x0f000000) >> 24];
161 
162  _bc_ws2812b.dma_bit_buffer[calculated_position++] = _bc_ws2812b_pulse_tab[(color & 0x0000f000) >> 12];
163  _bc_ws2812b.dma_bit_buffer[calculated_position++] = _bc_ws2812b_pulse_tab[(color & 0x00000f00) >> 8];
164 
165  if (_bc_ws2812b.buffer->type == BC_LED_STRIP_TYPE_RGBW)
166  {
167  _bc_ws2812b.dma_bit_buffer[calculated_position++] = _bc_ws2812b_pulse_tab[(color & 0x000000f0) >> 4];
168  _bc_ws2812b.dma_bit_buffer[calculated_position] = _bc_ws2812b_pulse_tab[color & 0x0000000f];
169  }
170 }
171 
172 void bc_ws2812b_set_pixel_from_rgb_swap_rg(int position, uint8_t red, uint8_t green, uint8_t blue, uint8_t white)
173 {
174  uint32_t calculated_position = (position * _bc_ws2812b.buffer->type * 2);
175 
176  _bc_ws2812b.dma_bit_buffer[calculated_position++] = _bc_ws2812b_pulse_tab[(red & 0xf0) >> 4];
177  _bc_ws2812b.dma_bit_buffer[calculated_position++] = _bc_ws2812b_pulse_tab[red & 0x0f];
178 
179  _bc_ws2812b.dma_bit_buffer[calculated_position++] = _bc_ws2812b_pulse_tab[(green & 0xf0) >> 4];
180  _bc_ws2812b.dma_bit_buffer[calculated_position++] = _bc_ws2812b_pulse_tab[green & 0x0f];
181 
182  _bc_ws2812b.dma_bit_buffer[calculated_position++] = _bc_ws2812b_pulse_tab[(blue & 0xf0) >> 4];
183  _bc_ws2812b.dma_bit_buffer[calculated_position++] = _bc_ws2812b_pulse_tab[blue & 0x0f];
184 
185  if (_bc_ws2812b.buffer->type == BC_LED_STRIP_TYPE_RGBW)
186  {
187  _bc_ws2812b.dma_bit_buffer[calculated_position++] = _bc_ws2812b_pulse_tab[(white & 0xf0) >> 4];
188  _bc_ws2812b.dma_bit_buffer[calculated_position] = _bc_ws2812b_pulse_tab[white & 0x0f];
189  }
190 }
191 
192 void bc_ws2812b_set_pixel_from_uint32_swap_rg(int position, uint32_t color)
193 {
194  uint32_t calculated_position = (position * _bc_ws2812b.buffer->type * 2);
195 
196  _bc_ws2812b.dma_bit_buffer[calculated_position++] = _bc_ws2812b_pulse_tab[(color & 0xf0000000) >> 28];
197  _bc_ws2812b.dma_bit_buffer[calculated_position++] = _bc_ws2812b_pulse_tab[(color & 0x0f000000) >> 24];
198 
199  _bc_ws2812b.dma_bit_buffer[calculated_position++] = _bc_ws2812b_pulse_tab[(color & 0x00f00000) >> 20];
200  _bc_ws2812b.dma_bit_buffer[calculated_position++] = _bc_ws2812b_pulse_tab[(color & 0x000f0000) >> 16];
201 
202  _bc_ws2812b.dma_bit_buffer[calculated_position++] = _bc_ws2812b_pulse_tab[(color & 0x0000f000) >> 12];
203  _bc_ws2812b.dma_bit_buffer[calculated_position++] = _bc_ws2812b_pulse_tab[(color & 0x00000f00) >> 8];
204 
205  if (_bc_ws2812b.buffer->type == BC_LED_STRIP_TYPE_RGBW)
206  {
207  _bc_ws2812b.dma_bit_buffer[calculated_position++] = _bc_ws2812b_pulse_tab[(color & 0x000000f0) >> 4];
208  _bc_ws2812b.dma_bit_buffer[calculated_position] = _bc_ws2812b_pulse_tab[color & 0x0000000f];
209  }
210 }
211 
212 bool bc_ws2812b_write(void)
213 {
214  if (_bc_ws2812b.transfer)
215  {
216  return false;
217  }
218 
219  // transmission complete flag
220  _bc_ws2812b.transfer = true;
221 
222  bc_system_pll_enable();
223 
224  HAL_TIM_Base_Stop(&_bc_ws2812b_timer2_handle);
225  (&_bc_ws2812b_timer2_handle)->Instance->CR1 &= ~((0x1U << (0U)));
226 
227  // clear all DMA flags
228  __HAL_DMA_CLEAR_FLAG(&_bc_ws2812b_dma_update, DMA_FLAG_TC2 | DMA_FLAG_HT2 | DMA_FLAG_TE2);
229 
230  // clear all TIM2 flags
231  __HAL_TIM_CLEAR_FLAG(&_bc_ws2812b_timer2_handle, TIM_FLAG_UPDATE | TIM_FLAG_CC1 | TIM_FLAG_CC2 | TIM_FLAG_CC3 | TIM_FLAG_CC4);
232 
233  size_t dma_bit_buffer_size = _bc_ws2812b.buffer->count * _bc_ws2812b.buffer->type * 8;
234 
235  _bc_ws2812b_dma_config.address_memory = (void *)_bc_ws2812b.dma_bit_buffer;
236  _bc_ws2812b_dma_config.length = dma_bit_buffer_size;
237  bc_dma_channel_config(BC_DMA_CHANNEL_2, &_bc_ws2812b_dma_config);
239 
240  TIM2->CNT = _BC_WS2812_TIMER_PERIOD - 1;
241 
242  // Set zero length for first pulse because the first bit loads after first TIM_UP
243  TIM2->CCR2 = 0;
244 
245  // Enable PWM Compare 2
246  (&_bc_ws2812b_timer2_handle)->Instance->CCMR1 |= TIM_CCMR1_OC2M_1;
247 
248  // IMPORTANT: enable the TIM2 DMA requests AFTER enabling the DMA channels!
249  __HAL_TIM_ENABLE_DMA(&_bc_ws2812b_timer2_handle, TIM_DMA_UPDATE);
250 
251  // start TIM2
252  TIM2->CR1 |= TIM_CR1_CEN;
253 
254  return true;
255 }
256 
257 bool bc_ws2812b_is_ready(void)
258 {
259  return !_bc_ws2812b.transfer;
260 }
261 
262 static void _bc_ws2812b_dma_event_handler(bc_dma_channel_t channel, bc_dma_event_t event, void *event_param)
263 {
264  (void) channel;
265  (void) event;
266  (void) event_param;
267 
268  if (event == BC_DMA_EVENT_DONE)
269  {
270  // Stop timer
271  TIM2->CR1 &= ~TIM_CR1_CEN;
272 
273  // Disable the DMA requests
274  __HAL_TIM_DISABLE_DMA(&_bc_ws2812b_timer2_handle, TIM_DMA_UPDATE);
275 
276  // Disable PWM output Compare 2
277  (&_bc_ws2812b_timer2_handle)->Instance->CCMR1 &= ~(TIM_CCMR1_OC2M_Msk);
278  (&_bc_ws2812b_timer2_handle)->Instance->CCMR1 |= TIM_CCMR1_OC2M_2;
279 
280  // Set 50us period for Treset pulse
281  TIM2->ARR = _BC_WS2812_TIMER_RESET_PULSE_PERIOD;
282  // Reset the timer
283  TIM2->CNT = 0;
284 
285  // Generate an update event to reload the prescaler value immediately
286  TIM2->EGR = TIM_EGR_UG;
287  __HAL_TIM_CLEAR_FLAG(&_bc_ws2812b_timer2_handle, TIM_FLAG_UPDATE);
288 
289  // Enable TIM2 Update interrupt for Treset signal
290  __HAL_TIM_ENABLE_IT(&_bc_ws2812b_timer2_handle, TIM_IT_UPDATE);
291  // Enable timer
292  TIM2->CR1 |= TIM_CR1_CEN;
293  }
294 }
295 
296 void TIM2_IRQHandler(void)
297 {
298  HAL_TIM_IRQHandler(&_bc_ws2812b_timer2_handle);
299 }
300 
301 // TIM2 Interrupt Handler gets executed on every TIM2 Update if enabled
302 void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
303 {
304  (void)htim;
305 
306  TIM2->CR1 = 0; // disable timer
307 
308  // disable the TIM2 Update IRQ
309  __HAL_TIM_DISABLE_IT(&_bc_ws2812b_timer2_handle, TIM_IT_UPDATE);
310 
311  // Set back 1,25us period
312  TIM2->ARR = _BC_WS2812_TIMER_PERIOD;
313 
314  // Generate an update event to reload the Prescaler value immediatly
315  TIM2->EGR = TIM_EGR_UG;
316  __HAL_TIM_CLEAR_FLAG(&_bc_ws2812b_timer2_handle, TIM_FLAG_UPDATE);
317 
318  bc_scheduler_plan_now(_bc_ws2812b.task_id);
319 }
320 
321 static void _bc_ws2812b_task(void *param)
322 {
323  (void) param;
324 
325  bc_system_pll_disable();
326 
327  // set transfer_complete flag
328  _bc_ws2812b.transfer = false;
329 
330  if (_bc_ws2812b.event_handler != NULL)
331  {
332  _bc_ws2812b.event_handler(BC_WS2812B_SEND_DONE, _bc_ws2812b.event_param);
333  }
334 }
size_t length
DMA channel data length.
Definition: bc_dma.h:180
DMA channel configuration.
Definition: bc_dma.h:165
bc_dma_event_t
DMA channel event.
Definition: bc_dma.h:132
bc_dma_channel_t
DMA channels.
Definition: bc_dma.h:12
DMA channel data size 2B.
Definition: bc_dma.h:111
bc_scheduler_task_id_t bc_scheduler_register(void(*task)(void *), void *param, bc_tick_t tick)
Register task in scheduler.
Definition: bc_scheduler.c:56
void bc_scheduler_plan_now(bc_scheduler_task_id_t task_id)
Schedule specified task for immediate execution.
Definition: bc_scheduler.c:119
void bc_dma_set_event_handler(bc_dma_channel_t channel, void(*event_handler)(bc_dma_channel_t, bc_dma_event_t, void *), void *event_param)
Set callback function.
Definition: bc_dma.c:173
void * address_memory
RAM memory address.
Definition: bc_dma.h:186
bc_dma_request_t request
DMA channel request.
Definition: bc_dma.h:168
void bc_dma_init(void)
Initialize DMA.
Definition: bc_dma.c:56
void bc_dma_channel_run(bc_dma_channel_t channel)
Start DMA channel.
Definition: bc_dma.c:179
DMA channel direction from RAM to peripheral.
Definition: bc_dma.h:96
size_t bc_scheduler_task_id_t
Task ID assigned by scheduler.
Definition: bc_scheduler.h:18
DMA channel 2.
Definition: bc_dma.h:18
DMA channel data size 1B.
Definition: bc_dma.h:108
DMA channel priority is very high.
Definition: bc_dma.h:159
DMA channel mode standard.
Definition: bc_dma.h:123
DMA request 8.
Definition: bc_dma.h:66
void bc_dma_channel_config(bc_dma_channel_t channel, bc_dma_channel_config_t *config)
Configure DMA channel.
Definition: bc_dma.c:95
#define BC_TICK_INFINITY
Maximum timestamp value.
Definition: bc_tick.h:12
DMA channel event done.
Definition: bc_dma.h:141