#ifndef WS2812B_H #define WS2812B_H #include #include //#include #include #include #include "../../data/Color.h" template class WS2812B { static constexpr const char* TAG = "WS2812"; static constexpr rmt_channel_t chan = RMT_CHANNEL_0; static constexpr gpio_num_t outPin = GPIO_NUM_27; //#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() static constexpr int numBits = (3*8) * 2; // (r,g,b) each 8 bit NOTE! must be < 64 to fit into the buffer! //static constexpr int numItems = 256;//(numLEDs*3)*8; //static constexpr int numItems = (numLEDs*3)*8; rmt_item32_t items[numBits+1]; // + a 0-terminator (just like within strings) /** enable/disable each led */ bool enabled[numLEDs] = {true}; /** color-value for each attached LED */ Color colors[numLEDs]; public: /** ctor */ WS2812B() { init(); } void init() { ESP_LOGI(TAG, "init()"); rmt_config_t cfg; cfg.rmt_mode = RMT_MODE_TX; cfg.channel = chan; cfg.gpio_num = outPin; cfg.mem_block_num = 1;//chan+1;//8-chan;//chan+1;//8 - chan; //chan+1;// cfg.clk_div = 8; cfg.tx_config.loop_en = false; cfg.tx_config.carrier_en = false; cfg.tx_config.idle_output_en = true; cfg.tx_config.idle_level = (rmt_idle_level_t)0; cfg.tx_config.carrier_freq_hz = 10000; cfg.tx_config.carrier_level = (rmt_carrier_level_t)1; cfg.tx_config.carrier_duty_percent = 50; // allocate one block for sending (64 bits) //ESP_ERROR_CHECK(rmt_set_mem_block_num(chan, 1)); ESP_ERROR_CHECK(rmt_config(&cfg)); ESP_ERROR_CHECK(rmt_driver_install(chan, 0, 0)); // setup constant values once for (int idx = 0; idx < numBits; ++idx) { items[idx].duration0 = 1; items[idx].level0 = 1; items[idx].duration1 = 1; items[idx].level1 = 0; } //items[numBits].val = 0; // 0 terminator ESP_LOGI(TAG, "init OK!"); } /** 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 */ void flush() { ESP_LOGI(TAG, "sending %d LEDs", numLEDs); int idx = 0; // process each LED for (int i = 0; i < numLEDs; ++i) { if (enabled[i]) { const Color c = colors[i]; emplaceByte(c.g, idx); emplaceByte(c.r, idx); emplaceByte(c.b, idx); } else { emplaceByte(0, idx); emplaceByte(0, idx); emplaceByte(0, idx); } if (idx >= numBits) { // wait for pervious transmission to finish //rmt_wait_tx_done(this->chan, (TickType_t)1); items[idx].val = 0; // 0 terminator ESP_ERROR_CHECK(rmt_fill_tx_items(this->chan, items, numBits, 0)); ESP_ERROR_CHECK(rmt_tx_start(this->chan, true)); rmt_wait_tx_done(this->chan, (TickType_t)1); // send within the background //const bool blockingWait = true; //ESP_ERROR_CHECK(rmt_write_items(this->chan, items, numItems, blockingWait)); //rmt_wait_tx_done(this->chan, (TickType_t)1); idx = 0; } } /* // bit counter int idx = 0; // process each LED for (int i = 0; i < numLEDs; ++i) { if (enabled[i]) { const Color c = colors[i]; emplaceByte(c.g, idx); emplaceByte(c.r, idx); emplaceByte(c.b, idx); } else { emplaceByte(0, idx); emplaceByte(0, idx); emplaceByte(0, idx); } } // blocking send all bits via RMT const bool blockingWait = true; ESP_ERROR_CHECK(rmt_write_items(this->chan, items, numItems, blockingWait)); ESP_LOGI(TAG, "%d bits sent", idx); */ } private: /** send one whole byte */ inline void emplaceByte(const uint8_t b, int& idx) { if (b & 0b10000000) {emplace1(idx);} else {emplace0(idx);} if (b & 0b01000000) {emplace1(idx);} else {emplace0(idx);} if (b & 0b00100000) {emplace1(idx);} else {emplace0(idx);} if (b & 0b00010000) {emplace1(idx);} else {emplace0(idx);} if (b & 0b00001000) {emplace1(idx);} else {emplace0(idx);} if (b & 0b00000100) {emplace1(idx);} else {emplace0(idx);} if (b & 0b00000010) {emplace1(idx);} else {emplace0(idx);} if (b & 0b00000001) {emplace1(idx);} else {emplace0(idx);} } /** emplace a 0 (short 1 pulse, long 0 pulse) */ inline void emplace0(int& idx) { items[idx].duration0 = 2; //items[idx].level0 = 1; items[idx].duration1 = 8; //items[idx].level1 = 0; ++idx; } /** emplace a 1 (long 1 pulse, short 0 pulse) */ inline void emplace1(int& idx) { items[idx].duration0 = 7; //items[idx].level0 = 1; items[idx].duration1 = 3; //items[idx].level1 = 0; ++idx; } }; #endif // WS2812B_H