#ifndef WS2812B_H #define WS2812B_H #include "../../data/Color.h" #include "../../Platforms.h" #include "../../Debug.h" #include "../../io/GPIO.h" #include #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 template 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