]> mj.ucw.cz Git - home-hw.git/commitdiff
test-neopixel-square: init
authorMartin Mares <mj@ucw.cz>
Sun, 24 Mar 2024 12:13:23 +0000 (13:13 +0100)
committerMartin Mares <mj@ucw.cz>
Sun, 24 Mar 2024 12:13:23 +0000 (13:13 +0100)
test-neopixel-square/Makefile [new file with mode: 0644]
test-neopixel-square/README [new file with mode: 0644]
test-neopixel-square/config.h [new file with mode: 0644]
test-neopixel-square/main.c [new file with mode: 0644]
test-neopixel/README

diff --git a/test-neopixel-square/Makefile b/test-neopixel-square/Makefile
new file mode 100644 (file)
index 0000000..fdc81f8
--- /dev/null
@@ -0,0 +1,6 @@
+ROOT=..
+BINARY=test
+OBJS=main.o
+LIB_OBJS=util-debug.o
+
+include $(ROOT)/mk/bluepill.mk
diff --git a/test-neopixel-square/README b/test-neopixel-square/README
new file mode 100644 (file)
index 0000000..2d42d67
--- /dev/null
@@ -0,0 +1,30 @@
+Assignment of peripherals and pins
+==================================
+
+USART1 debugging
+TIM4   Neopixel control
+
+
+                          Blue Pill pinout
+                       +--------------------+
+                       | VBATT         3.3V |
+BluePill LED           | PC13           GND |  Neopixel ground
+                       | PC14            5V |  Neopixel power
+                       | PC15           PB9 |
+                       | PA0            PB8 |  TIM4_CH3 - Neopixel data (pull up to +5V)
+                       | PA1            PB7 |
+                       | PA2            PB6 |
+                       | PA3            PB5 |
+                       | PA4            PB4 |
+                       | PA5            PB3 |
+                       | PA6           PA15 |
+                       | PA7           PA12 |
+                       | PB0           PA11 |
+                       | PB1           PA10 |  RXD1 - debugging console
+                       | PB10           PA9 |  TXD1 - debugging console
+                       | PB11           PA8 |
+                       | RESET         PB15 |
+                       | 3.3 V         PB14 |
+                       | GND           PB13 |
+                       | GND           PB12 |
+                       +--------------------+
diff --git a/test-neopixel-square/config.h b/test-neopixel-square/config.h
new file mode 100644 (file)
index 0000000..312c7be
--- /dev/null
@@ -0,0 +1,14 @@
+/*
+ *     Test Gadget -- Configuration
+ *
+ *     (c) 2020 Martin Mareš <mj@ucw.cz>
+ */
+
+// Processor clock
+
+#define CPU_CLOCK_MHZ 72
+
+// Debugging port
+
+#define DEBUG_USART USART1
+#define DEBUG_LED_BLUEPILL
diff --git a/test-neopixel-square/main.c b/test-neopixel-square/main.c
new file mode 100644 (file)
index 0000000..fdfe0ab
--- /dev/null
@@ -0,0 +1,447 @@
+/*
+ *     Neopixel (WS2812B) Test
+ *
+ *     (c) 2022 Martin Mareš <mj@ucw.cz>
+ */
+
+#include "util.h"
+
+#include <libopencm3/cm3/cortex.h>
+#include <libopencm3/cm3/nvic.h>
+#include <libopencm3/cm3/systick.h>
+#include <libopencm3/cm3/scb.h>
+#include <libopencm3/stm32/dma.h>
+#include <libopencm3/stm32/gpio.h>
+#include <libopencm3/stm32/rcc.h>
+#include <libopencm3/stm32/timer.h>
+#include <libopencm3/stm32/usart.h>
+
+#include <string.h>
+
+/*** Hardware init ***/
+
+static void clock_init(void)
+{
+       rcc_clock_setup_pll(&rcc_hse_configs[RCC_CLOCK_HSE8_72MHZ]);
+
+       rcc_periph_clock_enable(RCC_GPIOA);
+       rcc_periph_clock_enable(RCC_GPIOB);
+       rcc_periph_clock_enable(RCC_GPIOC);
+       rcc_periph_clock_enable(RCC_USART1);
+       rcc_periph_clock_enable(RCC_TIM4);
+       rcc_periph_clock_enable(RCC_DMA1);
+
+       rcc_periph_reset_pulse(RST_GPIOA);
+       rcc_periph_reset_pulse(RST_GPIOB);
+       rcc_periph_reset_pulse(RST_GPIOC);
+       rcc_periph_reset_pulse(RST_USART1);
+       rcc_periph_reset_pulse(RST_TIM4);
+}
+
+static void gpio_init(void)
+{
+       // PA9 = TXD1 for debugging console
+       // PA10 = RXD1 for debugging console
+       gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO9);
+       gpio_set_mode(GPIOA, GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, GPIO10);
+
+       // PC13 = BluePill LED
+       gpio_set_mode(GPIOC, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO13);
+       gpio_clear(GPIOC, GPIO13);
+
+       // PB8 = data for Neopixel
+       gpio_set_mode(GPIOB, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_OPENDRAIN, GPIO8);
+}
+
+static void usart_init(void)
+{
+       usart_set_baudrate(USART1, 115200);
+       usart_set_databits(USART1, 8);
+       usart_set_stopbits(USART1, USART_STOPBITS_1);
+       usart_set_mode(USART1, USART_MODE_TX);
+       usart_set_parity(USART1, USART_PARITY_NONE);
+       usart_set_flow_control(USART1, USART_FLOWCONTROL_NONE);
+
+       usart_enable(USART1);
+}
+
+/*** System ticks ***/
+
+static volatile u32 ms_ticks;
+
+void sys_tick_handler(void)
+{
+       ms_ticks++;
+}
+
+static void tick_init(void)
+{
+       systick_set_frequency(1000, CPU_CLOCK_MHZ * 1000000);
+       systick_counter_enable();
+       systick_interrupt_enable();
+}
+
+static void delay_ms(uint ms)
+{
+       u32 start_ticks = ms_ticks;
+       while (ms_ticks - start_ticks < ms)
+               ;
+}
+
+/*** Neopixels ***/
+
+#define NPIX_PERIOD 90         // timer runs on 72 MHz, so 90 periods = 1250 ns
+#define B0 30
+#define B1 60
+
+byte neopixel_buf[] = {
+       // 128 cycles low: reset (has to be longer than in the datasheet)
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+
+       // G7 G6 G5 G4 G3 G2 G1 G0
+       // R7 R6 R5 R4 R3 R2 R1 R0
+       // B7 B6 B5 B4 B3 B2 B1 B0
+
+       B0, B0, B0, B0, B1, B1, B1, B1,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B1, B1, B1, B1,
+
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B1, B1, B1, B1,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+
+       B0, B0, B0, B0, B1, B1, B1, B1,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B1, B1, B1, B1,
+
+       B0, B0, B0, B0, B1, B1, B1, B1,
+       B0, B0, B0, B0, B1, B1, B1, B1,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B1, B1, B1, B1,
+       B0, B0, B0, B0, B1, B1, B1, B1,
+
+       B0, B0, B0, B0, B1, B1, B1, B1,
+       B0, B0, B0, B0, B1, B1, B1, B1,
+       B0, B0, B0, B0, B1, B1, B1, B1,
+
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B1, B1, B1, B1,
+
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B1, B1, B1, B1,
+
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B1, B1, B1, B1,
+
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B1, B1, B1, B1,
+
+       B0, B0, B0, B0, B1, B1, B1, B1,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+       B0, B0, B0, B0, B0, B0, B0, B0,
+
+       B0, B0, B0, B0, B1, B1, B1, B1,
+       B0, B0, B0, B0, B1, B1, B1, B1,
+       B0, B0, B0, B0, B1, B1, B1, B1,
+};
+
+static void neopixel_init(void)
+{
+       // TIM4 update is connected to DMA1 channel 7
+
+       // FIXME: Strange programming sequence as specified in manual
+
+       dma_channel_reset(DMA1, 7);
+
+       dma_set_peripheral_address(DMA1, 7, (u32) &TIM_CCR3(TIM4));
+       dma_set_memory_address(DMA1, 7, (u32) neopixel_buf);
+       dma_set_number_of_data(DMA1, 7, ARRAY_SIZE(neopixel_buf));
+       dma_set_priority(DMA1, 7, DMA_CCR_PL_VERY_HIGH);
+
+       dma_set_read_from_memory(DMA1, 7);
+       dma_enable_circular_mode(DMA1, 7);
+
+       dma_set_memory_size(DMA1, 7, DMA_CCR_MSIZE_8BIT);
+       dma_enable_memory_increment_mode(DMA1, 7);
+
+       dma_set_peripheral_size(DMA1, 7, DMA_CCR_PSIZE_16BIT);
+       dma_disable_peripheral_increment_mode(DMA1, 7);
+
+       dma_enable_channel(DMA1, 7);
+
+       timer_set_prescaler(TIM4, 0);
+       timer_set_mode(TIM4, TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP);
+       timer_disable_preload(TIM4);
+       timer_set_period(TIM4, NPIX_PERIOD - 1);
+
+       timer_set_oc_mode(TIM4, TIM_OC3, TIM_OCM_PWM1);
+       timer_set_oc_value(TIM4, TIM_OC3, 0);
+       timer_set_oc_polarity_high(TIM4, TIM_OC3);
+       timer_enable_oc_output(TIM4, TIM_OC3);
+
+       timer_set_dma_on_update_event(TIM4);
+       TIM_DIER(TIM4) |= TIM_DIER_UDE;
+
+       timer_enable_counter(TIM4);
+}
+
+/*** Main ***/
+
+int main(void)
+{
+       clock_init();
+       gpio_init();
+       usart_init();
+       tick_init();
+       neopixel_init();
+
+       debug_printf("Hello, world!\n");
+
+#if 0
+       for (int i=0; i<24*64; i++)
+               neopixel_buf[128+i] = B1;
+#endif
+
+       for (;;) {
+               // wait_for_interrupt();
+               debug_led(1);
+               for (int i=4; i<8; i++)
+                       neopixel_buf[128+24*63+i] = B1;
+               delay_ms(100);
+               debug_led(0);
+               for (int i=4; i<8; i++)
+                       neopixel_buf[128+24*63+i] = B0;
+               delay_ms(500);
+       }
+
+       return 0;
+}
index bad9e94aff65f25125de8128690f9c8b39a3aef8..2d42d67126a5a7ad2ddf53149455eb450e18086d 100644 (file)
@@ -11,7 +11,7 @@ TIM4  Neopixel control
 BluePill LED           | PC13           GND |  Neopixel ground
                        | PC14            5V |  Neopixel power
                        | PC15           PB9 |
-                       | PA0            PB8 |  TIM4_CH3 - Neopixel data
+                       | PA0            PB8 |  TIM4_CH3 - Neopixel data (pull up to +5V)
                        | PA1            PB7 |
                        | PA2            PB6 |
                        | PA3            PB5 |