196 lines
4.5 KiB
C++
196 lines
4.5 KiB
C++
#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 <int numLEDs> 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
|