Remote Control Transceiver (RMT)
The Rmt class provides a wrapper around the ESP32 RMT peripheral. It allows you to send infrared signals with the ESP32. See the esp-idf documentation for more information about the RMT peripheral. (https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/peripherals/rmt.html)
The RmtEncoder class provides a wrapper around the ESP32 rmt encoder functionality. It allows you to encode infrared signals with the ESP32. See the esp-idf documentation for more information about the RMT encoder (https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/peripherals/rmt.html#rmt-encoder)
The main functionality of the Rmt / RmtEncoder classes beyond what is provided by the esp-idf is to allow the use of the RMT peripheral with c++ functions (such as with bound functions, functionals, etc.). It also provides a simpler wrapper / interface to the user.
API Reference
Header File
Classes
-
class Rmt : public espp::BaseComponent
Class wrapping the RMT peripheral on the ESP32.
The RMT (Remote Control Transceiver) peripheral is used to generate precise timing pulses on a GPIO pin. It can be used to drive a WS2812B or similar LED strip which uses a 1-wire protocol such as the WS2812B. The RMT peripheral is also used by the ESP32 to drive the IR transmitter.
See also
https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/rmt.html
Example 1: Transmitting data
// create the rmt object espp::Rmt rmt(espp::Rmt::Config{ .gpio_num = 18, // WS2812B data pin on the TinyS3 .resolution_hz = WS2812_FREQ_HZ, .log_level = espp::Logger::Verbosity::INFO, }); // tell the RMT object to use the led_encoder (espp::RmtEncoder) that's // defined above rmt.set_encoder(std::move(led_encoder)); // create a task to cycle through rainbow colors and send them to the // WS2812B LED using the RMT peripheral auto task_fn = [&rmt](std::mutex &m, std::condition_variable &cv) { static auto start = std::chrono::high_resolution_clock::now(); auto now = std::chrono::high_resolution_clock::now(); float t = std::chrono::duration<float>(now - start).count(); // rotate through rainbow colors in hsv based on time, hue is 0-360 float hue = (cos(t) * 0.5f + 0.5f) * 360.0f; espp::Hsv hsv(hue, 1.0f, 1.0f); espp::Rgb rgb = hsv.rgb(); uint8_t green = std::clamp(int(rgb.g * 255), 0, 255); uint8_t blue = std::clamp(int(rgb.b * 255), 0, 255); uint8_t red = std::clamp(int(rgb.r * 255), 0, 255); // NOTE: we only have one LED so we only need to send one set of RGB data uint8_t data[3] = {green, blue, red}; // now we can send the data to the WS2812B LED rmt.transmit(data, sizeof(data)); fmt::print("hsv->rgb->uint: {} -> {} -> {} {} {}\n", hsv, rgb, green, blue, red); // NOTE: sleeping in this way allows the sleep to exit early when the // task is being stopped / destroyed { std::unique_lock<std::mutex> lk(m); cv.wait_for(lk, 50ms); } // don't want to stop the task return false; }; auto task = espp::Task({.callback = task_fn, .task_config = { .name = "Rmt Task", .stack_size_bytes = 5 * 1024, }, .log_level = espp::Logger::Verbosity::WARN}); task.start();
Public Functions
-
inline explicit Rmt(const Config &config)
Constructor.
- Parameters
config – Configuration for this class
-
inline ~Rmt()
Destructor.
This function disables the RMT peripheral and frees the RMT channel.
-
inline bool transmit(const uint8_t *data, size_t length)
Transmit a buffer of data using the RMT peripheral.
Note
This function blocks until the data has been transmitted.
- Parameters
data – Pointer to the data to transmit
length – Length of the data to transmit
- Returns
True if the data was successfully transmitted, false otherwise
-
inline const std::string &get_name() const
Get the name of the component
Note
This is the tag of the logger
- Returns
A const reference to the name of the component
-
inline void set_log_tag(const std::string_view &tag)
Set the tag for the logger
- Parameters
tag – The tag to use for the logger
-
inline espp::Logger::Verbosity get_log_level() const
Get the log level for the logger
See also
See also
- Returns
The verbosity level of the logger
-
inline void set_log_level(espp::Logger::Verbosity level)
Set the log level for the logger
See also
See also
- Parameters
level – The verbosity level to use for the logger
-
inline void set_log_verbosity(espp::Logger::Verbosity level)
Set the log verbosity for the logger
See also
See also
See also
Note
This is a convenience method that calls set_log_level
- Parameters
level – The verbosity level to use for the logger
-
inline espp::Logger::Verbosity get_log_verbosity() const
Get the log verbosity for the logger
See also
See also
See also
Note
This is a convenience method that calls get_log_level
- Returns
The verbosity level of the logger
-
inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)
Set the rate limit for the logger
See also
Note
Only calls to the logger that have _rate_limit suffix will be rate limited
- Parameters
rate_limit – The rate limit to use for the logger
-
struct Config
Configuration for the RMT class.
Public Members
-
int gpio_num
GPIO pin to use for the RMT peripheral.
-
rmt_clock_source_t clock_src = RMT_CLK_SRC_DEFAULT
Clock source for the RMT peripheral.
-
bool dma_enabled = false
Whether to use DMA for the RMT peripheral.
-
int block_size = 64
Memory block size (e.g. 64 * 4 = 256 bytes) for the RMT peripheral. Note: this has different meaning depending on whether DMA is configured or not. Suggested size without DMA is >= 64, with DMA is >= 1024.
-
size_t resolution_hz = 10000000
Resolution of the RMT peripheral.
-
int transaction_queue_depth = 1
Depth of the RMT transaction queue (number of transactions that can be queued)
-
int gpio_num
-
inline explicit Rmt(const Config &config)
Header File
Classes
-
class RmtEncoder
Class representing an RMT encoder.
This class is used to encode data for the RMT peripheral. It is used by the Rmt class to encode data for transmission.
Example 1: WS2812 encoder
// // The RmtEncoder provides a way to encode data into the RMT peripheral. // This code is a custom encoder that encodes WS2812B data. It uses two // encoders, a bytes encoder and a copy encoder. The bytes encoder encodes // the RGB data into the RMT peripheral and the copy encoder encodes the // reset code. The reset code is a special code that is sent after the RGB // data to reset the WS2812B LEDs. The reset code is a 50us low pulse // followed by a 50us high pulse. The reset code is sent after the RGB data // to ensure that the WS2812B LEDs latch the RGB data. The reset code is // sent after the RGB data because the WS2812B LEDs latch the RGB data on // the rising edge of the reset code. // // This code is copied from the led_stip example in the esp-idf // (https://github.com/espressif/esp-idf/tree/master/examples/peripherals/rmt/led_strip/main) int led_encoder_state = 0; static constexpr int WS2812_FREQ_HZ = 10000000; static constexpr int MICROS_PER_SEC = 1000000; auto led_encoder = std::make_unique<espp::RmtEncoder>(espp::RmtEncoder::Config{ // NOTE: since we're using the 10MHz RMT clock, we can use the pre-defined // ws2812_10mhz_bytes_encoder_config .bytes_encoder_config = espp::RmtEncoder::ws2812_10mhz_bytes_encoder_config, .encode = [&led_encoder_state](auto channel, auto *copy_encoder, auto *bytes_encoder, const void *data, size_t data_size, rmt_encode_state_t *ret_state) -> size_t { // divide by 2 since we have both duration0 and duration1 in the reset code static uint16_t reset_ticks = WS2812_FREQ_HZ / MICROS_PER_SEC * 50 / 2; // reset code duration defaults to 50us static rmt_symbol_word_t led_reset_code = (rmt_symbol_word_t){ .duration0 = reset_ticks, .level0 = 0, .duration1 = reset_ticks, .level1 = 0, }; rmt_encode_state_t session_state = RMT_ENCODING_RESET; int state = RMT_ENCODING_RESET; size_t encoded_symbols = 0; switch (led_encoder_state) { case 0: // send RGB data encoded_symbols += bytes_encoder->encode(bytes_encoder, channel, data, data_size, &session_state); if (session_state & RMT_ENCODING_COMPLETE) { led_encoder_state = 1; // switch to next state when current encoding session finished } if (session_state & RMT_ENCODING_MEM_FULL) { state |= RMT_ENCODING_MEM_FULL; goto out; // yield if there's no free space for encoding artifacts } // fall-through case 1: // send reset code encoded_symbols += copy_encoder->encode(copy_encoder, channel, &led_reset_code, sizeof(led_reset_code), &session_state); if (session_state & RMT_ENCODING_COMPLETE) { led_encoder_state = RMT_ENCODING_RESET; // back to the initial encoding session state |= RMT_ENCODING_COMPLETE; } if (session_state & RMT_ENCODING_MEM_FULL) { state |= RMT_ENCODING_MEM_FULL; goto out; // yield if there's no free space for encoding artifacts } } out: *ret_state = static_cast<rmt_encode_state_t>(state); return encoded_symbols; }, .del = [](auto *base_encoder) -> esp_err_t { // we don't have any extra resources to free, so just return ESP_OK return ESP_OK; }, .reset = [&led_encoder_state](auto *base_encoder) -> esp_err_t { // all we have is some extra state to reset led_encoder_state = 0; return ESP_OK; }, });
Public Types
-
typedef std::function<size_t(rmt_channel_handle_t channel, rmt_encoder_t *copy_encoder, rmt_encoder_t *bytes_encoder, const void *primary_data, size_t data_size, rmt_encode_state_t *ret_state)> encode_fn
Function to encode data for the RMT peripheral.
Note
This function is called by the Rmt class to encode data for transmission. It is called repeatedly until all data has been encoded.
Note
This function should return the number of bytes encoded.
Note
This function should set the RMT encoder state to the next state to be used for encoding.
- Param channel
RMT channel to use for encoding
- Param copy_encoder
RMT encoder to use for copying data
- Param bytes_encoder
RMT encoder to use for encoding bytes
- Param primary_data
Pointer to the primary data to encode
- Param data_size
Size of the primary data to encode
- Param ret_state
Pointer to the RMT encoder state to return
- Return
Number of bytes encoded
-
typedef std::function<esp_err_t(rmt_encoder_t*)> delete_fn
Function to delete an RMT encoder.
- Param encoder
RMT encoder to delete
- Return
ESP_OK if the encoder was successfully deleted, an error code
-
typedef std::function<esp_err_t(rmt_encoder_t*)> reset_fn
Function to reset an RMT encoder.
- Param encoder
RMT encoder to reset
- Return
ESP_OK if the encoder was successfully reset, an error code
Public Functions
-
inline explicit RmtEncoder(const Config &config)
Constructor.
- Parameters
config – Configuration for this class
-
inline ~RmtEncoder()
Destructor.
-
inline rmt_encoder_handle_t handle() const
Get the RMT encoder handle.
- Returns
RMT encoder handle
Public Static Attributes
- static constexpr rmt_bytes_encoder_config_t sk6805_10mhz_bytes_encoder_config = {.bit0 ={.duration0 = static_cast<uint16_t>(0.3 * 10000000 / 1000000),.level0 = 1,.duration1 = static_cast<uint16_t>(0.9 * 10000000 / 1000000),.level1 = 0,},.bit1 ={.duration0 = static_cast<uint16_t>(0.6 * 10000000 / 1000000),.level0 = 1,.duration1 = static_cast<uint16_t>(0.6 * 10000000 / 1000000),.level1 = 0,},.flags ={.msb_first = 1},}
Configuration for the byte encoding for SK6805 LEDs.
This configuration is used to encode bytes for SK6085 LEDs.
See also
Note
This configuration can be provided to the configuration for this class. These values are based on the timing values provided in the SK6805 datasheet (https://cdn-shop.adafruit.com/product-files/3484/3484_Datasheet.pdf)
- static constexpr rmt_bytes_encoder_config_t ws2812_10mhz_bytes_encoder_config = {.bit0 ={.duration0 = static_cast<uint16_t>(0.3 * 10000000 / 1000000),.level0 = 1,.duration1 = static_cast<uint16_t>(0.9 * 10000000 / 1000000),.level1 = 0,},.bit1 ={.duration0 = static_cast<uint16_t>(0.9 * 10000000 / 1000000),.level0 = 1,.duration1 = static_cast<uint16_t>(0.3 * 10000000 / 1000000),.level1 = 0,},.flags ={.msb_first = 1},}
Configuration for the byte encoding for WS2812 LEDs.
This configuration is used to encode bytes for WS2812 LEDs.
See also
Note
This configuration can be provided to the configuration for this class.
-
struct Config
Configuration for this class.
-
typedef std::function<size_t(rmt_channel_handle_t channel, rmt_encoder_t *copy_encoder, rmt_encoder_t *bytes_encoder, const void *primary_data, size_t data_size, rmt_encode_state_t *ret_state)> encode_fn