Merge branch 'fix/fix_rmt_loop_tx_trigger_done_event_v5.2' into 'release/v5.2'

fix(rmt): clear stale TX done status before new transaction (v5.2)

See merge request espressif/esp-idf!51657
This commit is contained in:
morris
2026-08-26 18:51:54 +08:00
2 changed files with 98 additions and 4 deletions

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -681,11 +681,13 @@ static void IRAM_ATTR rmt_tx_do_transaction(rmt_tx_channel_t *tx_chan, rmt_tx_tr
// don't enable threshold interrupt with loop mode on
// threshold interrupt will be disabled in `rmt_encode_eof()`
rmt_ll_enable_interrupt(hal->regs, RMT_LL_EVENT_TX_THRES(channel_id), t->loop_count == 0);
// Threshold interrupt will be generated by accident, clear it before starting new transmission
rmt_ll_clear_interrupt_status(hal->regs, RMT_LL_EVENT_TX_THRES(channel_id));
}
// don't generate trans done event for loop transmission
rmt_ll_enable_interrupt(hal->regs, RMT_LL_EVENT_TX_DONE(channel_id), t->loop_count == 0);
// Clear stale TX events before the engine starts.
// Some targets can keep TX_DONE pending after a loop transaction.
// And Threshold interrupt may be generated by accident
rmt_ll_clear_interrupt_status(hal->regs, RMT_LL_EVENT_TX_MASK(channel_id));
portEXIT_CRITICAL_SAFE(&group->spinlock);
// at the beginning of a new transaction, encoding memory offset should start from zero.
@@ -869,6 +871,8 @@ static bool IRAM_ATTR rmt_isr_handle_tx_threshold(rmt_tx_channel_t *tx_chan)
{
// continue ping-pong transmission
rmt_tx_trans_desc_t *t = tx_chan->cur_trans;
// sanity check
assert(t);
size_t encoded_symbols = t->transmitted_symbol_num;
// encoding finished, only need to send the EOF symbol
if (t->flags.encoding_done) {

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -359,6 +359,96 @@ TEST_CASE("rmt finite loop transaction", "[rmt]")
#endif
}
typedef struct {
uint32_t expected_symbols[3];
uint32_t done_count;
} test_rmt_sequential_loop_context_t;
TEST_RMT_CALLBACK_ATTR
static bool test_rmt_sequential_loop_done_cb(rmt_channel_handle_t channel, const rmt_tx_done_event_data_t *edata, void *user_data)
{
test_rmt_sequential_loop_context_t *ctx = (test_rmt_sequential_loop_context_t *)user_data;
TEST_ASSERT_LESS_THAN(3, ctx->done_count);
esp_rom_printf("test_rmt_sequential_loop_done_cb: done_count = %d, expected_symbols = %d, num_symbols = %d\r\n", ctx->done_count, ctx->expected_symbols[ctx->done_count], edata->num_symbols);
TEST_ASSERT_EQUAL(ctx->expected_symbols[ctx->done_count], edata->num_symbols);
ctx->done_count++;
return false;
}
TEST_CASE("rmt loop transaction followed by ping-pong transaction", "[rmt]")
{
rmt_tx_channel_config_t tx_channel_cfg = {
.mem_block_symbols = SOC_RMT_MEM_WORDS_PER_CHANNEL * 2,
.clk_src = RMT_CLK_SRC_DEFAULT,
.resolution_hz = 1000000, // 1MHz, 1 tick = 1us
.trans_queue_depth = 4,
.gpio_num = TEST_RMT_GPIO_NUM_A,
.intr_priority = 2,
};
printf("install tx channel\r\n");
rmt_channel_handle_t tx_channel = NULL;
TEST_ESP_OK(rmt_new_tx_channel(&tx_channel_cfg, &tx_channel));
printf("install copy encoder\r\n");
rmt_encoder_handle_t copy_encoder = NULL;
rmt_copy_encoder_config_t copy_encoder_config = {};
TEST_ESP_OK(rmt_new_copy_encoder(&copy_encoder_config, &copy_encoder));
uint32_t ping_pong_symbol_num = SOC_RMT_MEM_WORDS_PER_CHANNEL * 3 + 5;
test_rmt_sequential_loop_context_t cb_ctx = {
// +1 for the eof marker
.expected_symbols = {
ping_pong_symbol_num + 1,
2,
ping_pong_symbol_num + 1,
},
};
rmt_tx_event_callbacks_t cbs = {
.on_trans_done = test_rmt_sequential_loop_done_cb,
};
TEST_ESP_OK(rmt_tx_register_event_callbacks(tx_channel, &cbs, &cb_ctx));
printf("enable tx channel\r\n");
TEST_ESP_OK(rmt_enable(tx_channel));
rmt_symbol_word_t ping_pong_symbols[ping_pong_symbol_num];
memset(ping_pong_symbols, 0, sizeof(ping_pong_symbols));
for (int i = 0; i < ping_pong_symbol_num; i++) {
ping_pong_symbols[i] = (rmt_symbol_word_t) {
.level0 = 0,
.duration0 = 5,
.level1 = 1,
.duration1 = 5,
};
}
rmt_symbol_word_t loop_symbol = {
.level0 = 0,
.duration0 = 5,
.level1 = 1,
.duration1 = 5,
};
printf("queue ping-pong, loop, ping-pong transactions\r\n");
rmt_transmit_config_t transmit_config = {
.loop_count = 0,
};
TEST_ESP_OK(rmt_transmit(tx_channel, copy_encoder, ping_pong_symbols, sizeof(ping_pong_symbols), &transmit_config));
transmit_config.loop_count = 50;
TEST_ESP_OK(rmt_transmit(tx_channel, copy_encoder, &loop_symbol, sizeof(loop_symbol), &transmit_config));
transmit_config.loop_count = 0;
TEST_ESP_OK(rmt_transmit(tx_channel, copy_encoder, ping_pong_symbols, sizeof(ping_pong_symbols), &transmit_config));
printf("wait for queued transactions done\r\n");
TEST_ESP_OK(rmt_tx_wait_all_done(tx_channel, -1));
TEST_ASSERT_EQUAL(3, cb_ctx.done_count);
printf("disable tx channel\r\n");
TEST_ESP_OK(rmt_disable(tx_channel));
printf("remove tx channel and copy encoder\r\n");
TEST_ESP_OK(rmt_del_channel(tx_channel));
TEST_ESP_OK(rmt_del_encoder(copy_encoder));
}
#endif // SOC_RMT_SUPPORT_TX_LOOP_COUNT
TEST_CASE("rmt infinite loop transaction", "[rmt]")