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