static const char *TAG = "rmt_leds"; #include #include #include #include "rmt_leds.hpp" RMT_LEDs::RMT_LEDs(int _gpio, int length) : LEDStrip(length), gpio(_gpio), channel(NULL), rmt_block(NULL) { rmt_tx_channel_config_t config = { .gpio_num = gpio, .clk_src = RMT_CLK_SRC_DEFAULT, .resolution_hz = 3200000, // (1.25 us / 4) => 3.2 MHz .mem_block_symbols = 64, // memory block size, 64 * 4 = 256Bytes .trans_queue_depth = 1, // We don't really need background transfers .flags = { .invert_out = false, .with_dma = false, // TODO: Why no DMA?? .io_loop_back = false, }, }; ESP_ERROR_CHECK(rmt_new_tx_channel(&config, &channel)); ESP_ERROR_CHECK(rmt_enable(channel)); configure(length); } void RMT_LEDs::configure(int n_leds) { if (rmt_block) { delete[] rmt_block; rmt_block = NULL; } if (n_leds <= 0) return; rmt_block = new rmt_symbol_word_t[n_leds * 24 + 1]; } /* static rmt_encoder_handle_t byte_enc; static const rmt_bytes_encoder_config_t byte_enc_config = { .bit0 = { .duration0 = 1, .level0 = 1, .duration1 = 3, .level1 = 0, }, .bit1 = { .duration0 = 2, .level0 = 1, .duration1 = 2, .level1 = 0, }, .flags = { .msb_first = 1, }, }; static esp_err_t bytes_enc_ok = rmt_new_bytes_encoder(&byte_enc_config, &byte_enc); static rmt_encoder_handle_t rst_enc; static const rmt_copy_encoder_config_t rst_enc_config = {}; static esp_err_t rst_enc_ok = rmt_new_copy_encoder(&rst_enc_config, &rst_enc); static const rmt_symbol_word_t rst_symbol = { .duration0 = 80, .level0 = 0, .duration1 = 80, .level1 = 0, }; struct strip_encoder { rmt_encoder_t base; int state; }; static size_t encode_strip( rmt_encoder_t *_encoder, rmt_channel_handle_t channel, const void *data, size_t n_bytes, rmt_encode_state_t *ret_state ) { strip_encoder *encoder = __containerof(_encoder, strip_encoder, base); size_t n_encoded = 0; rmt_encode_state_t substate = 0; rmt_encode_state_t state = 0; switch(encoder->state) { case 0: n_encoded += byte_enc.encode(&byte_enc, channel, data, n_bytes, &substate); if (substate & RMT_ENCODING_COMPLETE) { encoder->state = 1; break; } case 1: n_encoded += rst_enc.encode( &rst_enc, channel, &rst_symbol, sizeof(rst_symbol), &substate); if (substate & RMT_ENCODING_COMPLETE) { encoder->state = 0; state |= RMT_ENCODING_COMPLETE; } if (substate & RMT_ENCODING_MEM_FULL) { state |= RMT_ENCODING_MEM_FULL; } } *ret_state = state; return n_encoded; } static esp_err_t reset_strip_encoder(rmt_encoder_t *encoder) { strip_encoder *encoder = __containerof(encoder, strip_encoder, base); rmt_encoder_reset(byte_enc); rmt_encoder_reset(rst_enc); encoder->state = 0; return ESP_OK; } static esp_err_t rmt_del_led_strip_encoder(rmt_encoder_t *encoder) { strip_encoder *encoder = __containerof(encoder, strip_encoder, base); delete encoder; return ESP_OK; } static rmt_encoder_t* make_strip_encoder() { enc = new strip_encoder { .base = { .encode = encode_strip, .reset = reset_strip_encoder, .del = del_strip_encoder, }, .state = 0 } } */ static rmt_encoder_handle_t encoder; static const rmt_copy_encoder_config_t copy_encoder_config = {}; static esp_err_t copy_encoder_ok = rmt_new_copy_encoder( ©_encoder_config, &encoder ); constexpr rmt_symbol_word_t sym_0 = { .duration0 = 1, .level0 = 1, .duration1 = 3, .level1 = 0, }; constexpr rmt_symbol_word_t sym_1 = { .duration0 = 2, .level0 = 1, .duration1 = 2, .level1 = 0, }; constexpr rmt_symbol_word_t sym_reset = { .duration0 = 80, .level0 = 0, .duration1 = 80, .level1 = 0, }; static inline rmt_symbol_word_t* encode_byte(rmt_symbol_word_t *sym, uint8_t x) { for (int i = 8; i > 0; --i) { *sym = (x & 0x80) ? sym_1 : sym_0; x <<= 1; ++sym; } return sym; } /*** *** *** static std::string termcolor(Color c) { return "\x1b[48;2;" + std::to_string((int)c.r) + ";" + std::to_string((int)c.g) + ";" + std::to_string((int)c.b) + "m"; } static void show_terminal_LEDs(const Color *pixels, int length) { std::string line; for (int i = 0; i < length; i++) { line += termcolor(pixels[i]) + " "; } line += "\x1b[0m"; ESP_LOGI(TAG, "%s", line.c_str()); } *** *** ***/ void RMT_LEDs::show() { static const rmt_transmit_config_t config = { .loop_count = 0, .flags = { .eot_level = 0, }, }; rmt_symbol_word_t *sym = rmt_block; Color *pixel = pixels; for (int i = length; i > 0; --i) { sym = encode_byte(sym, pixel->r); sym = encode_byte(sym, pixel->g); sym = encode_byte(sym, pixel->b); ++pixel; } *sym++ = sym_reset; //show_terminal_LEDs(pixels, length); esp_err_t err = rmt_tx_wait_all_done(channel, -1); if (err) ESP_LOGE(TAG, "Failed to wait for TX complete: %d", err); ESP_ERROR_CHECK(rmt_transmit( channel, encoder, //pixels, length * sizeof(*pixels), rmt_block, (length * 24 + 1) * sizeof(*rmt_block), &config )); }