summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorxengineering <mail2xengineering@protonmail.com>2020-10-25 13:07:54 +0100
committerxengineering <mail2xengineering@protonmail.com>2020-10-25 13:07:54 +0100
commit58d3787ca563b7d6a2cb4e0a1ab7fdde67fd5557 (patch)
tree42115a58b60bdd7fa027b8b37cac7e76e7b74fab
parent9435a85605d7efc75642491c85b0942bd558fcec (diff)
downloadstm32f103c8-examples-58d3787ca563b7d6a2cb4e0a1ab7fdde67fd5557.tar
stm32f103c8-examples-58d3787ca563b7d6a2cb4e0a1ab7fdde67fd5557.tar.zst
stm32f103c8-examples-58d3787ca563b7d6a2cb4e0a1ab7fdde67fd5557.zip
Add ws2812 Code
-rw-r--r--libraries/ws2812.c125
-rw-r--r--libraries/ws2812.h38
-rw-r--r--ws2812/Makefile34
-rw-r--r--ws2812/main.c76
4 files changed, 273 insertions, 0 deletions
diff --git a/libraries/ws2812.c b/libraries/ws2812.c
new file mode 100644
index 0000000..41d4fb5
--- /dev/null
+++ b/libraries/ws2812.c
@@ -0,0 +1,125 @@
+
+
+/*
+
+# WS2812 Library for libopencm3
+
+Please mind these restrictions:
+
+- Only usable with libopencm3
+- Newer versions of libopencm3 may be not compatibel (libopencm3 api is not stable yet)
+- Just usable with a clock frequency of 80 MHz
+- You have to setup the clock and gpio yourself
+
+*/
+
+
+#include "ws2812.h"
+
+#define NUMBER_NOPS_RESET 1080 // > 50 µs --> 60 µs (to be sure) = 4320 cycles @ 72 MHz = 1080 nops
+#define NUMBER_NOPS_LONG 16 // 0.9 µs = 64.8 cycles @ 72 MHz = 16.2 nops --> 11.1 ns timing error
+#define NUMBER_NOPS_SHORT 6 // 0.35 µs = 25.2 cycles @ 72 MHz = 6.3 nops --> 16.7 ns timing error
+
+
+void ws2812_init(ws2812_init_typedef *control_struct, uint32_t port, uint16_t pin, uint32_t array_length, uint32_t matrix_width)
+{
+ control_struct->gpio_port = port;
+ control_struct->gpio_pin = pin;
+ control_struct->array_length = array_length;
+ control_struct->matrix_width = matrix_width;
+ control_struct->led_array = malloc(sizeof(uint8_t[array_length][3]));
+ ws2812_clear_buffer(control_struct);
+ ws2812_send_reset(control_struct);
+}
+
+
+void ws2812_send_reset(ws2812_init_typedef *control_struct)
+{
+ gpio_clear(control_struct->gpio_port, control_struct->gpio_pin);
+ for (int i = 0; i < NUMBER_NOPS_RESET; i++) {
+ __asm__("nop");
+ }
+}
+
+
+void ws2812_send_zero(ws2812_init_typedef *control_struct)
+{
+ gpio_set(control_struct->gpio_port, control_struct->gpio_pin);
+ for (int i = 0; i < NUMBER_NOPS_SHORT; i++) {
+ __asm__("nop");
+ }
+ gpio_clear(control_struct->gpio_port, control_struct->gpio_pin);
+ for (int i = 0; i < NUMBER_NOPS_LONG; i++) {
+ __asm__("nop");
+ }
+}
+
+
+void ws2812_send_one(ws2812_init_typedef *control_struct)
+{
+ gpio_set(control_struct->gpio_port, control_struct->gpio_pin);
+ for (int i = 0; i < NUMBER_NOPS_LONG; i++) {
+ __asm__("nop");
+ }
+ gpio_clear(control_struct->gpio_port, control_struct->gpio_pin);
+ for (int i = 0; i < NUMBER_NOPS_SHORT; i++) {
+ __asm__("nop");
+ }
+}
+
+
+void ws2812_send_byte(ws2812_init_typedef *control_struct, uint8_t data)
+{
+ for (int i=7; i>=0; i--){
+ if ( (data >> i) & 0x01 ){
+ ws2812_send_one(control_struct);
+ }
+ else {
+ ws2812_send_zero(control_struct);
+ }
+ }
+}
+
+
+void ws2812_send_led(ws2812_init_typedef *control_struct, uint8_t red, uint8_t green, uint8_t blue)
+{
+ ws2812_send_byte(control_struct, green);
+ ws2812_send_byte(control_struct, red);
+ ws2812_send_byte(control_struct, blue);
+}
+
+
+void ws2812_write_leds(ws2812_init_typedef *control_struct)
+{
+ for(uint32_t i=0; i<(control_struct->array_length); i++){
+ ws2812_send_led(
+ control_struct,
+ control_struct->led_array[i][0], // red
+ control_struct->led_array[i][1], // green
+ control_struct->led_array[i][2] // blue
+ );
+ }
+ ws2812_send_reset(control_struct);
+}
+
+
+void ws2812_set_array_led(ws2812_init_typedef *control_struct, uint32_t index, uint8_t red, uint8_t green, uint8_t blue)
+{
+ control_struct->led_array[index][0] = red;
+ control_struct->led_array[index][1] = green;
+ control_struct->led_array[index][2] = blue;
+}
+
+
+void ws2812_set_matrix_led(ws2812_init_typedef *control_struct, uint32_t x, uint32_t y, uint8_t red, uint8_t green, uint8_t blue)
+{
+ ws2812_set_array_led(control_struct, (x + y * (control_struct->matrix_width)), red, green, blue);
+}
+
+
+void ws2812_clear_buffer(ws2812_init_typedef *control_struct)
+{
+ for (uint32_t i=0; i<control_struct->array_length; i++){
+ ws2812_set_array_led(control_struct, i, 0, 0, 0);
+ }
+}
diff --git a/libraries/ws2812.h b/libraries/ws2812.h
new file mode 100644
index 0000000..e4f0754
--- /dev/null
+++ b/libraries/ws2812.h
@@ -0,0 +1,38 @@
+
+
+#ifndef WS2812_H
+#define WS2812_H
+
+
+#include <stdlib.h>
+#include <libopencm3/stm32/gpio.h>
+
+
+typedef struct ws2812_init_typedef{
+
+ uint32_t gpio_port;
+ uint16_t gpio_pin;
+ uint32_t array_length;
+ uint32_t matrix_width;
+ uint8_t (*led_array)[3];
+
+}ws2812_init_typedef;
+
+
+void ws2812_init(ws2812_init_typedef *control_struct, uint32_t port, uint16_t pin, uint32_t array_length, uint32_t matrix_width);
+
+void ws2812_send_reset(ws2812_init_typedef *control_struct);
+void ws2812_send_zero(ws2812_init_typedef *control_struct);
+void ws2812_send_one(ws2812_init_typedef *control_struct);
+
+void ws2812_send_byte(ws2812_init_typedef *control_struct, uint8_t data);
+void ws2812_send_led(ws2812_init_typedef *control_struct, uint8_t red, uint8_t green, uint8_t blue);
+void ws2812_write_leds(ws2812_init_typedef *control_struct);
+
+void ws2812_set_array_led(ws2812_init_typedef *control_struct, uint32_t index, uint8_t red, uint8_t green, uint8_t blue);
+void ws2812_set_matrix_led(ws2812_init_typedef *control_struct, uint32_t x, uint32_t y, uint8_t red, uint8_t green, uint8_t blue);
+
+void ws2812_clear_buffer(ws2812_init_typedef *control_struct);
+
+
+#endif /* WS2812_H */
diff --git a/ws2812/Makefile b/ws2812/Makefile
new file mode 100644
index 0000000..8973ef6
--- /dev/null
+++ b/ws2812/Makefile
@@ -0,0 +1,34 @@
+PROJECT = ws2812
+BUILD_DIR = bin
+
+SHARED_DIR = ../libraries
+CFILES = main.c
+CFILES += ws2812.c
+#AFILES += api-asm.S
+
+# TODO - you will need to edit these two lines!
+DEVICE=stm32f103c8
+#OOCD_FILE = board/stm32f4discovery.cfg
+
+# You shouldn't have to edit anything below here.
+VPATH += $(SHARED_DIR)
+INCLUDES += $(patsubst %,-I%, . $(SHARED_DIR))
+OPENCM3_DIR=../libopencm3
+
+include $(OPENCM3_DIR)/mk/genlink-config.mk
+include ../rules.mk
+include $(OPENCM3_DIR)/mk/genlink-rules.mk
+
+
+# Black Magic Probe:
+
+GDB=/usr/bin/arm-none-eabi-gdb
+BMP_DEVICE=/dev/ttyACM0
+
+bmp: $(PROJECT).elf
+ $(GDB) $(PROJECT).elf \
+ -ex 'set confirm off' \
+ -ex 'target extended-remote $(BMP_DEVICE)' \
+ -ex 'monitor swdp_scan' \
+ -ex 'attach 1'
+
diff --git a/ws2812/main.c b/ws2812/main.c
new file mode 100644
index 0000000..926cd68
--- /dev/null
+++ b/ws2812/main.c
@@ -0,0 +1,76 @@
+
+
+#include <libopencm3/stm32/rcc.h>
+#include <libopencm3/stm32/gpio.h>
+
+#include "ws2812.h"
+
+
+#define DELAY 30000 // 18,000,000 nops are one second
+#define BRIGHTNESS 100
+
+
+void clock_init(void);
+void gpio_init(void);
+void delay(void);
+
+
+ws2812_init_typedef ws2812;
+
+
+int main(void)
+{
+ clock_init();
+ gpio_init();
+ ws2812_init(&ws2812, GPIOB, GPIO13, 1, 1);
+
+ while(1){
+ /*ws2812_send_led(&ws2812, BRIGHTNESS, 0, 0);
+ delay();
+ ws2812_send_led(&ws2812, 0, BRIGHTNESS, 0);
+ delay();
+ ws2812_send_led(&ws2812, 0, 0, BRIGHTNESS);
+ delay();
+ ws2812_send_led(&ws2812, BRIGHTNESS, BRIGHTNESS, BRIGHTNESS);
+ delay();*/
+
+ for (uint16_t i=0; i<=255; i++){
+ ws2812_send_led(&ws2812, i, 0, 0);
+ delay();
+ }
+ for (uint16_t i=255; i>0; i--){
+ ws2812_send_led(&ws2812, i, 0, 0);
+ delay();
+ }
+ }
+
+ return 0;
+}
+
+
+void clock_init(void)
+{
+ rcc_clock_setup_in_hse_12mhz_out_72mhz();
+ rcc_periph_clock_enable(RCC_GPIOB); // for ws2812
+ rcc_periph_clock_enable(RCC_GPIOC); // for PC13 blinking
+}
+
+
+void gpio_init(void)
+{
+ // on board led blinking
+ gpio_set_mode(GPIOC, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO13);
+ gpio_set(GPIOC, GPIO13);
+
+ // ws2812 output pin
+ gpio_set_mode(GPIOB, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO13);
+ gpio_set(GPIOB, GPIO13);
+}
+
+
+void delay(void)
+{
+ for (int i = 0; i < DELAY; i++) {
+ __asm__("nop");
+ }
+}