change(rmt): split rmt encoders into different files

This commit is contained in:
morris
2025-03-21 18:56:25 +08:00
parent 720687e698
commit 1877605e59
12 changed files with 561 additions and 573 deletions

View File

@@ -5,6 +5,9 @@ set(public_include "include")
if(CONFIG_SOC_RMT_SUPPORTED)
list(APPEND srcs "src/rmt_common.c"
"src/rmt_encoder.c"
"src/rmt_encoder_bytes.c"
"src/rmt_encoder_copy.c"
"src/rmt_encoder_simple.c"
"src/rmt_rx.c"
"src/rmt_tx.c")
endif()

View File

@@ -1,5 +1,6 @@
menu "ESP-Driver:RMT Configurations"
depends on SOC_RMT_SUPPORTED
config RMT_ISR_HANDLER_IN_IRAM
bool "Place RMT ISR handler into IRAM"
select GDMA_CTRL_FUNC_IN_IRAM if SOC_RMT_SUPPORT_DMA
@@ -33,9 +34,13 @@ menu "ESP-Driver:RMT Configurations"
where its cache can be disabled.
config RMT_ENABLE_DEBUG_LOG
bool "Enable debug log"
bool "Force enable debug log"
default n
help
whether to enable the debug log message for RMT driver.
Note that, this option only controls the RMT driver log, won't affect other drivers.
If enabled, RMT driver component will:
1. ignore the global logging settings
2. compile all log messages into the binary
3. set the runtime log level to VERBOSE
Please enable this option by caution, as it will increase the binary size.
endmenu

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -14,18 +14,6 @@
extern "C" {
#endif
/**
* @brief RMT carrier wave configuration (for either modulation or demodulation)
*/
typedef struct {
uint32_t frequency_hz; /*!< Carrier wave frequency, in Hz, 0 means disabling the carrier */
float duty_cycle; /*!< Carrier wave duty cycle (0~100%) */
struct {
uint32_t polarity_active_low: 1; /*!< Specify the polarity of carrier, by default it's modulated to base signal's high level */
uint32_t always_on: 1; /*!< If set, the carrier can always exist even there's not transfer undergoing */
} flags; /*!< Carrier config flags */
} rmt_carrier_config_t;
/**
* @brief Delete an RMT channel
*

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -72,6 +72,18 @@ typedef struct {
*/
typedef bool (*rmt_rx_done_callback_t)(rmt_channel_handle_t rx_chan, const rmt_rx_done_event_data_t *edata, void *user_ctx);
/**
* @brief RMT carrier wave configuration (for either modulation or demodulation)
*/
typedef struct {
uint32_t frequency_hz; /*!< Carrier wave frequency, in Hz, 0 means disabling the carrier */
float duty_cycle; /*!< Carrier wave duty cycle (0~100%) */
struct {
uint32_t polarity_active_low: 1; /*!< Specify the polarity of carrier, by default it's modulated to base signal's high level */
uint32_t always_on: 1; /*!< If set, the carrier can always exist even there's not transfer undergoing */
} flags; /*!< Carrier config flags */
} rmt_carrier_config_t;
#ifdef __cplusplus
}
#endif

View File

@@ -4,26 +4,10 @@
* SPDX-License-Identifier: Apache-2.0
*/
#include <sys/lock.h>
#include "sdkconfig.h"
#if CONFIG_RMT_ENABLE_DEBUG_LOG
// The local log level must be defined before including esp_log.h
// Set the maximum log level for this source file
#define LOG_LOCAL_LEVEL ESP_LOG_DEBUG
#endif
#include "esp_log.h"
#include "esp_check.h"
#include "rmt_private.h"
#include "clk_ctrl_os.h"
#include "soc/rtc.h"
#include "soc/soc_caps.h"
#include "soc/rmt_periph.h"
#include "hal/rmt_ll.h"
#include "driver/gpio.h"
#include "esp_private/esp_clk_tree_common.h"
#include "esp_private/periph_ctrl.h"
static const char *TAG = "rmt";
#if SOC_PERIPH_CLK_CTRL_SHARED
#define RMT_CLOCK_SRC_ATOMIC() PERIPH_RCC_ATOMIC()
@@ -398,3 +382,11 @@ void rmt_create_retention_module(rmt_group_t *group)
_lock_release(&s_platform.mutex);
}
#endif // RMT_USE_RETENTION_LINK
#if CONFIG_RMT_ENABLE_DEBUG_LOG
__attribute__((constructor))
static void rmt_override_default_log_level(void)
{
esp_log_level_set(TAG, ESP_LOG_VERBOSE);
}
#endif

View File

@@ -1,507 +1,11 @@
/*
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdlib.h>
#include <string.h>
#include <sys/cdefs.h>
#include <sys/param.h>
#include "sdkconfig.h"
#if CONFIG_RMT_ENABLE_DEBUG_LOG
// The local log level must be defined before including esp_log.h
// Set the maximum log level for this source file
#define LOG_LOCAL_LEVEL ESP_LOG_DEBUG
#endif
#include "esp_log.h"
#include "esp_check.h"
#include "driver/rmt_encoder.h"
#include "rmt_private.h"
#include "hal/hal_utils.h"
static const char *TAG = "rmt";
typedef struct rmt_bytes_encoder_t {
rmt_encoder_t base; // encoder base class
size_t last_bit_index; // index of the encoding bit position in the encoding byte
size_t last_byte_index; // index of the encoding byte in the primary stream
rmt_symbol_word_t bit0; // bit zero representing
rmt_symbol_word_t bit1; // bit one representing
struct {
uint32_t msb_first: 1; // encode MSB firstly
} flags;
} rmt_bytes_encoder_t;
typedef struct rmt_copy_encoder_t {
rmt_encoder_t base; // encoder base class
size_t last_symbol_index; // index of symbol position in the primary stream
} rmt_copy_encoder_t;
typedef struct rmt_simple_encoder_t {
rmt_encoder_t base; // encoder base class
size_t last_symbol_index; // index of symbol position in the primary stream
rmt_encode_simple_cb_t callback; //callback to call to encode
void *arg; // opaque callback argument
rmt_symbol_word_t *ovf_buf; //overflow buffer
size_t ovf_buf_size; //size, in elements, of overflow buffer
size_t ovf_buf_fill_len; //how much actual info the overflow buffer has
size_t ovf_buf_parsed_pos; //up to where we moved info from the ovf buf to the rmt
bool callback_done; //true if we can't call the callback for more data anymore.
} rmt_simple_encoder_t;
static esp_err_t rmt_bytes_encoder_reset(rmt_encoder_t *encoder)
{
rmt_bytes_encoder_t *bytes_encoder = __containerof(encoder, rmt_bytes_encoder_t, base);
// reset index to zero
bytes_encoder->last_bit_index = 0;
bytes_encoder->last_byte_index = 0;
return ESP_OK;
}
static size_t IRAM_ATTR rmt_encode_bytes(rmt_encoder_t *encoder, rmt_channel_handle_t channel,
const void *primary_data, size_t data_size, rmt_encode_state_t *ret_state)
{
rmt_bytes_encoder_t *bytes_encoder = __containerof(encoder, rmt_bytes_encoder_t, base);
rmt_tx_channel_t *tx_chan = __containerof(channel, rmt_tx_channel_t, base);
const uint8_t *raw_data = (const uint8_t *)primary_data;
rmt_encode_state_t state = RMT_ENCODING_RESET;
rmt_dma_descriptor_t *desc0 = NULL;
rmt_dma_descriptor_t *desc1 = NULL;
size_t byte_index = bytes_encoder->last_byte_index;
size_t bit_index = bytes_encoder->last_bit_index;
// how many symbols will be generated by the encoder
size_t mem_want = (data_size - byte_index - 1) * 8 + (8 - bit_index);
// how many symbols we can save for this round
size_t mem_have = tx_chan->mem_end - tx_chan->mem_off;
// where to put the encoded symbols? DMA buffer or RMT HW memory
rmt_symbol_word_t *mem_to_nc = NULL;
if (channel->dma_chan) {
mem_to_nc = tx_chan->dma_mem_base_nc;
} else {
mem_to_nc = channel->hw_mem_base;
}
// how many symbols will be encoded in this round
size_t encode_len = MIN(mem_want, mem_have);
bool encoding_truncated = mem_have < mem_want;
bool encoding_space_free = mem_have > mem_want;
if (channel->dma_chan) {
// mark the start descriptor
if (tx_chan->mem_off < tx_chan->ping_pong_symbols) {
desc0 = &tx_chan->dma_nodes_nc[0];
} else {
desc0 = &tx_chan->dma_nodes_nc[1];
}
}
size_t len = encode_len;
while (len > 0) {
// start from last time truncated encoding
uint8_t cur_byte = raw_data[byte_index];
// bit-wise reverse
if (bytes_encoder->flags.msb_first) {
cur_byte = hal_utils_bitwise_reverse8(cur_byte);
}
while ((len > 0) && (bit_index < 8)) {
if (cur_byte & (1 << bit_index)) {
mem_to_nc[tx_chan->mem_off++] = bytes_encoder->bit1;
} else {
mem_to_nc[tx_chan->mem_off++] = bytes_encoder->bit0;
}
len--;
bit_index++;
}
if (bit_index >= 8) {
byte_index++;
bit_index = 0;
}
}
if (channel->dma_chan) {
// mark the end descriptor
if (tx_chan->mem_off < tx_chan->ping_pong_symbols) {
desc1 = &tx_chan->dma_nodes_nc[0];
} else {
desc1 = &tx_chan->dma_nodes_nc[1];
}
// cross line, means desc0 has prepared with sufficient data buffer
if (desc0 != desc1) {
desc0->dw0.length = tx_chan->ping_pong_symbols * sizeof(rmt_symbol_word_t);
desc0->dw0.owner = DMA_DESCRIPTOR_BUFFER_OWNER_DMA;
}
}
if (encoding_truncated) {
// this encoding has not finished yet, save the truncated position
bytes_encoder->last_bit_index = bit_index;
bytes_encoder->last_byte_index = byte_index;
} else {
// reset internal index if encoding session has finished
bytes_encoder->last_bit_index = 0;
bytes_encoder->last_byte_index = 0;
state |= RMT_ENCODING_COMPLETE;
}
if (!encoding_space_free) {
// no more free memory, the caller should yield
state |= RMT_ENCODING_MEM_FULL;
}
// reset offset pointer when exceeds maximum range
if (tx_chan->mem_off >= tx_chan->ping_pong_symbols * 2) {
if (channel->dma_chan) {
desc1->dw0.length = tx_chan->ping_pong_symbols * sizeof(rmt_symbol_word_t);
desc1->dw0.owner = DMA_DESCRIPTOR_BUFFER_OWNER_DMA;
}
tx_chan->mem_off = 0;
}
*ret_state = state;
return encode_len;
}
static esp_err_t rmt_copy_encoder_reset(rmt_encoder_t *encoder)
{
rmt_copy_encoder_t *copy_encoder = __containerof(encoder, rmt_copy_encoder_t, base);
copy_encoder->last_symbol_index = 0;
return ESP_OK;
}
static size_t IRAM_ATTR rmt_encode_copy(rmt_encoder_t *encoder, rmt_channel_handle_t channel,
const void *primary_data, size_t data_size, rmt_encode_state_t *ret_state)
{
rmt_copy_encoder_t *copy_encoder = __containerof(encoder, rmt_copy_encoder_t, base);
rmt_tx_channel_t *tx_chan = __containerof(channel, rmt_tx_channel_t, base);
rmt_symbol_word_t *symbols = (rmt_symbol_word_t *)primary_data;
rmt_encode_state_t state = RMT_ENCODING_RESET;
rmt_dma_descriptor_t *desc0 = NULL;
rmt_dma_descriptor_t *desc1 = NULL;
size_t symbol_index = copy_encoder->last_symbol_index;
// how many symbols will be copied by the encoder
size_t mem_want = (data_size / 4 - symbol_index);
// how many symbols we can save for this round
size_t mem_have = tx_chan->mem_end - tx_chan->mem_off;
// where to put the encoded symbols? DMA buffer or RMT HW memory
rmt_symbol_word_t *mem_to_nc = NULL;
if (channel->dma_chan) {
mem_to_nc = tx_chan->dma_mem_base_nc;
} else {
mem_to_nc = channel->hw_mem_base;
}
// how many symbols will be encoded in this round
size_t encode_len = MIN(mem_want, mem_have);
bool encoding_truncated = mem_have < mem_want;
bool encoding_space_free = mem_have > mem_want;
if (channel->dma_chan) {
// mark the start descriptor
if (tx_chan->mem_off < tx_chan->ping_pong_symbols) {
desc0 = &tx_chan->dma_nodes_nc[0];
} else {
desc0 = &tx_chan->dma_nodes_nc[1];
}
}
size_t len = encode_len;
while (len > 0) {
mem_to_nc[tx_chan->mem_off++] = symbols[symbol_index++];
len--;
}
if (channel->dma_chan) {
// mark the end descriptor
if (tx_chan->mem_off < tx_chan->ping_pong_symbols) {
desc1 = &tx_chan->dma_nodes_nc[0];
} else {
desc1 = &tx_chan->dma_nodes_nc[1];
}
// cross line, means desc0 has prepared with sufficient data buffer
if (desc0 != desc1) {
desc0->dw0.length = tx_chan->ping_pong_symbols * sizeof(rmt_symbol_word_t);
desc0->dw0.owner = DMA_DESCRIPTOR_BUFFER_OWNER_DMA;
}
}
if (encoding_truncated) {
// this encoding has not finished yet, save the truncated position
copy_encoder->last_symbol_index = symbol_index;
} else {
// reset internal index if encoding session has finished
copy_encoder->last_symbol_index = 0;
state |= RMT_ENCODING_COMPLETE;
}
if (!encoding_space_free) {
// no more free memory, the caller should yield
state |= RMT_ENCODING_MEM_FULL;
}
// reset offset pointer when exceeds maximum range
if (tx_chan->mem_off >= tx_chan->ping_pong_symbols * 2) {
if (channel->dma_chan) {
desc1->dw0.length = tx_chan->ping_pong_symbols * sizeof(rmt_symbol_word_t);
desc1->dw0.owner = DMA_DESCRIPTOR_BUFFER_OWNER_DMA;
}
tx_chan->mem_off = 0;
}
*ret_state = state;
return encode_len;
}
static size_t IRAM_ATTR rmt_encode_simple(rmt_encoder_t *encoder, rmt_channel_handle_t channel,
const void *data, size_t data_size, rmt_encode_state_t *ret_state)
{
rmt_simple_encoder_t *simple_encoder = __containerof(encoder, rmt_simple_encoder_t, base);
rmt_tx_channel_t *tx_chan = __containerof(channel, rmt_tx_channel_t, base);
rmt_encode_state_t state = RMT_ENCODING_RESET;
rmt_dma_descriptor_t *desc0 = NULL;
rmt_dma_descriptor_t *desc1 = NULL;
// where to put the encoded symbols? DMA buffer or RMT HW memory
rmt_symbol_word_t *mem_to_nc = NULL;
if (channel->dma_chan) {
mem_to_nc = tx_chan->dma_mem_base_nc;
} else {
mem_to_nc = channel->hw_mem_base;
}
if (channel->dma_chan) {
// mark the start descriptor
if (tx_chan->mem_off < tx_chan->ping_pong_symbols) {
desc0 = &tx_chan->dma_nodes_nc[0];
} else {
desc0 = &tx_chan->dma_nodes_nc[1];
}
}
// While we're not done, we need to use the callback to fill the RMT memory until it is
// exactly entirely full. We cannot do that if the RMT memory still has N free spaces
// but the encoder callback needs more than N spaces to properly encode a symbol.
// In order to work around that, if we detect that situation we let the encoder
// encode into an overflow buffer, then we use the contents of that buffer to fill
// those last N spaces. On the next call, we will first output the rest of the
// overflow buffer before again using the callback to continue filling the RMT
// buffer.
// Note the next code is in a while loop to properly handle 'unsure' callbacks that
// e.g. return 0 with a free buffer size of M, but then return less than M symbols
// when then called with a larger buffer.
size_t encode_len = 0; //total amount of symbols written to rmt memory
bool is_done = false;
while (tx_chan->mem_off < tx_chan->mem_end) {
if (simple_encoder->ovf_buf_parsed_pos < simple_encoder->ovf_buf_fill_len) {
// Overflow buffer has data from the previous encoding call. Copy one entry
// from that.
mem_to_nc[tx_chan->mem_off++] = simple_encoder->ovf_buf[simple_encoder->ovf_buf_parsed_pos++];
encode_len++;
} else {
// Overflow buffer is empty, so we don't need to empty that first.
if (simple_encoder->callback_done) {
// We cannot call the callback anymore and the overflow buffer
// is empty, so we're done with the transaction.
is_done = true;
break;
}
// Try to have the callback write the data directly into RMT memory.
size_t enc_size = simple_encoder->callback(data, data_size,
simple_encoder->last_symbol_index,
tx_chan->mem_end - tx_chan->mem_off,
&mem_to_nc[tx_chan->mem_off],
&is_done, simple_encoder->arg);
encode_len += enc_size;
tx_chan->mem_off += enc_size;
simple_encoder->last_symbol_index += enc_size;
if (is_done) {
break; // we're done, no more data to write to RMT memory.
}
if (enc_size == 0) {
// The encoder does not have enough space in RMT memory to encode its thing,
// but the RMT memory is not filled out entirely. Encode into the overflow
// buffer so the next iterations of the loop can fill out the RMT buffer
// from that.
enc_size = simple_encoder->callback(data, data_size,
simple_encoder->last_symbol_index,
simple_encoder->ovf_buf_size,
simple_encoder->ovf_buf,
&is_done, simple_encoder->arg);
simple_encoder->last_symbol_index += enc_size;
//Note we do *not* update encode_len here as the data isn't going to the RMT yet.
simple_encoder->ovf_buf_fill_len = enc_size;
simple_encoder->ovf_buf_parsed_pos = 0;
if (is_done) {
// If the encoder is done, we cannot call the callback anymore, but we still
// need to handle any data in the overflow buffer.
simple_encoder->callback_done = true;
} else {
if (enc_size == 0) {
//According to the callback docs, this is illegal.
//Report this. EARLY_LOGE as we're running from an ISR.
ESP_EARLY_LOGE(TAG, "rmt_encoder_simple: encoder callback returned 0 when fed a buffer of config::min_chunk_size!");
//Then abort the transaction.
is_done = true;
break;
}
}
}
}
}
if (channel->dma_chan) {
// mark the end descriptor
if (tx_chan->mem_off < tx_chan->ping_pong_symbols) {
desc1 = &tx_chan->dma_nodes_nc[0];
} else {
desc1 = &tx_chan->dma_nodes_nc[1];
}
// cross line, means desc0 has prepared with sufficient data buffer
if (desc0 != desc1) {
desc0->dw0.length = tx_chan->ping_pong_symbols * sizeof(rmt_symbol_word_t);
desc0->dw0.owner = DMA_DESCRIPTOR_BUFFER_OWNER_DMA;
}
}
if (is_done) {
// reset internal index if encoding session has finished
simple_encoder->last_symbol_index = 0;
state |= RMT_ENCODING_COMPLETE;
} else {
// no more free memory, the caller should yield
state |= RMT_ENCODING_MEM_FULL;
}
// reset offset pointer when exceeds maximum range
if (tx_chan->mem_off >= tx_chan->ping_pong_symbols * 2) {
if (channel->dma_chan) {
desc1->dw0.length = tx_chan->ping_pong_symbols * sizeof(rmt_symbol_word_t);
desc1->dw0.owner = DMA_DESCRIPTOR_BUFFER_OWNER_DMA;
}
tx_chan->mem_off = 0;
}
*ret_state = state;
return encode_len;
}
static esp_err_t rmt_del_bytes_encoder(rmt_encoder_t *encoder)
{
rmt_bytes_encoder_t *bytes_encoder = __containerof(encoder, rmt_bytes_encoder_t, base);
free(bytes_encoder);
return ESP_OK;
}
static esp_err_t rmt_del_copy_encoder(rmt_encoder_t *encoder)
{
rmt_copy_encoder_t *copy_encoder = __containerof(encoder, rmt_copy_encoder_t, base);
free(copy_encoder);
return ESP_OK;
}
static esp_err_t rmt_simple_encoder_reset(rmt_encoder_t *encoder)
{
rmt_simple_encoder_t *simple_encoder = __containerof(encoder, rmt_simple_encoder_t, base);
simple_encoder->last_symbol_index = 0;
simple_encoder->ovf_buf_fill_len = 0;
simple_encoder->ovf_buf_parsed_pos = 0;
simple_encoder->callback_done = false;
return ESP_OK;
}
static esp_err_t rmt_del_simple_encoder(rmt_encoder_t *encoder)
{
rmt_simple_encoder_t *simple_encoder = __containerof(encoder, rmt_simple_encoder_t, base);
if (simple_encoder->ovf_buf) {
free(simple_encoder->ovf_buf);
}
free(simple_encoder);
return ESP_OK;
}
esp_err_t rmt_new_bytes_encoder(const rmt_bytes_encoder_config_t *config, rmt_encoder_handle_t *ret_encoder)
{
esp_err_t ret = ESP_OK;
ESP_GOTO_ON_FALSE(config && ret_encoder, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
rmt_bytes_encoder_t *encoder = rmt_alloc_encoder_mem(sizeof(rmt_bytes_encoder_t));
ESP_GOTO_ON_FALSE(encoder, ESP_ERR_NO_MEM, err, TAG, "no mem for bytes encoder");
encoder->base.encode = rmt_encode_bytes;
encoder->base.del = rmt_del_bytes_encoder;
encoder->base.reset = rmt_bytes_encoder_reset;
encoder->bit0 = config->bit0;
encoder->bit1 = config->bit1;
encoder->flags.msb_first = config->flags.msb_first;
// return general encoder handle
*ret_encoder = &encoder->base;
ESP_LOGD(TAG, "new bytes encoder @%p", encoder);
err:
return ret;
}
esp_err_t rmt_bytes_encoder_update_config(rmt_encoder_handle_t bytes_encoder, const rmt_bytes_encoder_config_t *config)
{
ESP_RETURN_ON_FALSE(bytes_encoder && config, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
rmt_bytes_encoder_t *encoder = __containerof(bytes_encoder, rmt_bytes_encoder_t, base);
encoder->bit0 = config->bit0;
encoder->bit1 = config->bit1;
encoder->flags.msb_first = config->flags.msb_first;
return ESP_OK;
}
esp_err_t rmt_new_copy_encoder(const rmt_copy_encoder_config_t *config, rmt_encoder_handle_t *ret_encoder)
{
esp_err_t ret = ESP_OK;
ESP_GOTO_ON_FALSE(config && ret_encoder, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
rmt_copy_encoder_t *encoder = rmt_alloc_encoder_mem(sizeof(rmt_copy_encoder_t));
ESP_GOTO_ON_FALSE(encoder, ESP_ERR_NO_MEM, err, TAG, "no mem for copy encoder");
encoder->base.encode = rmt_encode_copy;
encoder->base.del = rmt_del_copy_encoder;
encoder->base.reset = rmt_copy_encoder_reset;
// return general encoder handle
*ret_encoder = &encoder->base;
ESP_LOGD(TAG, "new copy encoder @%p", encoder);
err:
return ret;
}
esp_err_t rmt_new_simple_encoder(const rmt_simple_encoder_config_t *config, rmt_encoder_handle_t *ret_encoder)
{
esp_err_t ret = ESP_OK;
rmt_simple_encoder_t *encoder = NULL;
ESP_GOTO_ON_FALSE(config && ret_encoder, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
encoder = rmt_alloc_encoder_mem(sizeof(rmt_simple_encoder_t));
ESP_GOTO_ON_FALSE(encoder, ESP_ERR_NO_MEM, err, TAG, "no mem for simple encoder");
encoder->base.encode = rmt_encode_simple;
encoder->base.del = rmt_del_simple_encoder;
encoder->base.reset = rmt_simple_encoder_reset;
encoder->callback = config->callback;
encoder->arg = config->arg;
size_t min_chunk_size = config->min_chunk_size;
if (min_chunk_size == 0) {
min_chunk_size = 64;
}
encoder->ovf_buf = rmt_alloc_encoder_mem(min_chunk_size * sizeof(rmt_symbol_word_t));
ESP_GOTO_ON_FALSE(encoder->ovf_buf, ESP_ERR_NO_MEM, err, TAG, "no mem for simple encoder overflow buffer");
encoder->ovf_buf_size = min_chunk_size;
encoder->ovf_buf_fill_len = 0;
encoder->ovf_buf_parsed_pos = 0;
// return general encoder handle
*ret_encoder = &encoder->base;
ESP_LOGD(TAG, "new simple encoder @%p", encoder);
return ret;
err:
if (encoder) {
free(encoder);
}
return ret;
}
esp_err_t rmt_del_encoder(rmt_encoder_handle_t encoder)
{

View File

@@ -0,0 +1,168 @@
/*
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "driver/rmt_encoder.h"
#include "rmt_private.h"
typedef struct rmt_bytes_encoder_t {
rmt_encoder_t base; // encoder base class
size_t last_bit_index; // index of the encoding bit position in the encoding byte
size_t last_byte_index; // index of the encoding byte in the primary stream
rmt_symbol_word_t bit0; // bit zero representing
rmt_symbol_word_t bit1; // bit one representing
struct {
uint32_t msb_first: 1; // encode MSB firstly
} flags;
} rmt_bytes_encoder_t;
static esp_err_t rmt_bytes_encoder_reset(rmt_encoder_t *encoder)
{
rmt_bytes_encoder_t *bytes_encoder = __containerof(encoder, rmt_bytes_encoder_t, base);
// reset index to zero
bytes_encoder->last_bit_index = 0;
bytes_encoder->last_byte_index = 0;
return ESP_OK;
}
static size_t IRAM_ATTR rmt_encode_bytes(rmt_encoder_t *encoder, rmt_channel_handle_t channel,
const void *primary_data, size_t data_size, rmt_encode_state_t *ret_state)
{
rmt_bytes_encoder_t *bytes_encoder = __containerof(encoder, rmt_bytes_encoder_t, base);
rmt_tx_channel_t *tx_chan = __containerof(channel, rmt_tx_channel_t, base);
const uint8_t *raw_data = (const uint8_t *)primary_data;
rmt_encode_state_t state = RMT_ENCODING_RESET;
rmt_dma_descriptor_t *desc0 = NULL;
rmt_dma_descriptor_t *desc1 = NULL;
size_t byte_index = bytes_encoder->last_byte_index;
size_t bit_index = bytes_encoder->last_bit_index;
// how many symbols will be generated by the encoder
size_t mem_want = (data_size - byte_index - 1) * 8 + (8 - bit_index);
// how many symbols we can save for this round
size_t mem_have = tx_chan->mem_end - tx_chan->mem_off;
// where to put the encoded symbols? DMA buffer or RMT HW memory
rmt_symbol_word_t *mem_to_nc = NULL;
if (channel->dma_chan) {
mem_to_nc = tx_chan->dma_mem_base_nc;
} else {
mem_to_nc = channel->hw_mem_base;
}
// how many symbols will be encoded in this round
size_t encode_len = MIN(mem_want, mem_have);
bool encoding_truncated = mem_have < mem_want;
bool encoding_space_free = mem_have > mem_want;
if (channel->dma_chan) {
// mark the start descriptor
if (tx_chan->mem_off < tx_chan->ping_pong_symbols) {
desc0 = &tx_chan->dma_nodes_nc[0];
} else {
desc0 = &tx_chan->dma_nodes_nc[1];
}
}
size_t len = encode_len;
while (len > 0) {
// start from last time truncated encoding
uint8_t cur_byte = raw_data[byte_index];
// bit-wise reverse
if (bytes_encoder->flags.msb_first) {
cur_byte = hal_utils_bitwise_reverse8(cur_byte);
}
while ((len > 0) && (bit_index < 8)) {
if (cur_byte & (1 << bit_index)) {
mem_to_nc[tx_chan->mem_off++] = bytes_encoder->bit1;
} else {
mem_to_nc[tx_chan->mem_off++] = bytes_encoder->bit0;
}
len--;
bit_index++;
}
if (bit_index >= 8) {
byte_index++;
bit_index = 0;
}
}
if (channel->dma_chan) {
// mark the end descriptor
if (tx_chan->mem_off < tx_chan->ping_pong_symbols) {
desc1 = &tx_chan->dma_nodes_nc[0];
} else {
desc1 = &tx_chan->dma_nodes_nc[1];
}
// cross line, means desc0 has prepared with sufficient data buffer
if (desc0 != desc1) {
desc0->dw0.length = tx_chan->ping_pong_symbols * sizeof(rmt_symbol_word_t);
desc0->dw0.owner = DMA_DESCRIPTOR_BUFFER_OWNER_DMA;
}
}
if (encoding_truncated) {
// this encoding has not finished yet, save the truncated position
bytes_encoder->last_bit_index = bit_index;
bytes_encoder->last_byte_index = byte_index;
} else {
// reset internal index if encoding session has finished
bytes_encoder->last_bit_index = 0;
bytes_encoder->last_byte_index = 0;
state |= RMT_ENCODING_COMPLETE;
}
if (!encoding_space_free) {
// no more free memory, the caller should yield
state |= RMT_ENCODING_MEM_FULL;
}
// reset offset pointer when exceeds maximum range
if (tx_chan->mem_off >= tx_chan->ping_pong_symbols * 2) {
if (channel->dma_chan) {
desc1->dw0.length = tx_chan->ping_pong_symbols * sizeof(rmt_symbol_word_t);
desc1->dw0.owner = DMA_DESCRIPTOR_BUFFER_OWNER_DMA;
}
tx_chan->mem_off = 0;
}
*ret_state = state;
return encode_len;
}
static esp_err_t rmt_del_bytes_encoder(rmt_encoder_t *encoder)
{
rmt_bytes_encoder_t *bytes_encoder = __containerof(encoder, rmt_bytes_encoder_t, base);
free(bytes_encoder);
return ESP_OK;
}
esp_err_t rmt_new_bytes_encoder(const rmt_bytes_encoder_config_t *config, rmt_encoder_handle_t *ret_encoder)
{
esp_err_t ret = ESP_OK;
ESP_GOTO_ON_FALSE(config && ret_encoder, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
rmt_bytes_encoder_t *encoder = rmt_alloc_encoder_mem(sizeof(rmt_bytes_encoder_t));
ESP_GOTO_ON_FALSE(encoder, ESP_ERR_NO_MEM, err, TAG, "no mem for bytes encoder");
encoder->base.encode = rmt_encode_bytes;
encoder->base.del = rmt_del_bytes_encoder;
encoder->base.reset = rmt_bytes_encoder_reset;
encoder->bit0 = config->bit0;
encoder->bit1 = config->bit1;
encoder->flags.msb_first = config->flags.msb_first;
// return general encoder handle
*ret_encoder = &encoder->base;
ESP_LOGD(TAG, "new bytes encoder @%p", encoder);
err:
return ret;
}
esp_err_t rmt_bytes_encoder_update_config(rmt_encoder_handle_t bytes_encoder, const rmt_bytes_encoder_config_t *config)
{
ESP_RETURN_ON_FALSE(bytes_encoder && config, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
rmt_bytes_encoder_t *encoder = __containerof(bytes_encoder, rmt_bytes_encoder_t, base);
encoder->bit0 = config->bit0;
encoder->bit1 = config->bit1;
encoder->flags.msb_first = config->flags.msb_first;
return ESP_OK;
}

View File

@@ -0,0 +1,127 @@
/*
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "driver/rmt_encoder.h"
#include "rmt_private.h"
typedef struct rmt_copy_encoder_t {
rmt_encoder_t base; // encoder base class
size_t last_symbol_index; // index of symbol position in the primary stream
} rmt_copy_encoder_t;
static esp_err_t rmt_copy_encoder_reset(rmt_encoder_t *encoder)
{
rmt_copy_encoder_t *copy_encoder = __containerof(encoder, rmt_copy_encoder_t, base);
copy_encoder->last_symbol_index = 0;
return ESP_OK;
}
static size_t IRAM_ATTR rmt_encode_copy(rmt_encoder_t *encoder, rmt_channel_handle_t channel,
const void *primary_data, size_t data_size, rmt_encode_state_t *ret_state)
{
rmt_copy_encoder_t *copy_encoder = __containerof(encoder, rmt_copy_encoder_t, base);
rmt_tx_channel_t *tx_chan = __containerof(channel, rmt_tx_channel_t, base);
rmt_symbol_word_t *symbols = (rmt_symbol_word_t *)primary_data;
rmt_encode_state_t state = RMT_ENCODING_RESET;
rmt_dma_descriptor_t *desc0 = NULL;
rmt_dma_descriptor_t *desc1 = NULL;
size_t symbol_index = copy_encoder->last_symbol_index;
// how many symbols will be copied by the encoder
size_t mem_want = (data_size / 4 - symbol_index);
// how many symbols we can save for this round
size_t mem_have = tx_chan->mem_end - tx_chan->mem_off;
// where to put the encoded symbols? DMA buffer or RMT HW memory
rmt_symbol_word_t *mem_to_nc = NULL;
if (channel->dma_chan) {
mem_to_nc = tx_chan->dma_mem_base_nc;
} else {
mem_to_nc = channel->hw_mem_base;
}
// how many symbols will be encoded in this round
size_t encode_len = MIN(mem_want, mem_have);
bool encoding_truncated = mem_have < mem_want;
bool encoding_space_free = mem_have > mem_want;
if (channel->dma_chan) {
// mark the start descriptor
if (tx_chan->mem_off < tx_chan->ping_pong_symbols) {
desc0 = &tx_chan->dma_nodes_nc[0];
} else {
desc0 = &tx_chan->dma_nodes_nc[1];
}
}
size_t len = encode_len;
while (len > 0) {
mem_to_nc[tx_chan->mem_off++] = symbols[symbol_index++];
len--;
}
if (channel->dma_chan) {
// mark the end descriptor
if (tx_chan->mem_off < tx_chan->ping_pong_symbols) {
desc1 = &tx_chan->dma_nodes_nc[0];
} else {
desc1 = &tx_chan->dma_nodes_nc[1];
}
// cross line, means desc0 has prepared with sufficient data buffer
if (desc0 != desc1) {
desc0->dw0.length = tx_chan->ping_pong_symbols * sizeof(rmt_symbol_word_t);
desc0->dw0.owner = DMA_DESCRIPTOR_BUFFER_OWNER_DMA;
}
}
if (encoding_truncated) {
// this encoding has not finished yet, save the truncated position
copy_encoder->last_symbol_index = symbol_index;
} else {
// reset internal index if encoding session has finished
copy_encoder->last_symbol_index = 0;
state |= RMT_ENCODING_COMPLETE;
}
if (!encoding_space_free) {
// no more free memory, the caller should yield
state |= RMT_ENCODING_MEM_FULL;
}
// reset offset pointer when exceeds maximum range
if (tx_chan->mem_off >= tx_chan->ping_pong_symbols * 2) {
if (channel->dma_chan) {
desc1->dw0.length = tx_chan->ping_pong_symbols * sizeof(rmt_symbol_word_t);
desc1->dw0.owner = DMA_DESCRIPTOR_BUFFER_OWNER_DMA;
}
tx_chan->mem_off = 0;
}
*ret_state = state;
return encode_len;
}
static esp_err_t rmt_del_copy_encoder(rmt_encoder_t *encoder)
{
rmt_copy_encoder_t *copy_encoder = __containerof(encoder, rmt_copy_encoder_t, base);
free(copy_encoder);
return ESP_OK;
}
esp_err_t rmt_new_copy_encoder(const rmt_copy_encoder_config_t *config, rmt_encoder_handle_t *ret_encoder)
{
esp_err_t ret = ESP_OK;
ESP_GOTO_ON_FALSE(config && ret_encoder, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
rmt_copy_encoder_t *encoder = rmt_alloc_encoder_mem(sizeof(rmt_copy_encoder_t));
ESP_GOTO_ON_FALSE(encoder, ESP_ERR_NO_MEM, err, TAG, "no mem for copy encoder");
encoder->base.encode = rmt_encode_copy;
encoder->base.del = rmt_del_copy_encoder;
encoder->base.reset = rmt_copy_encoder_reset;
// return general encoder handle
*ret_encoder = &encoder->base;
ESP_LOGD(TAG, "new copy encoder @%p", encoder);
err:
return ret;
}

View File

@@ -0,0 +1,210 @@
/*
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "driver/rmt_encoder.h"
#include "rmt_private.h"
typedef struct rmt_simple_encoder_t {
rmt_encoder_t base; // encoder base class
size_t last_symbol_index; // index of symbol position in the primary stream
rmt_encode_simple_cb_t callback; //callback to call to encode
void *arg; // opaque callback argument
rmt_symbol_word_t *ovf_buf; //overflow buffer
size_t ovf_buf_size; //size, in elements, of overflow buffer
size_t ovf_buf_fill_len; //how much actual info the overflow buffer has
size_t ovf_buf_parsed_pos; //up to where we moved info from the ovf buf to the rmt
bool callback_done; //true if we can't call the callback for more data anymore.
} rmt_simple_encoder_t;
static esp_err_t rmt_simple_encoder_reset(rmt_encoder_t *encoder)
{
rmt_simple_encoder_t *simple_encoder = __containerof(encoder, rmt_simple_encoder_t, base);
simple_encoder->last_symbol_index = 0;
simple_encoder->ovf_buf_fill_len = 0;
simple_encoder->ovf_buf_parsed_pos = 0;
simple_encoder->callback_done = false;
return ESP_OK;
}
static size_t IRAM_ATTR rmt_encode_simple(rmt_encoder_t *encoder, rmt_channel_handle_t channel,
const void *data, size_t data_size, rmt_encode_state_t *ret_state)
{
rmt_simple_encoder_t *simple_encoder = __containerof(encoder, rmt_simple_encoder_t, base);
rmt_tx_channel_t *tx_chan = __containerof(channel, rmt_tx_channel_t, base);
rmt_encode_state_t state = RMT_ENCODING_RESET;
rmt_dma_descriptor_t *desc0 = NULL;
rmt_dma_descriptor_t *desc1 = NULL;
// where to put the encoded symbols? DMA buffer or RMT HW memory
rmt_symbol_word_t *mem_to_nc = NULL;
if (channel->dma_chan) {
mem_to_nc = tx_chan->dma_mem_base_nc;
} else {
mem_to_nc = channel->hw_mem_base;
}
if (channel->dma_chan) {
// mark the start descriptor
if (tx_chan->mem_off < tx_chan->ping_pong_symbols) {
desc0 = &tx_chan->dma_nodes_nc[0];
} else {
desc0 = &tx_chan->dma_nodes_nc[1];
}
}
// While we're not done, we need to use the callback to fill the RMT memory until it is
// exactly entirely full. We cannot do that if the RMT memory still has N free spaces
// but the encoder callback needs more than N spaces to properly encode a symbol.
// In order to work around that, if we detect that situation we let the encoder
// encode into an overflow buffer, then we use the contents of that buffer to fill
// those last N spaces. On the next call, we will first output the rest of the
// overflow buffer before again using the callback to continue filling the RMT
// buffer.
// Note the next code is in a while loop to properly handle 'unsure' callbacks that
// e.g. return 0 with a free buffer size of M, but then return less than M symbols
// when then called with a larger buffer.
size_t encode_len = 0; //total amount of symbols written to rmt memory
bool is_done = false;
while (tx_chan->mem_off < tx_chan->mem_end) {
if (simple_encoder->ovf_buf_parsed_pos < simple_encoder->ovf_buf_fill_len) {
// Overflow buffer has data from the previous encoding call. Copy one entry
// from that.
mem_to_nc[tx_chan->mem_off++] = simple_encoder->ovf_buf[simple_encoder->ovf_buf_parsed_pos++];
encode_len++;
} else {
// Overflow buffer is empty, so we don't need to empty that first.
if (simple_encoder->callback_done) {
// We cannot call the callback anymore and the overflow buffer
// is empty, so we're done with the transaction.
is_done = true;
break;
}
// Try to have the callback write the data directly into RMT memory.
size_t enc_size = simple_encoder->callback(data, data_size,
simple_encoder->last_symbol_index,
tx_chan->mem_end - tx_chan->mem_off,
&mem_to_nc[tx_chan->mem_off],
&is_done, simple_encoder->arg);
encode_len += enc_size;
tx_chan->mem_off += enc_size;
simple_encoder->last_symbol_index += enc_size;
if (is_done) {
break; // we're done, no more data to write to RMT memory.
}
if (enc_size == 0) {
// The encoder does not have enough space in RMT memory to encode its thing,
// but the RMT memory is not filled out entirely. Encode into the overflow
// buffer so the next iterations of the loop can fill out the RMT buffer
// from that.
enc_size = simple_encoder->callback(data, data_size,
simple_encoder->last_symbol_index,
simple_encoder->ovf_buf_size,
simple_encoder->ovf_buf,
&is_done, simple_encoder->arg);
simple_encoder->last_symbol_index += enc_size;
//Note we do *not* update encode_len here as the data isn't going to the RMT yet.
simple_encoder->ovf_buf_fill_len = enc_size;
simple_encoder->ovf_buf_parsed_pos = 0;
if (is_done) {
// If the encoder is done, we cannot call the callback anymore, but we still
// need to handle any data in the overflow buffer.
simple_encoder->callback_done = true;
} else {
if (enc_size == 0) {
//According to the callback docs, this is illegal.
//Report this. EARLY_LOGE as we're running from an ISR.
ESP_EARLY_LOGE(TAG, "rmt_encoder_simple: encoder callback returned 0 when fed a buffer of config::min_chunk_size!");
//Then abort the transaction.
is_done = true;
break;
}
}
}
}
}
if (channel->dma_chan) {
// mark the end descriptor
if (tx_chan->mem_off < tx_chan->ping_pong_symbols) {
desc1 = &tx_chan->dma_nodes_nc[0];
} else {
desc1 = &tx_chan->dma_nodes_nc[1];
}
// cross line, means desc0 has prepared with sufficient data buffer
if (desc0 != desc1) {
desc0->dw0.length = tx_chan->ping_pong_symbols * sizeof(rmt_symbol_word_t);
desc0->dw0.owner = DMA_DESCRIPTOR_BUFFER_OWNER_DMA;
}
}
if (is_done) {
// reset internal index if encoding session has finished
simple_encoder->last_symbol_index = 0;
state |= RMT_ENCODING_COMPLETE;
} else {
// no more free memory, the caller should yield
state |= RMT_ENCODING_MEM_FULL;
}
// reset offset pointer when exceeds maximum range
if (tx_chan->mem_off >= tx_chan->ping_pong_symbols * 2) {
if (channel->dma_chan) {
desc1->dw0.length = tx_chan->ping_pong_symbols * sizeof(rmt_symbol_word_t);
desc1->dw0.owner = DMA_DESCRIPTOR_BUFFER_OWNER_DMA;
}
tx_chan->mem_off = 0;
}
*ret_state = state;
return encode_len;
}
static esp_err_t rmt_del_simple_encoder(rmt_encoder_t *encoder)
{
rmt_simple_encoder_t *simple_encoder = __containerof(encoder, rmt_simple_encoder_t, base);
if (simple_encoder->ovf_buf) {
free(simple_encoder->ovf_buf);
}
free(simple_encoder);
return ESP_OK;
}
esp_err_t rmt_new_simple_encoder(const rmt_simple_encoder_config_t *config, rmt_encoder_handle_t *ret_encoder)
{
esp_err_t ret = ESP_OK;
rmt_simple_encoder_t *encoder = NULL;
ESP_GOTO_ON_FALSE(config && ret_encoder, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
encoder = rmt_alloc_encoder_mem(sizeof(rmt_simple_encoder_t));
ESP_GOTO_ON_FALSE(encoder, ESP_ERR_NO_MEM, err, TAG, "no mem for simple encoder");
encoder->base.encode = rmt_encode_simple;
encoder->base.del = rmt_del_simple_encoder;
encoder->base.reset = rmt_simple_encoder_reset;
encoder->callback = config->callback;
encoder->arg = config->arg;
size_t min_chunk_size = config->min_chunk_size;
if (min_chunk_size == 0) {
min_chunk_size = 64;
}
encoder->ovf_buf = rmt_alloc_encoder_mem(min_chunk_size * sizeof(rmt_symbol_word_t));
ESP_GOTO_ON_FALSE(encoder->ovf_buf, ESP_ERR_NO_MEM, err, TAG, "no mem for simple encoder overflow buffer");
encoder->ovf_buf_size = min_chunk_size;
encoder->ovf_buf_fill_len = 0;
encoder->ovf_buf_parsed_pos = 0;
// return general encoder handle
*ret_encoder = &encoder->base;
ESP_LOGD(TAG, "new simple encoder @%p", encoder);
return ret;
err:
if (encoder) {
free(encoder);
}
return ret;
}

View File

@@ -6,19 +6,34 @@
#pragma once
#include <stdlib.h>
#include <string.h>
#include <sys/cdefs.h>
#include <sys/param.h>
#include <sys/lock.h>
#include <stdatomic.h>
#include "sdkconfig.h"
#if CONFIG_RMT_ENABLE_DEBUG_LOG
// The local log level must be defined before including esp_log.h
// Set the maximum log level for rmt driver
#define LOG_LOCAL_LEVEL ESP_LOG_VERBOSE
#endif
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "freertos/idf_additions.h"
#include "esp_log.h"
#include "esp_check.h"
#include "esp_err.h"
#include "soc/soc_caps.h"
#include "soc/gdma_channel.h"
#include "soc/rmt_periph.h"
#include "hal/rmt_types.h"
#include "hal/rmt_hal.h"
#include "hal/rmt_ll.h"
#include "hal/dma_types.h"
#include "hal/cache_ll.h"
#include "hal/cache_hal.h"
#include "hal/hal_utils.h"
#include "esp_intr_alloc.h"
#include "esp_heap_caps.h"
@@ -29,7 +44,9 @@
#include "esp_private/esp_gpio_reserve.h"
#include "esp_private/gpio.h"
#include "esp_private/sleep_retention.h"
#include "driver/rmt_common.h"
#include "esp_private/periph_ctrl.h"
#include "esp_private/esp_clk_tree_common.h"
#include "driver/rmt_types.h"
#ifdef __cplusplus
extern "C" {
@@ -73,6 +90,9 @@ typedef dma_descriptor_align4_t rmt_dma_descriptor_t;
#define RMT_USE_RETENTION_LINK (SOC_RMT_SUPPORT_SLEEP_RETENTION && CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP)
///!< Logging settings
#define TAG "rmt"
typedef struct {
struct {
rmt_symbol_word_t symbols[SOC_RMT_MEM_WORDS_PER_CHANNEL];

View File

@@ -4,32 +4,15 @@
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdlib.h>
#include <string.h>
#include <sys/cdefs.h>
#include <sys/param.h>
#include "sdkconfig.h"
#if CONFIG_RMT_ENABLE_DEBUG_LOG
// The local log level must be defined before including esp_log.h
// Set the maximum log level for this source file
#define LOG_LOCAL_LEVEL ESP_LOG_DEBUG
#endif
#include "esp_log.h"
#include "esp_check.h"
#include "esp_memory_utils.h"
#include "esp_cache.h"
#include "esp_rom_gpio.h"
#include "soc/rmt_periph.h"
#include "soc/rtc.h"
#include "hal/rmt_ll.h"
#include "hal/cache_hal.h"
#include "hal/gpio_hal.h"
#include "driver/gpio.h"
#include "driver/rmt_rx.h"
#include "rmt_private.h"
static const char *TAG = "rmt";
static esp_err_t rmt_del_rx_channel(rmt_channel_handle_t channel);
static esp_err_t rmt_rx_demodulate_carrier(rmt_channel_handle_t channel, const rmt_carrier_config_t *config);
static esp_err_t rmt_rx_enable(rmt_channel_handle_t channel);
@@ -182,9 +165,6 @@ static esp_err_t rmt_rx_destroy(rmt_rx_channel_t *rx_channel)
esp_err_t rmt_new_rx_channel(const rmt_rx_channel_config_t *config, rmt_channel_handle_t *ret_chan)
{
#if CONFIG_RMT_ENABLE_DEBUG_LOG
esp_log_level_set(TAG, ESP_LOG_DEBUG);
#endif
esp_err_t ret = ESP_OK;
rmt_rx_channel_t *rx_channel = NULL;
// Check if priority is valid

View File

@@ -4,32 +4,14 @@
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdlib.h>
#include <string.h>
#include <sys/cdefs.h>
#include <sys/param.h>
#include "sdkconfig.h"
#if CONFIG_RMT_ENABLE_DEBUG_LOG
// The local log level must be defined before including esp_log.h
// Set the maximum log level for this source file
#define LOG_LOCAL_LEVEL ESP_LOG_DEBUG
#endif
#include "esp_log.h"
#include "esp_check.h"
#include "esp_rom_gpio.h"
#include "soc/rmt_periph.h"
#include "esp_memory_utils.h"
#include "soc/rtc.h"
#include "hal/rmt_ll.h"
#include "hal/gpio_hal.h"
#include "hal/cache_hal.h"
#include "hal/cache_ll.h"
#include "esp_cache.h"
#include "driver/gpio.h"
#include "driver/rmt_tx.h"
#include "rmt_private.h"
#include "esp_memory_utils.h"
static const char *TAG = "rmt";
struct rmt_sync_manager_t {
rmt_group_t *group; // which group the synchro belongs to
@@ -247,9 +229,6 @@ static esp_err_t rmt_tx_destroy(rmt_tx_channel_t *tx_channel)
esp_err_t rmt_new_tx_channel(const rmt_tx_channel_config_t *config, rmt_channel_handle_t *ret_chan)
{
#if CONFIG_RMT_ENABLE_DEBUG_LOG
esp_log_level_set(TAG, ESP_LOG_DEBUG);
#endif
esp_err_t ret = ESP_OK;
rmt_tx_channel_t *tx_channel = NULL;
// Check if priority is valid