Files
ESP8266lib/ext/led/WS2812B_v2.h
2022-07-17 14:47:21 +02:00

229 lines
5.0 KiB
C++

#ifndef WS2812B_H
#define WS2812B_H
#include "../../data/Color.h"
#include "../../Platforms.h"
#include "../../Debug.h"
#include "../../io/GPIO.h"
#include <xtensa/xtruntime.h>
#if IS_ESP8266
// https://github.com/FastLED/FastLED/tree/master/src/platforms/esp/8266
//#include "../../io/fastGPIO.h"
#include "../../io/GPIO.h"
#include "driver/i2s.h"
#include <string.h>
template <int numLEDs> class WS2812B {
static constexpr const char* NAME = "WS2812B";
#define LED_SET_PIN_TO_OUTPUT MyGPIO::setOutput(5) //GPIO5_OUTPUT_SET
#define LED_SET_PIN_H MyGPIO::set(5) //GPIO5_H
#define LED_SET_PIN_L MyGPIO::clear(5) //GPIO5_L
//#define NS_PER_TICK ( (1000ul*1000ul*1000ul) / (80ul*1000ul*1000ul) )
/** color-value for each attached LED */
Color colors[numLEDs];
/** enable/disable each led */
bool enabled[numLEDs] = {true};
static constexpr const int bits = 16;
static constexpr const i2s_port_t I2S_NUM = (i2s_port_t)0;
static constexpr const int SAMPLE_RATE = 44100; // 100000
class SendBuffer {
uint32_t buf[numLEDs * 3 + 32];
int idx = 0;
i2s_config_t i2s_config;
i2s_pin_config_t pin_config;
public:
SendBuffer() {
}
void init() {
Log::addInfo("i2s", "init()");
memset(&i2s_config, 0, sizeof(i2s_config));
i2s_config.mode = (i2s_mode_t) (I2S_MODE_MASTER | I2S_MODE_TX); // Only TX
i2s_config.sample_rate = SAMPLE_RATE;
i2s_config.bits_per_sample = (i2s_bits_per_sample_t)16; // 16 bit
i2s_config.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT; // 2-channels
i2s_config.communication_format = (i2s_comm_format_t) (I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB);
i2s_config.dma_buf_count = 6;
i2s_config.dma_buf_len = 256;
memset(&pin_config, 0, sizeof(pin_config));
pin_config.bck_o_en = 1;
pin_config.ws_o_en = 2;
pin_config.data_out_en = 15; // 5
ESP_ERROR_CHECK(i2s_driver_install(I2S_NUM, &i2s_config, 0, nullptr));
ESP_ERROR_CHECK(i2s_set_pin(I2S_NUM, &pin_config));
//ESP_ERROR_CHECK(i2s_set_clk(I2S_NUM, SAMPLE_RATE, (i2s_bits_per_sample_t)16, (i2s_channel_t)2));
}
void reset() {
idx = 0;
}
void add(uint8_t b) {
buf[idx] = encode(b);
++idx;
}
void transmit() {
size_t written = 0;
size_t bytes = 512;//sizeof(uint32_t) * idx + 20+512;
ESP_ERROR_CHECK(i2s_write(I2S_NUM, buf, bytes, &written, 100));
Log::addInfo("I2s", "transmit %d %d", bytes, written);
}
/** byte -> i2s transmission pattern */
uint32_t encode(uint8_t b) {
#define _LO 0b1000
#define _HI 0b1110
uint32_t res;
uint8_t* tmp = (uint8_t*) &res;
tmp[0] = (((b & (1<<7)) ? (_HI) : (_LO)) << 4) | (((b & (1<<6)) ? (_HI) : (_LO)) << 0);
tmp[1] = (((b & (1<<5)) ? (_HI) : (_LO)) << 4) | (((b & (1<<4)) ? (_HI) : (_LO)) << 0);
tmp[2] = (((b & (1<<3)) ? (_HI) : (_LO)) << 4) | (((b & (1<<2)) ? (_HI) : (_LO)) << 0);
tmp[3] = (((b & (1<<1)) ? (_HI) : (_LO)) << 4) | (((b & (1<<0)) ? (_HI) : (_LO)) << 0);
return res;
}
} sendBuf;
public:
/** ctor */
WS2812B() {
init();
}
void init() {
LED_SET_PIN_TO_OUTPUT;
Log::addInfo(NAME, "init with %d leds", numLEDs);
}
void init2() {
sendBuf.init();
}
/** 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() {
sendBuf.reset();
// process each LED
for (uint16_t i = 0; i < numLEDs; ++i) {
// send each LEDs 24-bit GRB data
if (enabled[i]) {
const Color rgb = colors[i];
sendBuf.add(rgb.g);
sendBuf.add(rgb.r);
sendBuf.add(rgb.b);
} else {
sendBuf.add(0);
sendBuf.add(0);
sendBuf.add(0);
}
}
sendBuf.transmit();
}
/** flush configured changes, including global brightness */
IRAM_ATTR void flushBrightness(const uint8_t brightness) {
sendBuf.reset();
// process each LED
for (uint16_t i = 0; i < numLEDs; ++i) {
// send each LEDs 24-bit GRB data
if (enabled[i]) {
const Color rgb = colors[i].brightness(brightness);
sendBuf.add(rgb.g);
sendBuf.add(rgb.r);
sendBuf.add(rgb.b);
} else {
sendBuf.add(0);
sendBuf.add(0);
sendBuf.add(0);
}
}
sendBuf.transmit();
}
};
#endif
#endif // WS2812B_H