]> mj.ucw.cz Git - home-hw.git/blob - test-neopixel/main.c
Rainbow: LEDs have optional owners
[home-hw.git] / test-neopixel / main.c
1 /*
2  *      Neopixel (WS2812B) Test
3  *
4  *      (c) 2022 Martin Mareš <mj@ucw.cz>
5  */
6
7 #include "util.h"
8
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>
18
19 #include <string.h>
20
21 /*** Hardware init ***/
22
23 static void clock_init(void)
24 {
25         rcc_clock_setup_pll(&rcc_hse_configs[RCC_CLOCK_HSE8_72MHZ]);
26
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);
33
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);
39 }
40
41 static void gpio_init(void)
42 {
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);
47
48         // PC13 = BluePill LED
49         gpio_set_mode(GPIOC, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO13);
50         gpio_clear(GPIOC, GPIO13);
51
52         // PB8 = data for Neopixel
53         gpio_set_mode(GPIOB, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_OPENDRAIN, GPIO8);
54 }
55
56 static void usart_init(void)
57 {
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);
64
65         usart_enable(USART1);
66 }
67
68 /*** System ticks ***/
69
70 static volatile u32 ms_ticks;
71
72 void sys_tick_handler(void)
73 {
74         ms_ticks++;
75 }
76
77 static void tick_init(void)
78 {
79         systick_set_frequency(1000, CPU_CLOCK_MHZ * 1000000);
80         systick_counter_enable();
81         systick_interrupt_enable();
82 }
83
84 static void delay_ms(uint ms)
85 {
86         u32 start_ticks = ms_ticks;
87         while (ms_ticks - start_ticks < ms)
88                 ;
89 }
90
91 /*** Neopixels ***/
92
93 #define NPIX_PERIOD 90          // timer runs on 72 MHz, so 90 periods = 1250 ns
94 #define B0 30
95 #define B1 60
96
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,
107
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
111
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,
115
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,
119
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,
123
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,
127
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,
131
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,
135
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,
139
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,
143
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,
147
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,
151
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,
155
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,
159 };
160
161 static void neopixel_init(void)
162 {
163         // TIM4 update is connected to DMA1 channel 7
164
165         // FIXME: Strange programming sequence as specified in manual
166
167         dma_channel_reset(DMA1, 7);
168
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);
173
174         dma_set_read_from_memory(DMA1, 7);
175         dma_enable_circular_mode(DMA1, 7);
176
177         dma_set_memory_size(DMA1, 7, DMA_CCR_MSIZE_8BIT);
178         dma_enable_memory_increment_mode(DMA1, 7);
179
180         dma_set_peripheral_size(DMA1, 7, DMA_CCR_PSIZE_16BIT);
181         dma_disable_peripheral_increment_mode(DMA1, 7);
182
183         dma_enable_channel(DMA1, 7);
184
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);
189
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);
194
195         timer_set_dma_on_update_event(TIM4);
196         TIM_DIER(TIM4) |= TIM_DIER_UDE;
197
198         timer_enable_counter(TIM4);
199 }
200
201 /*** Main ***/
202
203 int main(void)
204 {
205         clock_init();
206         gpio_init();
207         usart_init();
208         tick_init();
209         neopixel_init();
210
211         debug_printf("Hello, world!\n");
212
213         for (;;) {
214                 // wait_for_interrupt();
215                 debug_led(1);
216                 for (int i=4; i<8; i++)
217                         neopixel_buf[64+i] = B1;
218                 delay_ms(100);
219                 debug_led(0);
220                 for (int i=4; i<8; i++)
221                         neopixel_buf[64+i] = B0;
222                 delay_ms(500);
223         }
224
225         return 0;
226 }