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
94 #define NPIX_RESET 128 // the chip needs longer reset pulse than documented
95 #define NPIX_NUM_LEDS 64
99 byte neopixel_buf[NPIX_RESET + 24*NPIX_NUM_LEDS];
101 static void neopixel_set(uint led, byte r, byte g, byte b)
103 byte *buf = &neopixel_buf[NPIX_RESET + 24*led];
105 for (uint m=0x80; m; m >>= 1)
106 *buf++ = (g & m) ? B1 : B0;
107 for (uint m=0x80; m; m >>= 1)
108 *buf++ = (r & m) ? B1 : B0;
109 for (uint m=0x80; m; m >>= 1)
110 *buf++ = (b & m) ? B1 : B0;
114 static void neopixel_init(void)
116 for (uint i=0; i < NPIX_NUM_LEDS; i++)
117 neopixel_set(i, 7, 7, 7);
119 // TIM4 update is connected to DMA1 channel 7
121 // FIXME: Strange programming sequence as specified in manual
123 dma_channel_reset(DMA1, 7);
125 dma_set_peripheral_address(DMA1, 7, (u32) &TIM_CCR3(TIM4));
126 dma_set_memory_address(DMA1, 7, (u32) neopixel_buf);
127 dma_set_number_of_data(DMA1, 7, ARRAY_SIZE(neopixel_buf));
128 dma_set_priority(DMA1, 7, DMA_CCR_PL_VERY_HIGH);
130 dma_set_read_from_memory(DMA1, 7);
131 dma_enable_circular_mode(DMA1, 7);
133 dma_set_memory_size(DMA1, 7, DMA_CCR_MSIZE_8BIT);
134 dma_enable_memory_increment_mode(DMA1, 7);
136 dma_set_peripheral_size(DMA1, 7, DMA_CCR_PSIZE_16BIT);
137 dma_disable_peripheral_increment_mode(DMA1, 7);
139 dma_enable_channel(DMA1, 7);
141 timer_set_prescaler(TIM4, 0);
142 timer_set_mode(TIM4, TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP);
143 timer_disable_preload(TIM4);
144 timer_set_period(TIM4, NPIX_PERIOD - 1);
146 timer_set_oc_mode(TIM4, TIM_OC3, TIM_OCM_PWM1);
147 timer_set_oc_value(TIM4, TIM_OC3, 0);
148 timer_set_oc_polarity_high(TIM4, TIM_OC3);
149 timer_enable_oc_output(TIM4, TIM_OC3);
151 timer_set_dma_on_update_event(TIM4);
152 TIM_DIER(TIM4) |= TIM_DIER_UDE;
154 timer_enable_counter(TIM4);
167 debug_printf("Hello, world!\n");
172 // wait_for_interrupt();
174 // neopixel_set(NPIX_NUM_LEDS-1, 0, 0x7f, 0);
175 neopixel_set(i, 0, 0, 7);
177 neopixel_set(i, 0, 63, 0);
180 // neopixel_set(NPIX_NUM_LEDS-1, 0, 0, 0x7f);