Files
ESP32lib/ext/led/WS2812B.h
2018-09-22 15:49:40 +02:00

224 lines
5.3 KiB
C++

#ifndef WS2812B_H
#define WS2812B_H
#include <rom/ets_sys.h>
#include <xtensa/core-macros.h>
//#include <driver/gpio.h>
#include <driver/rmt.h>
#include <soc/rmt_struct.h>
#include "../../data/Color.h"
template <int numLEDs> 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