2 #include <twr_ws2812b.h>
3 #include <twr_scheduler.h>
5 #include <twr_system.h>
8 #define _TWR_WS2812_TIMER_PERIOD 40
9 #define _TWR_WS2812_TIMER_RESET_PULSE_PERIOD 1666
10 #define _TWR_WS2812_COMPARE_PULSE_LOGIC_0 11
11 #define _TWR_WS2812_COMPARE_PULSE_LOGIC_1 26
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
17 static struct ws2812b_t
19 uint32_t *dma_bit_buffer;
24 void (*event_handler)(twr_ws2812b_event_t,
void *);
36 .address_peripheral = (
void *)&(TIM2->CCR2),
40 TIM_HandleTypeDef _twr_ws2812b_timer2_handle;
41 TIM_OC_InitTypeDef _twr_ws2812b_timer2_oc1;
43 const uint32_t _twr_ws2812b_pulse_tab[] =
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,
64 static void _twr_ws2812b_TIM2_interrupt_handler(
void *param);
65 static void _twr_ws2812b_task(
void *param);
69 memset(&_twr_ws2812b, 0,
sizeof(_twr_ws2812b));
71 _twr_ws2812b.buffer = led_strip;
73 _twr_ws2812b.dma_bit_buffer = led_strip->buffer;
75 size_t dma_bit_buffer_size = _twr_ws2812b.buffer->count * _twr_ws2812b.buffer->type * 8;
77 memset(_twr_ws2812b.dma_bit_buffer, _TWR_WS2812_COMPARE_PULSE_LOGIC_0, dma_bit_buffer_size);
79 __HAL_RCC_GPIOA_CLK_ENABLE();
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);
94 __HAL_RCC_TIM2_CLK_ENABLE();
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);
105 HAL_NVIC_SetPriority(TIM2_IRQn, 0, 0);
106 HAL_NVIC_EnableIRQ(TIM2_IRQn);
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);
114 TIM2->CR1 &= ~TIM_CR1_CEN;
116 TIM2->CCER |= (uint32_t)(TIM_CCx_ENABLE << TIM_CHANNEL_2);
120 TIM2->DCR = TIM_DMABASE_CCR2 | TIM_DMABURSTLENGTH_1TRANSFER;
124 _twr_ws2812b.transfer =
false;
129 void twr_ws2812b_set_event_handler(
void (*event_handler)(twr_ws2812b_event_t,
void *),
void *event_param)
131 _twr_ws2812b.event_handler = event_handler;
132 _twr_ws2812b.event_param = event_param;
135 void twr_ws2812b_set_pixel_from_rgb(
int position, uint8_t red, uint8_t green, uint8_t blue, uint8_t white)
137 uint32_t calculated_position = (position * _twr_ws2812b.buffer->type * 2);
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];
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];
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];
148 if (_twr_ws2812b.buffer->type == TWR_LED_STRIP_TYPE_RGBW)
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];
155 void twr_ws2812b_set_pixel_from_uint32(
int position, uint32_t color)
157 uint32_t calculated_position = (position * _twr_ws2812b.buffer->type * 2);
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];
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];
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];
168 if (_twr_ws2812b.buffer->type == TWR_LED_STRIP_TYPE_RGBW)
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];
175 void twr_ws2812b_set_pixel_from_rgb_swap_rg(
int position, uint8_t red, uint8_t green, uint8_t blue, uint8_t white)
177 uint32_t calculated_position = (position * _twr_ws2812b.buffer->type * 2);
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];
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];
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];
188 if (_twr_ws2812b.buffer->type == TWR_LED_STRIP_TYPE_RGBW)
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];
195 void twr_ws2812b_set_pixel_from_uint32_swap_rg(
int position, uint32_t color)
197 uint32_t calculated_position = (position * _twr_ws2812b.buffer->type * 2);
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];
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];
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];
208 if (_twr_ws2812b.buffer->type == TWR_LED_STRIP_TYPE_RGBW)
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];
215 bool twr_ws2812b_write(
void)
217 if (_twr_ws2812b.transfer)
223 _twr_ws2812b.transfer =
true;
225 twr_system_pll_enable();
227 HAL_TIM_Base_Stop(&_twr_ws2812b_timer2_handle);
228 (&_twr_ws2812b_timer2_handle)->Instance->CR1 &= ~((0x1U << (0U)));
231 __HAL_DMA_CLEAR_FLAG(&_twr_ws2812b_dma_update, DMA_FLAG_TC2 | DMA_FLAG_HT2 | DMA_FLAG_TE2);
234 __HAL_TIM_CLEAR_FLAG(&_twr_ws2812b_timer2_handle, TIM_FLAG_UPDATE | TIM_FLAG_CC1 | TIM_FLAG_CC2 | TIM_FLAG_CC3 | TIM_FLAG_CC4);
236 size_t dma_bit_buffer_size = _twr_ws2812b.buffer->count * _twr_ws2812b.buffer->type * 8;
238 _twr_ws2812b_dma_config.
address_memory = (
void *)_twr_ws2812b.dma_bit_buffer;
239 _twr_ws2812b_dma_config.
length = dma_bit_buffer_size;
243 TIM2->CNT = _TWR_WS2812_TIMER_PERIOD - 1;
249 (&_twr_ws2812b_timer2_handle)->Instance->CCMR1 |= TIM_CCMR1_OC2M_1;
252 __HAL_TIM_ENABLE_DMA(&_twr_ws2812b_timer2_handle, TIM_DMA_UPDATE);
255 TIM2->CR1 |= TIM_CR1_CEN;
260 bool twr_ws2812b_is_ready(
void)
262 return !_twr_ws2812b.transfer;
274 TIM2->CR1 &= ~TIM_CR1_CEN;
277 __HAL_TIM_DISABLE_DMA(&_twr_ws2812b_timer2_handle, TIM_DMA_UPDATE);
280 (&_twr_ws2812b_timer2_handle)->Instance->CCMR1 &= ~(TIM_CCMR1_OC2M_Msk);
281 (&_twr_ws2812b_timer2_handle)->Instance->CCMR1 |= TIM_CCMR1_OC2M_2;
284 TIM2->ARR = _TWR_WS2812_TIMER_RESET_PULSE_PERIOD;
289 TIM2->EGR = TIM_EGR_UG;
290 __HAL_TIM_CLEAR_FLAG(&_twr_ws2812b_timer2_handle, TIM_FLAG_UPDATE);
293 __HAL_TIM_ENABLE_IT(&_twr_ws2812b_timer2_handle, TIM_IT_UPDATE);
295 TIM2->CR1 |= TIM_CR1_CEN;
300 void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
307 __HAL_TIM_DISABLE_IT(&_twr_ws2812b_timer2_handle, TIM_IT_UPDATE);
310 TIM2->ARR = _TWR_WS2812_TIMER_PERIOD;
313 TIM2->EGR = TIM_EGR_UG;
314 __HAL_TIM_CLEAR_FLAG(&_twr_ws2812b_timer2_handle, TIM_FLAG_UPDATE);
319 static void _twr_ws2812b_TIM2_interrupt_handler(
void *param)
323 HAL_TIM_IRQHandler(&_twr_ws2812b_timer2_handle);
326 static void _twr_ws2812b_task(
void *param)
330 twr_system_pll_disable();
333 _twr_ws2812b.transfer =
false;
335 if (_twr_ws2812b.event_handler != NULL)
337 _twr_ws2812b.event_handler(TWR_WS2812B_SEND_DONE, _twr_ws2812b.event_param);
void twr_dma_channel_config(twr_dma_channel_t channel, twr_dma_channel_config_t *config)
Configure DMA channel.
void twr_dma_channel_run(twr_dma_channel_t channel)
Start DMA channel.
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.
twr_dma_event_t
DMA channel event.
void twr_dma_init(void)
Initialize DMA.
twr_dma_channel_t
DMA channels.
@ TWR_DMA_REQUEST_8
DMA request 8.
@ TWR_DMA_EVENT_DONE
DMA channel event done.
@ TWR_DMA_SIZE_2
DMA channel data size 2B.
@ TWR_DMA_SIZE_1
DMA channel data size 1B.
@ TWR_DMA_DIRECTION_TO_PERIPHERAL
DMA channel direction from RAM to peripheral.
@ TWR_DMA_PRIORITY_VERY_HIGH
DMA channel priority is very high.
@ TWR_DMA_CHANNEL_2
DMA channel 2.
@ TWR_DMA_MODE_STANDARD
DMA channel mode standard.
size_t twr_scheduler_task_id_t
Task ID assigned by scheduler.
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.
#define TWR_TICK_INFINITY
Maximum timestamp value.
bool twr_timer_set_irq_handler(TIM_TypeDef *tim, void(*irq_handler)(void *), void *irq_param)
Register timer IRQ handler.
DMA channel configuration.
twr_dma_request_t request
DMA channel request.
size_t length
DMA channel data length.
void * address_memory
RAM memory address.