From ba376fa81c6dafab9174ff3f361034871cb576e5 Mon Sep 17 00:00:00 2001 From: Chen Jichang Date: Thu, 22 May 2025 14:28:15 +0800 Subject: [PATCH 1/2] fix(rmt): deal with spurious RX done interrupts on ESP32 Closes https://github.com/espressif/esp-idf/issues/15948 --- components/driver/deprecated/rmt_legacy.c | 2 +- components/esp_driver_rmt/src/rmt_rx.c | 10 ++++++++++ components/esp_driver_rmt/src/rmt_tx.c | 4 ++-- components/soc/esp32c3/include/soc/Kconfig.soc_caps.in | 2 +- components/soc/esp32c3/include/soc/soc_caps.h | 2 +- components/soc/esp32c5/include/soc/Kconfig.soc_caps.in | 2 +- components/soc/esp32c5/include/soc/soc_caps.h | 2 +- components/soc/esp32c6/include/soc/Kconfig.soc_caps.in | 2 +- components/soc/esp32c6/include/soc/soc_caps.h | 2 +- components/soc/esp32h2/include/soc/Kconfig.soc_caps.in | 2 +- components/soc/esp32h2/include/soc/soc_caps.h | 2 +- components/soc/esp32h21/include/soc/soc_caps.h | 2 +- components/soc/esp32h4/include/soc/soc_caps.h | 2 +- components/soc/esp32p4/include/soc/Kconfig.soc_caps.in | 2 +- components/soc/esp32p4/include/soc/soc_caps.h | 2 +- components/soc/esp32s2/include/soc/Kconfig.soc_caps.in | 2 +- components/soc/esp32s2/include/soc/soc_caps.h | 2 +- components/soc/esp32s3/include/soc/Kconfig.soc_caps.in | 2 +- components/soc/esp32s3/include/soc/soc_caps.h | 2 +- 19 files changed, 29 insertions(+), 19 deletions(-) diff --git a/components/driver/deprecated/rmt_legacy.c b/components/driver/deprecated/rmt_legacy.c index 254aa46c06..ff9ea4fbee 100644 --- a/components/driver/deprecated/rmt_legacy.c +++ b/components/driver/deprecated/rmt_legacy.c @@ -302,7 +302,7 @@ esp_err_t rmt_tx_stop(rmt_channel_t channel) { ESP_RETURN_ON_FALSE(RMT_IS_TX_CHANNEL(channel), ESP_ERR_INVALID_ARG, TAG, RMT_CHANNEL_ERROR_STR); RMT_ENTER_CRITICAL(); -#if SOC_RMT_SUPPORT_TX_ASYNC_STOP +#if SOC_RMT_SUPPORT_ASYNC_STOP rmt_ll_tx_stop(rmt_contex.hal.regs, channel); #else // write ending marker to stop the TX channel diff --git a/components/esp_driver_rmt/src/rmt_rx.c b/components/esp_driver_rmt/src/rmt_rx.c index 2b1b88bb68..5ccb22f1e5 100644 --- a/components/esp_driver_rmt/src/rmt_rx.c +++ b/components/esp_driver_rmt/src/rmt_rx.c @@ -586,6 +586,16 @@ bool rmt_isr_handle_rx_done(rmt_rx_channel_t *rx_chan) rmt_ll_rx_enable(hal->regs, channel_id, false); portEXIT_CRITICAL_ISR(&channel->spinlock); +#if !SOC_RMT_SUPPORT_ASYNC_STOP + // This is a workaround for ESP32. + // The RX engine can not be disabled once it is enabled in ESP32 + // If the state isn't RMT_FSM_RUN, it means the RX engine was disabled + // and we shouldn't process the data. + if (atomic_load(&channel->fsm) != RMT_FSM_RUN) { + return false; + } +#endif + uint32_t offset = rmt_ll_rx_get_memory_writer_offset(hal->regs, channel_id); // Start from C6, the actual pulse count is the number of input pulses N - 1. diff --git a/components/esp_driver_rmt/src/rmt_tx.c b/components/esp_driver_rmt/src/rmt_tx.c index 79bd447cda..bf0972ae5e 100644 --- a/components/esp_driver_rmt/src/rmt_tx.c +++ b/components/esp_driver_rmt/src/rmt_tx.c @@ -823,14 +823,14 @@ static esp_err_t rmt_tx_disable(rmt_channel_handle_t channel) // disable the hardware portENTER_CRITICAL(&channel->spinlock); rmt_ll_tx_enable_loop(hal->regs, channel->channel_id, false); -#if SOC_RMT_SUPPORT_TX_ASYNC_STOP +#if SOC_RMT_SUPPORT_ASYNC_STOP rmt_ll_tx_stop(hal->regs, channel->channel_id); #endif portEXIT_CRITICAL(&channel->spinlock); portENTER_CRITICAL(&group->spinlock); rmt_ll_enable_interrupt(hal->regs, RMT_LL_EVENT_TX_MASK(channel_id), false); -#if !SOC_RMT_SUPPORT_TX_ASYNC_STOP +#if !SOC_RMT_SUPPORT_ASYNC_STOP // we do a trick to stop the undergoing transmission // stop interrupt, insert EOF marker to the RMT memory, polling the trans_done event channel->hw_mem_base[0].val = 0; diff --git a/components/soc/esp32c3/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c3/include/soc/Kconfig.soc_caps.in index afaa031a1c..ac62851a2e 100644 --- a/components/soc/esp32c3/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c3/include/soc/Kconfig.soc_caps.in @@ -619,7 +619,7 @@ config SOC_RMT_SUPPORT_RX_DEMODULATION bool default y -config SOC_RMT_SUPPORT_TX_ASYNC_STOP +config SOC_RMT_SUPPORT_ASYNC_STOP bool default y diff --git a/components/soc/esp32c3/include/soc/soc_caps.h b/components/soc/esp32c3/include/soc/soc_caps.h index 9c0b52212c..61cb2b8a50 100644 --- a/components/soc/esp32c3/include/soc/soc_caps.h +++ b/components/soc/esp32c3/include/soc/soc_caps.h @@ -252,7 +252,7 @@ #define SOC_RMT_MEM_WORDS_PER_CHANNEL 48 /*!< Each channel owns 48 words memory (1 word = 4 Bytes) */ #define SOC_RMT_SUPPORT_RX_PINGPONG 1 /*!< Support Ping-Pong mode on RX path */ #define SOC_RMT_SUPPORT_RX_DEMODULATION 1 /*!< Support signal demodulation on RX path (i.e. remove carrier) */ -#define SOC_RMT_SUPPORT_TX_ASYNC_STOP 1 /*!< Support stop transmission asynchronously */ +#define SOC_RMT_SUPPORT_ASYNC_STOP 1 /*!< Support stop transmission asynchronously */ #define SOC_RMT_SUPPORT_TX_LOOP_COUNT 1 /*!< Support transmit specified number of cycles in loop mode */ #define SOC_RMT_SUPPORT_TX_SYNCHRO 1 /*!< Support coordinate a group of TX channels to start simultaneously */ #define SOC_RMT_SUPPORT_TX_CARRIER_DATA_ONLY 1 /*!< TX carrier can be modulated to data phase only */ diff --git a/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in index 87e8b89461..6e99e3391c 100644 --- a/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in @@ -891,7 +891,7 @@ config SOC_RMT_SUPPORT_RX_DEMODULATION bool default y -config SOC_RMT_SUPPORT_TX_ASYNC_STOP +config SOC_RMT_SUPPORT_ASYNC_STOP bool default y diff --git a/components/soc/esp32c5/include/soc/soc_caps.h b/components/soc/esp32c5/include/soc/soc_caps.h index a90bcfb192..8daccdfbe8 100644 --- a/components/soc/esp32c5/include/soc/soc_caps.h +++ b/components/soc/esp32c5/include/soc/soc_caps.h @@ -350,7 +350,7 @@ #define SOC_RMT_MEM_WORDS_PER_CHANNEL 48 /*!< Each channel owns 48 words memory (1 word = 4 Bytes) */ #define SOC_RMT_SUPPORT_RX_PINGPONG 1 /*!< Support Ping-Pong mode on RX path */ #define SOC_RMT_SUPPORT_RX_DEMODULATION 1 /*!< Support signal demodulation on RX path (i.e. remove carrier) */ -#define SOC_RMT_SUPPORT_TX_ASYNC_STOP 1 /*!< Support stop transmission asynchronously */ +#define SOC_RMT_SUPPORT_ASYNC_STOP 1 /*!< Support stop transmission asynchronously */ #define SOC_RMT_SUPPORT_TX_LOOP_COUNT 1 /*!< Support transmit specified number of cycles in loop mode */ #define SOC_RMT_SUPPORT_TX_LOOP_AUTO_STOP 1 /*!< Hardware support of auto-stop in loop mode */ #define SOC_RMT_SUPPORT_TX_SYNCHRO 1 /*!< Support coordinate a group of TX channels to start simultaneously */ diff --git a/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in index c79c672f9e..83cd9d82c5 100644 --- a/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in @@ -835,7 +835,7 @@ config SOC_RMT_SUPPORT_RX_DEMODULATION bool default y -config SOC_RMT_SUPPORT_TX_ASYNC_STOP +config SOC_RMT_SUPPORT_ASYNC_STOP bool default y diff --git a/components/soc/esp32c6/include/soc/soc_caps.h b/components/soc/esp32c6/include/soc/soc_caps.h index 34746417ea..78c91b2e47 100644 --- a/components/soc/esp32c6/include/soc/soc_caps.h +++ b/components/soc/esp32c6/include/soc/soc_caps.h @@ -324,7 +324,7 @@ #define SOC_RMT_MEM_WORDS_PER_CHANNEL 48 /*!< Each channel owns 48 words memory (1 word = 4 Bytes) */ #define SOC_RMT_SUPPORT_RX_PINGPONG 1 /*!< Support Ping-Pong mode on RX path */ #define SOC_RMT_SUPPORT_RX_DEMODULATION 1 /*!< Support signal demodulation on RX path (i.e. remove carrier) */ -#define SOC_RMT_SUPPORT_TX_ASYNC_STOP 1 /*!< Support stop transmission asynchronously */ +#define SOC_RMT_SUPPORT_ASYNC_STOP 1 /*!< Support stop transmission asynchronously */ #define SOC_RMT_SUPPORT_TX_LOOP_COUNT 1 /*!< Support transmit specified number of cycles in loop mode */ #define SOC_RMT_SUPPORT_TX_LOOP_AUTO_STOP 1 /*!< Hardware support of auto-stop in loop mode */ #define SOC_RMT_SUPPORT_TX_SYNCHRO 1 /*!< Support coordinate a group of TX channels to start simultaneously */ diff --git a/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in b/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in index f300b9514f..5fcbbf2126 100644 --- a/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in @@ -831,7 +831,7 @@ config SOC_RMT_SUPPORT_RX_DEMODULATION bool default y -config SOC_RMT_SUPPORT_TX_ASYNC_STOP +config SOC_RMT_SUPPORT_ASYNC_STOP bool default y diff --git a/components/soc/esp32h2/include/soc/soc_caps.h b/components/soc/esp32h2/include/soc/soc_caps.h index a101230a2c..b874973442 100644 --- a/components/soc/esp32h2/include/soc/soc_caps.h +++ b/components/soc/esp32h2/include/soc/soc_caps.h @@ -338,7 +338,7 @@ #define SOC_RMT_MEM_WORDS_PER_CHANNEL 48 /*!< Each channel owns 48 words memory (1 word = 4 Bytes) */ #define SOC_RMT_SUPPORT_RX_PINGPONG 1 /*!< Support Ping-Pong mode on RX path */ #define SOC_RMT_SUPPORT_RX_DEMODULATION 1 /*!< Support signal demodulation on RX path (i.e. remove carrier) */ -#define SOC_RMT_SUPPORT_TX_ASYNC_STOP 1 /*!< Support stop transmission asynchronously */ +#define SOC_RMT_SUPPORT_ASYNC_STOP 1 /*!< Support stop transmission asynchronously */ #define SOC_RMT_SUPPORT_TX_LOOP_COUNT 1 /*!< Support transmit specified number of cycles in loop mode */ #define SOC_RMT_SUPPORT_TX_LOOP_AUTO_STOP 1 /*!< Hardware support of auto-stop in loop mode */ #define SOC_RMT_SUPPORT_TX_SYNCHRO 1 /*!< Support coordinate a group of TX channels to start simultaneously */ diff --git a/components/soc/esp32h21/include/soc/soc_caps.h b/components/soc/esp32h21/include/soc/soc_caps.h index 1081cb9efc..b3155843e6 100644 --- a/components/soc/esp32h21/include/soc/soc_caps.h +++ b/components/soc/esp32h21/include/soc/soc_caps.h @@ -311,7 +311,7 @@ // #define SOC_RMT_MEM_WORDS_PER_CHANNEL 48 /*!< Each channel owns 48 words memory (1 word = 4 Bytes) */ // #define SOC_RMT_SUPPORT_RX_PINGPONG 1 /*!< Support Ping-Pong mode on RX path */ // #define SOC_RMT_SUPPORT_RX_DEMODULATION 1 /*!< Support signal demodulation on RX path (i.e. remove carrier) */ -// #define SOC_RMT_SUPPORT_TX_ASYNC_STOP 1 /*!< Support stop transmission asynchronously */ +// #define SOC_RMT_SUPPORT_ASYNC_STOP 1 /*!< Support stop transmission asynchronously */ // #define SOC_RMT_SUPPORT_TX_LOOP_COUNT 1 /*!< Support transmit specified number of cycles in loop mode */ // #define SOC_RMT_SUPPORT_TX_LOOP_AUTO_STOP 1 /*!< Hardware support of auto-stop in loop mode */ // #define SOC_RMT_SUPPORT_TX_SYNCHRO 1 /*!< Support coordinate a group of TX channels to start simultaneously */ diff --git a/components/soc/esp32h4/include/soc/soc_caps.h b/components/soc/esp32h4/include/soc/soc_caps.h index af14c42aaa..9166123814 100644 --- a/components/soc/esp32h4/include/soc/soc_caps.h +++ b/components/soc/esp32h4/include/soc/soc_caps.h @@ -317,7 +317,7 @@ // #define SOC_RMT_MEM_WORDS_PER_CHANNEL 48 /*!< Each channel owns 48 words memory (1 word = 4 Bytes) */ // #define SOC_RMT_SUPPORT_RX_PINGPONG 1 /*!< Support Ping-Pong mode on RX path */ // #define SOC_RMT_SUPPORT_RX_DEMODULATION 1 /*!< Support signal demodulation on RX path (i.e. remove carrier) */ -// #define SOC_RMT_SUPPORT_TX_ASYNC_STOP 1 /*!< Support stop transmission asynchronously */ +// #define SOC_RMT_SUPPORT_ASYNC_STOP 1 /*!< Support stop transmission asynchronously */ // #define SOC_RMT_SUPPORT_TX_LOOP_COUNT 1 /*!< Support transmit specified number of cycles in loop mode */ // #define SOC_RMT_SUPPORT_TX_LOOP_AUTO_STOP 1 /*!< Hardware support of auto-stop in loop mode */ // #define SOC_RMT_SUPPORT_TX_SYNCHRO 1 /*!< Support coordinate a group of TX channels to start simultaneously */ diff --git a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in index 122f4e8d73..e3ae810b7b 100644 --- a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in @@ -1207,7 +1207,7 @@ config SOC_RMT_SUPPORT_RX_DEMODULATION bool default y -config SOC_RMT_SUPPORT_TX_ASYNC_STOP +config SOC_RMT_SUPPORT_ASYNC_STOP bool default y diff --git a/components/soc/esp32p4/include/soc/soc_caps.h b/components/soc/esp32p4/include/soc/soc_caps.h index d98d7b7765..72a13de051 100644 --- a/components/soc/esp32p4/include/soc/soc_caps.h +++ b/components/soc/esp32p4/include/soc/soc_caps.h @@ -432,7 +432,7 @@ #define SOC_RMT_MEM_WORDS_PER_CHANNEL 48 /*!< Each channel owns 48 words memory (1 word = 4 Bytes) */ #define SOC_RMT_SUPPORT_RX_PINGPONG 1 /*!< Support Ping-Pong mode on RX path */ #define SOC_RMT_SUPPORT_RX_DEMODULATION 1 /*!< Support signal demodulation on RX path (i.e. remove carrier) */ -#define SOC_RMT_SUPPORT_TX_ASYNC_STOP 1 /*!< Support stop transmission asynchronously */ +#define SOC_RMT_SUPPORT_ASYNC_STOP 1 /*!< Support stop transmission asynchronously */ #define SOC_RMT_SUPPORT_TX_LOOP_COUNT 1 /*!< Support transmit specified number of cycles in loop mode */ #define SOC_RMT_SUPPORT_TX_LOOP_AUTO_STOP 1 /*!< Hardware support of auto-stop in loop mode */ #define SOC_RMT_SUPPORT_TX_SYNCHRO 1 /*!< Support coordinate a group of TX channels to start simultaneously */ diff --git a/components/soc/esp32s2/include/soc/Kconfig.soc_caps.in b/components/soc/esp32s2/include/soc/Kconfig.soc_caps.in index 58e4996e97..5b1219fa79 100644 --- a/components/soc/esp32s2/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32s2/include/soc/Kconfig.soc_caps.in @@ -623,7 +623,7 @@ config SOC_RMT_SUPPORT_RX_DEMODULATION bool default y -config SOC_RMT_SUPPORT_TX_ASYNC_STOP +config SOC_RMT_SUPPORT_ASYNC_STOP bool default y diff --git a/components/soc/esp32s2/include/soc/soc_caps.h b/components/soc/esp32s2/include/soc/soc_caps.h index edb1119c19..8cc946cda9 100644 --- a/components/soc/esp32s2/include/soc/soc_caps.h +++ b/components/soc/esp32s2/include/soc/soc_caps.h @@ -264,7 +264,7 @@ #define SOC_RMT_CHANNELS_PER_GROUP 4 /*!< Total 4 channels */ #define SOC_RMT_MEM_WORDS_PER_CHANNEL 64 /*!< Each channel owns 64 words memory (1 word = 4 Bytes) */ #define SOC_RMT_SUPPORT_RX_DEMODULATION 1 /*!< Support signal demodulation on RX path (i.e. remove carrier) */ -#define SOC_RMT_SUPPORT_TX_ASYNC_STOP 1 /*!< Support stop transmission asynchronously */ +#define SOC_RMT_SUPPORT_ASYNC_STOP 1 /*!< Support stop transmission asynchronously */ #define SOC_RMT_SUPPORT_TX_LOOP_COUNT 1 /*!< Support transmitting specified number of cycles in loop mode */ #define SOC_RMT_SUPPORT_TX_SYNCHRO 1 /*!< Support coordinate a group of TX channels to start simultaneously */ #define SOC_RMT_SUPPORT_TX_CARRIER_DATA_ONLY 1 /*!< TX carrier can be modulated to data phase only */ diff --git a/components/soc/esp32s3/include/soc/Kconfig.soc_caps.in b/components/soc/esp32s3/include/soc/Kconfig.soc_caps.in index 77bd0bf783..697cb9fd6f 100644 --- a/components/soc/esp32s3/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32s3/include/soc/Kconfig.soc_caps.in @@ -747,7 +747,7 @@ config SOC_RMT_SUPPORT_RX_DEMODULATION bool default y -config SOC_RMT_SUPPORT_TX_ASYNC_STOP +config SOC_RMT_SUPPORT_ASYNC_STOP bool default y diff --git a/components/soc/esp32s3/include/soc/soc_caps.h b/components/soc/esp32s3/include/soc/soc_caps.h index b5b3170296..26e89ba34c 100644 --- a/components/soc/esp32s3/include/soc/soc_caps.h +++ b/components/soc/esp32s3/include/soc/soc_caps.h @@ -288,7 +288,7 @@ #define SOC_RMT_MEM_WORDS_PER_CHANNEL 48 /*!< Each channel owns 48 words memory (1 word = 4 Bytes) */ #define SOC_RMT_SUPPORT_RX_PINGPONG 1 /*!< Support Ping-Pong mode on RX path */ #define SOC_RMT_SUPPORT_RX_DEMODULATION 1 /*!< Support signal demodulation on RX path (i.e. remove carrier) */ -#define SOC_RMT_SUPPORT_TX_ASYNC_STOP 1 /*!< Support stop transmission asynchronously */ +#define SOC_RMT_SUPPORT_ASYNC_STOP 1 /*!< Support stop transmission asynchronously */ #define SOC_RMT_SUPPORT_TX_LOOP_COUNT 1 /*!< Support transmit specified number of cycles in loop mode */ #define SOC_RMT_SUPPORT_TX_LOOP_AUTO_STOP 1 /*!< Hardware support of auto-stop in loop mode */ #define SOC_RMT_SUPPORT_TX_SYNCHRO 1 /*!< Support coordinate a group of TX channels to start simultaneously */ From 733d68532e85ca826b5046fff0f474b5997d7e2c Mon Sep 17 00:00:00 2001 From: Chen Jichang Date: Thu, 12 Jun 2025 18:18:30 +0800 Subject: [PATCH 2/2] feat(rmt): allow to set init level before any tx transmission Closes https://github.com/espressif/esp-idf/issues/16068 --- components/esp_driver_rmt/include/driver/rmt_tx.h | 1 + components/esp_driver_rmt/src/rmt_tx.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/components/esp_driver_rmt/include/driver/rmt_tx.h b/components/esp_driver_rmt/include/driver/rmt_tx.h index aae80b7567..70269f57e4 100644 --- a/components/esp_driver_rmt/include/driver/rmt_tx.h +++ b/components/esp_driver_rmt/include/driver/rmt_tx.h @@ -46,6 +46,7 @@ typedef struct { uint32_t io_od_mode: 1; /*!< Configure the GPIO as open-drain mode */ uint32_t allow_pd: 1; /*!< If set, driver allows the power domain to be powered off when system enters sleep mode. This can save power, but at the expense of more RAM being consumed to save register context. */ + uint32_t init_level: 1; /*!< Set the initial level of the RMT channel signal */ } flags; /*!< TX channel config flags */ } rmt_tx_channel_config_t; diff --git a/components/esp_driver_rmt/src/rmt_tx.c b/components/esp_driver_rmt/src/rmt_tx.c index bf0972ae5e..c0e762b932 100644 --- a/components/esp_driver_rmt/src/rmt_tx.c +++ b/components/esp_driver_rmt/src/rmt_tx.c @@ -329,7 +329,7 @@ esp_err_t rmt_new_tx_channel(const rmt_tx_channel_config_t *config, rmt_channel_ // disable carrier modulation by default, can re-enable by `rmt_apply_carrier()` rmt_ll_tx_enable_carrier_modulation(hal->regs, channel_id, false); // idle level is determined by register value - rmt_ll_tx_fix_idle_level(hal->regs, channel_id, 0, true); + rmt_ll_tx_fix_idle_level(hal->regs, channel_id, config->flags.init_level, true); // always enable tx wrap, both DMA mode and ping-pong mode rely this feature rmt_ll_tx_enable_wrap(hal->regs, channel_id, true);