From ccf13b973200d04928a135ea8c51f6ef905e4867 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/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 +- 17 files changed, 27 insertions(+), 17 deletions(-) diff --git a/components/driver/deprecated/rmt_legacy.c b/components/driver/deprecated/rmt_legacy.c index baff30aa46..06e28c7cbc 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 ed8e1095b6..32aa19b67e 100644 --- a/components/esp_driver_rmt/src/rmt_rx.c +++ b/components/esp_driver_rmt/src/rmt_rx.c @@ -599,6 +599,16 @@ static bool IRAM_ATTR 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 4017aea8ce..8d3d4f23f7 100644 --- a/components/esp_driver_rmt/src/rmt_tx.c +++ b/components/esp_driver_rmt/src/rmt_tx.c @@ -828,14 +828,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 abf437ea8c..ed6eddaa41 100644 --- a/components/soc/esp32c3/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c3/include/soc/Kconfig.soc_caps.in @@ -603,7 +603,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 772507205d..6d9ab27ecd 100644 --- a/components/soc/esp32c3/include/soc/soc_caps.h +++ b/components/soc/esp32c3/include/soc/soc_caps.h @@ -248,7 +248,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 bade9f21f5..14c0d1024a 100644 --- a/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in @@ -815,7 +815,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 a125cdb54b..da10448871 100644 --- a/components/soc/esp32c5/include/soc/soc_caps.h +++ b/components/soc/esp32c5/include/soc/soc_caps.h @@ -336,7 +336,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 0f97f4c32f..31dcb5543b 100644 --- a/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in @@ -819,7 +819,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 7358793892..5e1affd293 100644 --- a/components/soc/esp32c6/include/soc/soc_caps.h +++ b/components/soc/esp32c6/include/soc/soc_caps.h @@ -320,7 +320,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 5e8cb0e51f..2b53dc600a 100644 --- a/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in @@ -811,7 +811,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 8148712fc2..39a62a1afe 100644 --- a/components/soc/esp32h2/include/soc/soc_caps.h +++ b/components/soc/esp32h2/include/soc/soc_caps.h @@ -333,7 +333,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 7d7e81d6d2..99ea912b67 100644 --- a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in @@ -1183,7 +1183,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 13262136c5..154edce0e5 100644 --- a/components/soc/esp32p4/include/soc/soc_caps.h +++ b/components/soc/esp32p4/include/soc/soc_caps.h @@ -426,7 +426,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 a1cfe60af7..b23b5fc831 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 862157aabb..f8b90d978d 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 88f3c3217c..291154d32f 100644 --- a/components/soc/esp32s3/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32s3/include/soc/Kconfig.soc_caps.in @@ -731,7 +731,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 1490160f22..8396b85e2a 100644 --- a/components/soc/esp32s3/include/soc/soc_caps.h +++ b/components/soc/esp32s3/include/soc/soc_caps.h @@ -280,7 +280,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 6a17241f1f26ff5c5999c219532ef023f17e9c26 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 cd6c6661bd..7dca3962d5 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 8d3d4f23f7..782d8fed6d 100644 --- a/components/esp_driver_rmt/src/rmt_tx.c +++ b/components/esp_driver_rmt/src/rmt_tx.c @@ -344,7 +344,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);