2 * Neopixel (WS2812B) Test
4 * (c) 2022 Martin Mareš <mj@ucw.cz>
9 #include <libopencm3/cm3/cortex.h>
10 #include <libopencm3/cm3/nvic.h>
11 #include <libopencm3/cm3/systick.h>
12 #include <libopencm3/cm3/scb.h>
13 #include <libopencm3/stm32/dma.h>
14 #include <libopencm3/stm32/gpio.h>
15 #include <libopencm3/stm32/rcc.h>
16 #include <libopencm3/stm32/timer.h>
17 #include <libopencm3/stm32/usart.h>
21 /*** Hardware init ***/
23 static void clock_init(void)
25 rcc_clock_setup_pll(&rcc_hse_configs[RCC_CLOCK_HSE8_72MHZ]);
27 rcc_periph_clock_enable(RCC_GPIOA);
28 rcc_periph_clock_enable(RCC_GPIOB);
29 rcc_periph_clock_enable(RCC_GPIOC);
30 rcc_periph_clock_enable(RCC_USART1);
31 rcc_periph_clock_enable(RCC_TIM4);
32 rcc_periph_clock_enable(RCC_DMA1);
34 rcc_periph_reset_pulse(RST_GPIOA);
35 rcc_periph_reset_pulse(RST_GPIOB);
36 rcc_periph_reset_pulse(RST_GPIOC);
37 rcc_periph_reset_pulse(RST_USART1);
38 rcc_periph_reset_pulse(RST_TIM4);
41 static void gpio_init(void)
43 // PA9 = TXD1 for debugging console
44 // PA10 = RXD1 for debugging console
45 gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO9);
46 gpio_set_mode(GPIOA, GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, GPIO10);
48 // PC13 = BluePill LED
49 gpio_set_mode(GPIOC, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO13);
50 gpio_clear(GPIOC, GPIO13);
52 // PB8 = data for Neopixel
53 gpio_set_mode(GPIOB, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_OPENDRAIN, GPIO8);
56 static void usart_init(void)
58 usart_set_baudrate(USART1, 115200);
59 usart_set_databits(USART1, 8);
60 usart_set_stopbits(USART1, USART_STOPBITS_1);
61 usart_set_mode(USART1, USART_MODE_TX);
62 usart_set_parity(USART1, USART_PARITY_NONE);
63 usart_set_flow_control(USART1, USART_FLOWCONTROL_NONE);
68 /*** System ticks ***/
70 static volatile u32 ms_ticks;
72 void sys_tick_handler(void)
77 static void tick_init(void)
79 systick_set_frequency(1000, CPU_CLOCK_MHZ * 1000000);
80 systick_counter_enable();
81 systick_interrupt_enable();
84 static void delay_ms(uint ms)
86 u32 start_ticks = ms_ticks;
87 while (ms_ticks - start_ticks < ms)
93 #define NPIX_PERIOD 90 // timer runs on 72 MHz, so 90 periods = 1250 ns
97 byte neopixel_buf[] = {
98 // 128 cycles low: reset (has to be longer than in the datasheet)
99 0, 0, 0, 0, 0, 0, 0, 0,
100 0, 0, 0, 0, 0, 0, 0, 0,
101 0, 0, 0, 0, 0, 0, 0, 0,
102 0, 0, 0, 0, 0, 0, 0, 0,
103 0, 0, 0, 0, 0, 0, 0, 0,
104 0, 0, 0, 0, 0, 0, 0, 0,
105 0, 0, 0, 0, 0, 0, 0, 0,
106 0, 0, 0, 0, 0, 0, 0, 0,
107 0, 0, 0, 0, 0, 0, 0, 0,
108 0, 0, 0, 0, 0, 0, 0, 0,
109 0, 0, 0, 0, 0, 0, 0, 0,
110 0, 0, 0, 0, 0, 0, 0, 0,
111 0, 0, 0, 0, 0, 0, 0, 0,
112 0, 0, 0, 0, 0, 0, 0, 0,
113 0, 0, 0, 0, 0, 0, 0, 0,
114 0, 0, 0, 0, 0, 0, 0, 0,
116 // G7 G6 G5 G4 G3 G2 G1 G0
117 // R7 R6 R5 R4 R3 R2 R1 R0
118 // B7 B6 B5 B4 B3 B2 B1 B0
120 B0, B0, B0, B0, B1, B1, B1, B1,
121 B0, B0, B0, B0, B0, B0, B0, B0,
122 B0, B0, B0, B0, B0, B0, B0, B0,
124 B0, B0, B0, B0, B0, B0, B0, B0,
125 B0, B0, B0, B0, B0, B0, B0, B0,
126 B0, B0, B0, B0, B1, B1, B1, B1,
128 B0, B0, B0, B0, B0, B0, B0, B0,
129 B0, B0, B0, B0, B1, B1, B1, B1,
130 B0, B0, B0, B0, B0, B0, B0, B0,
132 B0, B0, B0, B0, B1, B1, B1, B1,
133 B0, B0, B0, B0, B0, B0, B0, B0,
134 B0, B0, B0, B0, B1, B1, B1, B1,
136 B0, B0, B0, B0, B1, B1, B1, B1,
137 B0, B0, B0, B0, B1, B1, B1, B1,
138 B0, B0, B0, B0, B0, B0, B0, B0,
140 B0, B0, B0, B0, B0, B0, B0, B0,
141 B0, B0, B0, B0, B1, B1, B1, B1,
142 B0, B0, B0, B0, B1, B1, B1, B1,
144 B0, B0, B0, B0, B1, B1, B1, B1,
145 B0, B0, B0, B0, B1, B1, B1, B1,
146 B0, B0, B0, B0, B1, B1, B1, B1,
148 B0, B0, B0, B0, B0, B0, B0, B0,
149 B0, B0, B0, B0, B0, B0, B0, B0,
150 B0, B0, B0, B0, B1, B1, B1, B1,
152 B0, B0, B0, B0, B0, B0, B0, B0,
153 B0, B0, B0, B0, B0, B0, B0, B0,
154 B0, B0, B0, B0, B1, B1, B1, B1,
156 B0, B0, B0, B0, B0, B0, B0, B0,
157 B0, B0, B0, B0, B0, B0, B0, B0,
158 B0, B0, B0, B0, B1, B1, B1, B1,
160 B0, B0, B0, B0, B0, B0, B0, B0,
161 B0, B0, B0, B0, B0, B0, B0, B0,
162 B0, B0, B0, B0, B1, B1, B1, B1,
164 B0, B0, B0, B0, B1, B1, B1, B1,
165 B0, B0, B0, B0, B0, B0, B0, B0,
166 B0, B0, B0, B0, B0, B0, B0, B0,
168 B0, B0, B0, B0, B0, B0, B0, B0,
169 B0, B0, B0, B0, B0, B0, B0, B0,
170 B0, B0, B0, B0, B0, B0, B0, B0,
172 B0, B0, B0, B0, B0, B0, B0, B0,
173 B0, B0, B0, B0, B0, B0, B0, B0,
174 B0, B0, B0, B0, B0, B0, B0, B0,
176 B0, B0, B0, B0, B0, B0, B0, B0,
177 B0, B0, B0, B0, B0, B0, B0, B0,
178 B0, B0, B0, B0, B0, B0, B0, B0,
180 B0, B0, B0, B0, B0, B0, B0, B0,
181 B0, B0, B0, B0, B0, B0, B0, B0,
182 B0, B0, B0, B0, B0, B0, B0, B0,
184 B0, B0, B0, B0, B0, B0, B0, B0,
185 B0, B0, B0, B0, B0, B0, B0, B0,
186 B0, B0, B0, B0, B0, B0, B0, B0,
188 B0, B0, B0, B0, B0, B0, B0, B0,
189 B0, B0, B0, B0, B0, B0, B0, B0,
190 B0, B0, B0, B0, B0, B0, B0, B0,
192 B0, B0, B0, B0, B0, B0, B0, B0,
193 B0, B0, B0, B0, B0, B0, B0, B0,
194 B0, B0, B0, B0, B0, B0, B0, B0,
196 B0, B0, B0, B0, B0, B0, B0, B0,
197 B0, B0, B0, B0, B0, B0, B0, B0,
198 B0, B0, B0, B0, B0, B0, B0, B0,
200 B0, B0, B0, B0, B0, B0, B0, B0,
201 B0, B0, B0, B0, B0, B0, B0, B0,
202 B0, B0, B0, B0, B0, B0, B0, B0,
204 B0, B0, B0, B0, B0, B0, B0, B0,
205 B0, B0, B0, B0, B0, B0, B0, B0,
206 B0, B0, B0, B0, B0, B0, B0, B0,
208 B0, B0, B0, B0, B0, B0, B0, B0,
209 B0, B0, B0, B0, B0, B0, B0, B0,
210 B0, B0, B0, B0, B0, B0, B0, B0,
212 B0, B0, B0, B0, B0, B0, B0, B0,
213 B0, B0, B0, B0, B0, B0, B0, B0,
214 B0, B0, B0, B0, B0, B0, B0, B0,
216 B0, B0, B0, B0, B0, B0, B0, B0,
217 B0, B0, B0, B0, B0, B0, B0, B0,
218 B0, B0, B0, B0, B0, B0, B0, B0,
220 B0, B0, B0, B0, B0, B0, B0, B0,
221 B0, B0, B0, B0, B0, B0, B0, B0,
222 B0, B0, B0, B0, B0, B0, B0, B0,
224 B0, B0, B0, B0, B0, B0, B0, B0,
225 B0, B0, B0, B0, B0, B0, B0, B0,
226 B0, B0, B0, B0, B0, B0, B0, B0,
228 B0, B0, B0, B0, B0, B0, B0, B0,
229 B0, B0, B0, B0, B0, B0, B0, B0,
230 B0, B0, B0, B0, B0, B0, B0, B0,
232 B0, B0, B0, B0, B0, B0, B0, B0,
233 B0, B0, B0, B0, B0, B0, B0, B0,
234 B0, B0, B0, B0, B0, B0, B0, B0,
236 B0, B0, B0, B0, B0, B0, B0, B0,
237 B0, B0, B0, B0, B0, B0, B0, B0,
238 B0, B0, B0, B0, B0, B0, B0, B0,
240 B0, B0, B0, B0, B0, B0, B0, B0,
241 B0, B0, B0, B0, B0, B0, B0, B0,
242 B0, B0, B0, B0, B0, B0, B0, B0,
244 B0, B0, B0, B0, B0, B0, B0, B0,
245 B0, B0, B0, B0, B0, B0, B0, B0,
246 B0, B0, B0, B0, B0, B0, B0, B0,
248 B0, B0, B0, B0, B0, B0, B0, B0,
249 B0, B0, B0, B0, B0, B0, B0, B0,
250 B0, B0, B0, B0, B0, B0, B0, B0,
252 B0, B0, B0, B0, B0, B0, B0, B0,
253 B0, B0, B0, B0, B0, B0, B0, B0,
254 B0, B0, B0, B0, B0, B0, B0, B0,
256 B0, B0, B0, B0, B0, B0, B0, B0,
257 B0, B0, B0, B0, B0, B0, B0, B0,
258 B0, B0, B0, B0, B0, B0, B0, B0,
260 B0, B0, B0, B0, B0, B0, B0, B0,
261 B0, B0, B0, B0, B0, B0, B0, B0,
262 B0, B0, B0, B0, B0, B0, B0, B0,
264 B0, B0, B0, B0, B0, B0, B0, B0,
265 B0, B0, B0, B0, B0, B0, B0, B0,
266 B0, B0, B0, B0, B0, B0, B0, B0,
268 B0, B0, B0, B0, B0, B0, B0, B0,
269 B0, B0, B0, B0, B0, B0, B0, B0,
270 B0, B0, B0, B0, B0, B0, B0, B0,
272 B0, B0, B0, B0, B0, B0, B0, B0,
273 B0, B0, B0, B0, B0, B0, B0, B0,
274 B0, B0, B0, B0, B0, B0, B0, B0,
276 B0, B0, B0, B0, B0, B0, B0, B0,
277 B0, B0, B0, B0, B0, B0, B0, B0,
278 B0, B0, B0, B0, B0, B0, B0, B0,
280 B0, B0, B0, B0, B0, B0, B0, B0,
281 B0, B0, B0, B0, B0, B0, B0, B0,
282 B0, B0, B0, B0, B0, B0, B0, B0,
284 B0, B0, B0, B0, B0, B0, B0, B0,
285 B0, B0, B0, B0, B0, B0, B0, B0,
286 B0, B0, B0, B0, B0, B0, B0, B0,
288 B0, B0, B0, B0, B0, B0, B0, B0,
289 B0, B0, B0, B0, B0, B0, B0, B0,
290 B0, B0, B0, B0, B0, B0, B0, B0,
292 B0, B0, B0, B0, B0, B0, B0, B0,
293 B0, B0, B0, B0, B0, B0, B0, B0,
294 B0, B0, B0, B0, B0, B0, B0, B0,
296 B0, B0, B0, B0, B0, B0, B0, B0,
297 B0, B0, B0, B0, B0, B0, B0, B0,
298 B0, B0, B0, B0, B0, B0, B0, B0,
300 B0, B0, B0, B0, B0, B0, B0, B0,
301 B0, B0, B0, B0, B0, B0, B0, B0,
302 B0, B0, B0, B0, B0, B0, B0, B0,
304 B0, B0, B0, B0, B0, B0, B0, B0,
305 B0, B0, B0, B0, B0, B0, B0, B0,
306 B0, B0, B0, B0, B0, B0, B0, B0,
308 B0, B0, B0, B0, B0, B0, B0, B0,
309 B0, B0, B0, B0, B0, B0, B0, B0,
310 B0, B0, B0, B0, B0, B0, B0, B0,
312 B0, B0, B0, B0, B0, B0, B0, B0,
313 B0, B0, B0, B0, B0, B0, B0, B0,
314 B0, B0, B0, B0, B0, B0, B0, B0,
316 B0, B0, B0, B0, B0, B0, B0, B0,
317 B0, B0, B0, B0, B0, B0, B0, B0,
318 B0, B0, B0, B0, B0, B0, B0, B0,
320 B0, B0, B0, B0, B0, B0, B0, B0,
321 B0, B0, B0, B0, B0, B0, B0, B0,
322 B0, B0, B0, B0, B0, B0, B0, B0,
324 B0, B0, B0, B0, B0, B0, B0, B0,
325 B0, B0, B0, B0, B0, B0, B0, B0,
326 B0, B0, B0, B0, B0, B0, B0, B0,
328 B0, B0, B0, B0, B0, B0, B0, B0,
329 B0, B0, B0, B0, B0, B0, B0, B0,
330 B0, B0, B0, B0, B0, B0, B0, B0,
332 B0, B0, B0, B0, B0, B0, B0, B0,
333 B0, B0, B0, B0, B0, B0, B0, B0,
334 B0, B0, B0, B0, B0, B0, B0, B0,
336 B0, B0, B0, B0, B0, B0, B0, B0,
337 B0, B0, B0, B0, B0, B0, B0, B0,
338 B0, B0, B0, B0, B0, B0, B0, B0,
340 B0, B0, B0, B0, B0, B0, B0, B0,
341 B0, B0, B0, B0, B0, B0, B0, B0,
342 B0, B0, B0, B0, B0, B0, B0, B0,
344 B0, B0, B0, B0, B0, B0, B0, B0,
345 B0, B0, B0, B0, B0, B0, B0, B0,
346 B0, B0, B0, B0, B0, B0, B0, B0,
348 B0, B0, B0, B0, B0, B0, B0, B0,
349 B0, B0, B0, B0, B0, B0, B0, B0,
350 B0, B0, B0, B0, B0, B0, B0, B0,
352 B0, B0, B0, B0, B0, B0, B0, B0,
353 B0, B0, B0, B0, B0, B0, B0, B0,
354 B0, B0, B0, B0, B0, B0, B0, B0,
356 B0, B0, B0, B0, B0, B0, B0, B0,
357 B0, B0, B0, B0, B0, B0, B0, B0,
358 B0, B0, B0, B0, B0, B0, B0, B0,
360 B0, B0, B0, B0, B0, B0, B0, B0,
361 B0, B0, B0, B0, B0, B0, B0, B0,
362 B0, B0, B0, B0, B0, B0, B0, B0,
364 B0, B0, B0, B0, B0, B0, B0, B0,
365 B0, B0, B0, B0, B0, B0, B0, B0,
366 B0, B0, B0, B0, B0, B0, B0, B0,
368 B0, B0, B0, B0, B0, B0, B0, B0,
369 B0, B0, B0, B0, B0, B0, B0, B0,
370 B0, B0, B0, B0, B0, B0, B0, B0,
372 B0, B0, B0, B0, B1, B1, B1, B1,
373 B0, B0, B0, B0, B1, B1, B1, B1,
374 B0, B0, B0, B0, B1, B1, B1, B1,
377 static void neopixel_init(void)
379 // TIM4 update is connected to DMA1 channel 7
381 // FIXME: Strange programming sequence as specified in manual
383 dma_channel_reset(DMA1, 7);
385 dma_set_peripheral_address(DMA1, 7, (u32) &TIM_CCR3(TIM4));
386 dma_set_memory_address(DMA1, 7, (u32) neopixel_buf);
387 dma_set_number_of_data(DMA1, 7, ARRAY_SIZE(neopixel_buf));
388 dma_set_priority(DMA1, 7, DMA_CCR_PL_VERY_HIGH);
390 dma_set_read_from_memory(DMA1, 7);
391 dma_enable_circular_mode(DMA1, 7);
393 dma_set_memory_size(DMA1, 7, DMA_CCR_MSIZE_8BIT);
394 dma_enable_memory_increment_mode(DMA1, 7);
396 dma_set_peripheral_size(DMA1, 7, DMA_CCR_PSIZE_16BIT);
397 dma_disable_peripheral_increment_mode(DMA1, 7);
399 dma_enable_channel(DMA1, 7);
401 timer_set_prescaler(TIM4, 0);
402 timer_set_mode(TIM4, TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP);
403 timer_disable_preload(TIM4);
404 timer_set_period(TIM4, NPIX_PERIOD - 1);
406 timer_set_oc_mode(TIM4, TIM_OC3, TIM_OCM_PWM1);
407 timer_set_oc_value(TIM4, TIM_OC3, 0);
408 timer_set_oc_polarity_high(TIM4, TIM_OC3);
409 timer_enable_oc_output(TIM4, TIM_OC3);
411 timer_set_dma_on_update_event(TIM4);
412 TIM_DIER(TIM4) |= TIM_DIER_UDE;
414 timer_enable_counter(TIM4);
427 debug_printf("Hello, world!\n");
430 for (int i=0; i<24*64; i++)
431 neopixel_buf[128+i] = B1;
435 // wait_for_interrupt();
437 for (int i=4; i<8; i++)
438 neopixel_buf[128+24*63+i] = B1;
441 for (int i=4; i<8; i++)
442 neopixel_buf[128+24*63+i] = B0;