From 1877605e590f00826067eca6576260dff47fc5c6 Mon Sep 17 00:00:00 2001 From: morris Date: Fri, 21 Mar 2025 18:56:25 +0800 Subject: [PATCH] change(rmt): split rmt encoders into different files --- components/esp_driver_rmt/CMakeLists.txt | 3 + components/esp_driver_rmt/Kconfig | 11 +- .../include/driver/rmt_common.h | 14 +- .../esp_driver_rmt/include/driver/rmt_types.h | 14 +- components/esp_driver_rmt/src/rmt_common.c | 24 +- components/esp_driver_rmt/src/rmt_encoder.c | 498 +----------------- .../esp_driver_rmt/src/rmt_encoder_bytes.c | 168 ++++++ .../esp_driver_rmt/src/rmt_encoder_copy.c | 127 +++++ .../esp_driver_rmt/src/rmt_encoder_simple.c | 210 ++++++++ components/esp_driver_rmt/src/rmt_private.h | 22 +- components/esp_driver_rmt/src/rmt_rx.c | 20 - components/esp_driver_rmt/src/rmt_tx.c | 23 +- 12 files changed, 561 insertions(+), 573 deletions(-) create mode 100644 components/esp_driver_rmt/src/rmt_encoder_bytes.c create mode 100644 components/esp_driver_rmt/src/rmt_encoder_copy.c create mode 100644 components/esp_driver_rmt/src/rmt_encoder_simple.c diff --git a/components/esp_driver_rmt/CMakeLists.txt b/components/esp_driver_rmt/CMakeLists.txt index fa980f776a..081d601980 100644 --- a/components/esp_driver_rmt/CMakeLists.txt +++ b/components/esp_driver_rmt/CMakeLists.txt @@ -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() diff --git a/components/esp_driver_rmt/Kconfig b/components/esp_driver_rmt/Kconfig index 1530d45063..0af2e0d7db 100644 --- a/components/esp_driver_rmt/Kconfig +++ b/components/esp_driver_rmt/Kconfig @@ -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 diff --git a/components/esp_driver_rmt/include/driver/rmt_common.h b/components/esp_driver_rmt/include/driver/rmt_common.h index c4d5b6430a..97a9b8ca68 100644 --- a/components/esp_driver_rmt/include/driver/rmt_common.h +++ b/components/esp_driver_rmt/include/driver/rmt_common.h @@ -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 * diff --git a/components/esp_driver_rmt/include/driver/rmt_types.h b/components/esp_driver_rmt/include/driver/rmt_types.h index e795cfda8d..4c1a2353f7 100644 --- a/components/esp_driver_rmt/include/driver/rmt_types.h +++ b/components/esp_driver_rmt/include/driver/rmt_types.h @@ -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 diff --git a/components/esp_driver_rmt/src/rmt_common.c b/components/esp_driver_rmt/src/rmt_common.c index 066df4f1a4..d61a950aff 100644 --- a/components/esp_driver_rmt/src/rmt_common.c +++ b/components/esp_driver_rmt/src/rmt_common.c @@ -4,26 +4,10 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include -#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 diff --git a/components/esp_driver_rmt/src/rmt_encoder.c b/components/esp_driver_rmt/src/rmt_encoder.c index 760a0f3462..b6b6ed63b7 100644 --- a/components/esp_driver_rmt/src/rmt_encoder.c +++ b/components/esp_driver_rmt/src/rmt_encoder.c @@ -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 -#include -#include -#include -#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) { diff --git a/components/esp_driver_rmt/src/rmt_encoder_bytes.c b/components/esp_driver_rmt/src/rmt_encoder_bytes.c new file mode 100644 index 0000000000..9580c50ecd --- /dev/null +++ b/components/esp_driver_rmt/src/rmt_encoder_bytes.c @@ -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; +} diff --git a/components/esp_driver_rmt/src/rmt_encoder_copy.c b/components/esp_driver_rmt/src/rmt_encoder_copy.c new file mode 100644 index 0000000000..6d81829454 --- /dev/null +++ b/components/esp_driver_rmt/src/rmt_encoder_copy.c @@ -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; +} diff --git a/components/esp_driver_rmt/src/rmt_encoder_simple.c b/components/esp_driver_rmt/src/rmt_encoder_simple.c new file mode 100644 index 0000000000..32b398e9a5 --- /dev/null +++ b/components/esp_driver_rmt/src/rmt_encoder_simple.c @@ -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; +} diff --git a/components/esp_driver_rmt/src/rmt_private.h b/components/esp_driver_rmt/src/rmt_private.h index d4cecb61a9..23aea64563 100644 --- a/components/esp_driver_rmt/src/rmt_private.h +++ b/components/esp_driver_rmt/src/rmt_private.h @@ -6,19 +6,34 @@ #pragma once +#include +#include +#include +#include +#include #include #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]; diff --git a/components/esp_driver_rmt/src/rmt_rx.c b/components/esp_driver_rmt/src/rmt_rx.c index 10b6238763..420a407ccd 100644 --- a/components/esp_driver_rmt/src/rmt_rx.c +++ b/components/esp_driver_rmt/src/rmt_rx.c @@ -4,32 +4,15 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include -#include -#include -#include -#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 diff --git a/components/esp_driver_rmt/src/rmt_tx.c b/components/esp_driver_rmt/src/rmt_tx.c index 891125216f..b97b220444 100644 --- a/components/esp_driver_rmt/src/rmt_tx.c +++ b/components/esp_driver_rmt/src/rmt_tx.c @@ -4,32 +4,14 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include -#include -#include -#include -#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