Bladeren bron

Add RMT backend

Without DMA, this is glitchy as heck.
rmt-backend
jrhoffa 3 jaren geleden
bovenliggende
commit
30e6020d0d
2 gewijzigde bestanden met toevoegingen van 238 en 0 verwijderingen
  1. +218
    -0
      main/rmt_leds.cpp
  2. +20
    -0
      main/rmt_leds.hpp

+ 218
- 0
main/rmt_leds.cpp Bestand weergeven

@@ -0,0 +1,218 @@
static const char *TAG = "rmt_leds";
#include <esp_log.h>

#include <freertos/FreeRTOS.h>
#include <freertos/task.h>

#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(
&copy_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
));
}

+ 20
- 0
main/rmt_leds.hpp Bestand weergeven

@@ -0,0 +1,20 @@
#pragma once

#include <driver/rmt_tx.h>

#include "leds.hpp"


class RMT_LEDs : public LEDStrip {
public:
RMT_LEDs(int gpio, int length = 0);
void show();
void length_changing(int len) { configure(len); }

private:
int gpio;
rmt_channel_handle_t channel;
rmt_symbol_word_t *rmt_block;

void configure(int length);
};

Laden…
Annuleren
Opslaan