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 // 64 cycles low: reset
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,
108 // G7 G6 G5 G4 G3 G2 G1 G0
109 // R7 R6 R5 R4 R3 R2 R1 R0
110 // B7 B6 B5 B4 B3 B2 B1 B0
112 B0, B0, B0, B0, B1, B1, B1, B1,
113 B0, B0, B0, B0, B0, B0, B0, B0,
114 B0, B0, B0, B0, B0, B0, B0, B0,
116 B0, B0, B0, B0, B0, B0, B0, B0,
117 B0, B0, B0, B0, B0, B0, B0, B0,
118 B0, B0, B0, B0, B1, B1, B1, B1,
120 B0, B0, B0, B0, B0, B0, B0, B0,
121 B0, B0, B0, B0, B1, B1, B1, B1,
122 B0, B0, B0, B0, B0, B0, B0, B0,
124 B0, B0, B0, B0, B1, B1, B1, B1,
125 B0, B0, B0, B0, B0, B0, B0, B0,
126 B0, B0, B0, B0, B1, B1, B1, B1,
128 B0, B0, B0, B0, B1, B1, B1, B1,
129 B0, B0, B0, B0, B1, B1, B1, B1,
130 B0, B0, B0, B0, B0, B0, B0, B0,
132 B0, B0, B0, B0, B0, B0, B0, B0,
133 B0, B0, B0, B0, B1, B1, B1, B1,
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, B1, B1, B1, B1,
140 B0, B0, B0, B0, B0, B0, B0, B0,
141 B0, B0, B0, B0, B0, B0, B0, B0,
142 B0, B0, B0, B0, B1, B1, B1, B1,
144 B0, B0, B0, B0, B0, B0, B0, B0,
145 B0, B0, B0, B0, B0, B0, B0, B0,
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, B1, B1, B1, B1,
157 B0, B0, B0, B0, B0, B0, B0, B0,
158 B0, B0, B0, B0, B0, B0, B0, B0,
161 static void neopixel_init(void)
163 // TIM4 update is connected to DMA1 channel 7
165 // FIXME: Strange programming sequence as specified in manual
167 dma_channel_reset(DMA1, 7);
169 dma_set_peripheral_address(DMA1, 7, (u32) &TIM_CCR3(TIM4));
170 dma_set_memory_address(DMA1, 7, (u32) neopixel_buf);
171 dma_set_number_of_data(DMA1, 7, ARRAY_SIZE(neopixel_buf));
172 dma_set_priority(DMA1, 7, DMA_CCR_PL_VERY_HIGH);
174 dma_set_read_from_memory(DMA1, 7);
175 dma_enable_circular_mode(DMA1, 7);
177 dma_set_memory_size(DMA1, 7, DMA_CCR_MSIZE_8BIT);
178 dma_enable_memory_increment_mode(DMA1, 7);
180 dma_set_peripheral_size(DMA1, 7, DMA_CCR_PSIZE_16BIT);
181 dma_disable_peripheral_increment_mode(DMA1, 7);
183 dma_enable_channel(DMA1, 7);
185 timer_set_prescaler(TIM4, 0);
186 timer_set_mode(TIM4, TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP);
187 timer_disable_preload(TIM4);
188 timer_set_period(TIM4, NPIX_PERIOD - 1);
190 timer_set_oc_mode(TIM4, TIM_OC3, TIM_OCM_PWM1);
191 timer_set_oc_value(TIM4, TIM_OC3, 0);
192 timer_set_oc_polarity_high(TIM4, TIM_OC3);
193 timer_enable_oc_output(TIM4, TIM_OC3);
195 timer_set_dma_on_update_event(TIM4);
196 TIM_DIER(TIM4) |= TIM_DIER_UDE;
198 timer_enable_counter(TIM4);
211 debug_printf("Hello, world!\n");
214 // wait_for_interrupt();
216 for (int i=4; i<8; i++)
217 neopixel_buf[64+i] = B1;
220 for (int i=4; i<8; i++)
221 neopixel_buf[64+i] = B0;