#ifndef WS2812B_H #define WS2812B_H #include "driver/gpio.h" #include "rom/ets_sys.h" #include "xtensa/core-macros.h" #include "../../data/Color.h" template class WS2812B { #define WS2812B_PIN GPIO_NUM_27 #define LED_SET_PIN_TO_OUTPUT gpio_set_direction(WS2812B_PIN, GPIO_MODE_OUTPUT); #define LED_SET_PIN_TO_INPUT gpio_set_direction(WS2812B_PIN, GPIO_MODE_INPUT); //#define LED_SET_PIN_H gpio_set_level(WS2812B_PIN, 1) //#define LED_SET_PIN_L gpio_set_level(WS2812B_PIN, 0) //#define ENABLE_INTERRUPTS XTOS_RESTORE_INTLEVEL(ilevel); //#define DISABLE_INTERRUPTS uint32_t volatile register ilevel = XTOS_DISABLE_ALL_INTERRUPTS #define LED_SET_PIN_H GPIO.out_w1ts |= (1 << WS2812B_PIN) #define LED_SET_PIN_L GPIO.out_w1tc |= (1 << WS2812B_PIN) #define portDISABLE_INTERRUPTS() do { XTOS_SET_INTLEVEL(XCHAL_EXCM_LEVEL); portbenchmarkINTERRUPT_DISABLE(); } while (0) #define portENABLE_INTERRUPTS() do { portbenchmarkINTERRUPT_RESTORE(0); XTOS_SET_INTLEVEL(0); } while (0) #define ENABLE_INTERRUPTS() portENABLE_INTERRUPTS() #define DISABLE_INTERRUPTS() portDISABLE_INTERRUPTS() #define SLEEP_US(us) ets_delay_us(us) //#define NS_PER_TICK ( (1000ul*1000ul*1000ul) / (80ul*1000ul*1000ul) ) // Color* colors; /** enable/disable each led */ bool enabled[numLEDs] = {true}; /** color-value for each attached LED */ Color colors[numLEDs]; public: /** ctor */ WS2812B() { init(); } void init() { LED_SET_PIN_TO_OUTPUT; } /** set the color for the given LED */ void setColor(const uint8_t idx, const Color rgb) { colors[idx] = rgb; } /** set the color for all LEDs */ void setColor(const Color rgb) { for (int idx = 0; idx < numLEDs; ++idx) { colors[idx] = rgb; } } /** enable/disable the given LED */ void setEnabled(const uint8_t idx, const bool en) { enabled[idx] = en; } /** enable/disable all LEDs */ void setEnabled(const bool en) { for (int idx = 0; idx < numLEDs; ++idx) { enabled[idx] = en; } } /** is the given LED enabled? */ bool isEnabled(const uint8_t idx) const { return enabled[idx]; } Color& getColor(const uint8_t idx) { return colors[idx]; } /** flush configured changes */ IRAM_ATTR void flush() { SLEEP_US(50); DISABLE_INTERRUPTS(); LED_SET_PIN_TO_OUTPUT; // process each LED for (int i = 0; i < 8; ++i) { //if (i == 0) {LED_SET_PIN_TO_INPUT;} //if (i > 0) {LED_SET_PIN_TO_OUTPUT;} const Color rgb = colors[i]; // send each LEDs 24-bit GRB data //if (enabled[i]) { // sendByte(rgb.g); // sendByte(rgb.r); // sendByte(rgb.b); //} else { sendByte(1); sendByte(2); sendByte(3); //} } ENABLE_INTERRUPTS(); reset(); } private: IRAM_ATTR __attribute__((always_inline)) inline void sendByte(const uint8_t b) { if (b & 0b10000000) {send1();} else {send0();} if (b & 0b01000000) {send1();} else {send0();} if (b & 0b00100000) {send1();} else {send0();} if (b & 0b00010000) {send1();} else {send0();} if (b & 0b00001000) {send1();} else {send0();} if (b & 0b00000100) {send1();} else {send0();} if (b & 0b00000010) {send1();} else {send0();} if (b & 0b00000001) {send1();} else {send0();} } IRAM_ATTR __attribute__((always_inline)) inline void send1() { // 800ns high, 450ns low LED_SET_PIN_H; delay800(); LED_SET_PIN_L; delay100(); } IRAM_ATTR __attribute__((always_inline)) inline void send0() { // 400ns high, 850ns low LED_SET_PIN_H; delay100(); //delay100(); LED_SET_PIN_L; delay800(); } IRAM_ATTR __attribute__((always_inline)) inline void reset() { LED_SET_PIN_L; SLEEP_US(50); } //#pragma GCC optimize 0 // one NOP is: // 80 MHz 12.5 ns // 240 MHz 4.166 ns IRAM_ATTR __attribute__((always_inline)) inline void delay100() { // 24 * 4.166ns = 100ns asm volatile("nop"); asm volatile("nop"); asm volatile("nop"); asm volatile("nop"); asm volatile("nop"); asm volatile("nop"); asm volatile("nop"); asm volatile("nop"); asm volatile("nop"); asm volatile("nop"); asm volatile("nop"); asm volatile("nop"); asm volatile("nop"); asm volatile("nop"); asm volatile("nop"); asm volatile("nop"); // for (register int i = 0; i < 24/6; ++i) { // asm volatile("nop"); // } } IRAM_ATTR __attribute__((always_inline)) inline void delay800() { delay100(); delay100(); delay100(); delay100(); delay100(); delay100(); delay100(); delay100(); // for (register int i = 0; i < 24*8/6-8; ++i) { // asm volatile("nop"); // } } }; #endif // WS2812B_H