From 58d3787ca563b7d6a2cb4e0a1ab7fdde67fd5557 Mon Sep 17 00:00:00 2001
From: xengineering <mail2xengineering@protonmail.com>
Date: Sun, 25 Oct 2020 13:07:54 +0100
Subject: Add ws2812 Code

---
 libraries/ws2812.c | 125 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 libraries/ws2812.h |  38 ++++++++++++++++
 ws2812/Makefile    |  34 +++++++++++++++
 ws2812/main.c      |  76 ++++++++++++++++++++++++++++++++
 4 files changed, 273 insertions(+)
 create mode 100644 libraries/ws2812.c
 create mode 100644 libraries/ws2812.h
 create mode 100644 ws2812/Makefile
 create mode 100644 ws2812/main.c

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");
+	}
+}
-- 
cgit v1.2.3-70-g09d2