aboutsummaryrefslogtreecommitdiff
path: root/drivers/arm/ws2812.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/arm/ws2812.c')
-rw-r--r--drivers/arm/ws2812.c101
1 files changed, 100 insertions, 1 deletions
diff --git a/drivers/arm/ws2812.c b/drivers/arm/ws2812.c
index 2094e5009..b076eff33 100644
--- a/drivers/arm/ws2812.c
+++ b/drivers/arm/ws2812.c
@@ -1 +1,100 @@
1#error("NOT SUPPORTED") \ No newline at end of file 1#include "quantum.h"
2#include "ws2812.h"
3#include "ch.h"
4#include "hal.h"
5
6/* Adapted from https://github.com/bigjosh/SimpleNeoPixelDemo/ */
7
8#ifndef NOP_FUDGE
9# if defined(STM32F1XX) || defined(STM32F1xx) || defined(STM32F0XX) || defined(STM32F0xx) || defined(STM32F3XX) || defined(STM32F3xx) || defined(STM32L0XX) || defined(STM32L0xx)
10# define NOP_FUDGE 0.4
11# else
12# error("NOP_FUDGE configuration required")
13# define NOP_FUDGE 1 // this just pleases the compile so the above error is easier to spot
14# endif
15#endif
16
17#define NUMBER_NOPS 6
18#define CYCLES_PER_SEC (STM32_SYSCLK / NUMBER_NOPS * NOP_FUDGE)
19#define NS_PER_SEC (1000000000L) // Note that this has to be SIGNED since we want to be able to check for negative values of derivatives
20#define NS_PER_CYCLE (NS_PER_SEC / CYCLES_PER_SEC)
21#define NS_TO_CYCLES(n) ((n) / NS_PER_CYCLE)
22
23#define wait_ns(x) \
24 do { \
25 for (int i = 0; i < NS_TO_CYCLES(x); i++) { \
26 __asm__ volatile("nop\n\t" \
27 "nop\n\t" \
28 "nop\n\t" \
29 "nop\n\t" \
30 "nop\n\t" \
31 "nop\n\t"); \
32 } \
33 } while (0)
34
35// These are the timing constraints taken mostly from the WS2812 datasheets
36// These are chosen to be conservative and avoid problems rather than for maximum throughput
37
38#define T1H 900 // Width of a 1 bit in ns
39#define T1L (1250 - T1H) // Width of a 1 bit in ns
40
41#define T0H 350 // Width of a 0 bit in ns
42#define T0L (1250 - T0H) // Width of a 0 bit in ns
43
44// The reset gap can be 6000 ns, but depending on the LED strip it may have to be increased
45// to values like 600000 ns. If it is too small, the pixels will show nothing most of the time.
46#define RES 10000 // Width of the low gap between bits to cause a frame to latch
47
48void sendByte(uint8_t byte) {
49 // WS2812 protocol wants most significant bits first
50 for (unsigned char bit = 0; bit < 8; bit++) {
51 bool is_one = byte & (1 << (7 - bit));
52 // using something like wait_ns(is_one ? T1L : T0L) here throws off timings
53 if (is_one) {
54 // 1
55 writePinHigh(RGB_DI_PIN);
56 wait_ns(T1H);
57 writePinLow(RGB_DI_PIN);
58 wait_ns(T1L);
59 } else {
60 // 0
61 writePinHigh(RGB_DI_PIN);
62 wait_ns(T0H);
63 writePinLow(RGB_DI_PIN);
64 wait_ns(T0L);
65 }
66 }
67}
68
69void ws2812_init(void) { setPinOutput(RGB_DI_PIN); }
70
71// Setleds for standard RGB
72void ws2812_setleds(LED_TYPE *ledarray, uint16_t leds) {
73 static bool s_init = false;
74 if (!s_init) {
75 ws2812_init();
76 s_init = true;
77 }
78
79 // this code is very time dependent, so we need to disable interrupts
80 chSysLock();
81
82 for (uint8_t i = 0; i < leds; i++) {
83 // WS2812 protocol dictates grb order
84 sendByte(ledarray[i].g);
85 sendByte(ledarray[i].r);
86 sendByte(ledarray[i].b);
87 }
88
89 wait_ns(RES);
90
91 chSysUnlock();
92}
93
94// Setleds for SK6812RGBW
95void ws2812_setleds_rgbw(LED_TYPE *ledarray, uint16_t leds) {
96// not supported - for now error out if its enabled
97#ifdef RGBW
98# error "RGBW not supported"
99#endif
100}