diff --git a/components/esp_driver_rmt/src/rmt_rx.c b/components/esp_driver_rmt/src/rmt_rx.c index 6c435c9748..c13af21741 100644 --- a/components/esp_driver_rmt/src/rmt_rx.c +++ b/components/esp_driver_rmt/src/rmt_rx.c @@ -605,9 +605,20 @@ static bool IRAM_ATTR rmt_isr_handle_rx_done(rmt_rx_channel_t *rx_chan) portEXIT_CRITICAL_ISR(&channel->spinlock); uint32_t offset = rmt_ll_rx_get_memory_writer_offset(hal->regs, channel_id); - // sanity check - assert(offset >= rx_chan->mem_off); - size_t mem_want = (offset - rx_chan->mem_off) * sizeof(rmt_symbol_word_t); + + // Start from C6, the actual pulse count is the number of input pulses N - 1. + // Resulting in the last threshold interrupts may not be triggered correctly when the number of received symbols is a multiple of the memory block size. + // As shown in the figure below, So we special handle the offset + + // mem_off (should be updated here in the last threshold interrupt, but interrupt lost) + // | + // V + // |________|________| + // | | + // offset mem_off(actually here now) + + size_t mem_want = (offset >= rx_chan->mem_off ? offset - rx_chan->mem_off : rx_chan->mem_off - offset); + mem_want *= sizeof(rmt_symbol_word_t); size_t mem_have = trans_desc->buffer_size - trans_desc->copy_dest_off; size_t copy_size = mem_want; if (mem_want > mem_have) { diff --git a/components/esp_driver_rmt/test_apps/rmt/main/test_rmt_rx.c b/components/esp_driver_rmt/test_apps/rmt/main/test_rmt_rx.c index 108dbe8251..a86b459148 100644 --- a/components/esp_driver_rmt/test_apps/rmt/main/test_rmt_rx.c +++ b/components/esp_driver_rmt/test_apps/rmt/main/test_rmt_rx.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -208,9 +208,9 @@ TEST_CASE("rmt rx nec with carrier", "[rmt]") #if SOC_RMT_SUPPORT_RX_PINGPONG #define TEST_RMT_SYMBOLS 10000 // a very long frame, contains 10000 symbols -static void pwm_bit_bang(int gpio_num) +static void pwm_bit_bang(int gpio_num, int count) { - for (int i = 0; i < TEST_RMT_SYMBOLS; i++) { + for (int i = 0; i < count; i++) { gpio_set_level(gpio_num, 1); esp_rom_delay_us(50); gpio_set_level(gpio_num, 0); @@ -231,7 +231,7 @@ static bool test_rmt_partial_receive_done(rmt_channel_handle_t channel, const rm return high_task_wakeup == pdTRUE; } -static void test_rmt_partial_receive(size_t mem_block_symbols, bool with_dma, rmt_clock_source_t clk_src) +static void test_rmt_partial_receive(size_t mem_block_symbols, int test_symbols_num, bool with_dma, rmt_clock_source_t clk_src) { uint32_t const test_rx_buffer_symbols = 128; // the user buffer is small, it can't hold all the received symbols rmt_symbol_word_t *receive_user_buf = heap_caps_aligned_calloc(64, test_rx_buffer_symbols, sizeof(rmt_symbol_word_t), @@ -280,11 +280,11 @@ static void test_rmt_partial_receive(size_t mem_block_symbols, bool with_dma, rm TEST_ESP_OK(rmt_receive(rx_channel, receive_user_buf, test_rx_buffer_symbols * sizeof(rmt_symbol_word_t), &rx_config)); // simulate input signal by GPIO - pwm_bit_bang(TEST_RMT_GPIO_NUM_A); + pwm_bit_bang(TEST_RMT_GPIO_NUM_A, test_symbols_num); TEST_ASSERT_NOT_EQUAL(0, ulTaskNotifyTake(pdFALSE, pdMS_TO_TICKS(2000))); printf("received %zu symbols\r\n", test_user_data.received_symbol_num); - TEST_ASSERT_EQUAL(TEST_RMT_SYMBOLS, test_user_data.received_symbol_num); + TEST_ASSERT_EQUAL(test_symbols_num, test_user_data.received_symbol_num); // verify the received data for (int i = 0; i < 10; i++) { printf("{%d:%d},{%d:%d}\r\n", receive_user_buf[i].level0, receive_user_buf[i].duration0, receive_user_buf[i].level1, receive_user_buf[i].duration1); @@ -303,11 +303,19 @@ static void test_rmt_partial_receive(size_t mem_block_symbols, bool with_dma, rm TEST_CASE("rmt rx long frame partially", "[rmt]") { - test_rmt_partial_receive(SOC_RMT_MEM_WORDS_PER_CHANNEL, false, RMT_CLK_SRC_DEFAULT); + test_rmt_partial_receive(SOC_RMT_MEM_WORDS_PER_CHANNEL, TEST_RMT_SYMBOLS, false, RMT_CLK_SRC_DEFAULT); #if SOC_RMT_SUPPORT_DMA - test_rmt_partial_receive(256, true, RMT_CLK_SRC_DEFAULT); + test_rmt_partial_receive(256, TEST_RMT_SYMBOLS, true, RMT_CLK_SRC_DEFAULT); #endif } + +TEST_CASE("rmt rx boundary conditions", "[rmt]") +{ + test_rmt_partial_receive(SOC_RMT_MEM_WORDS_PER_CHANNEL, SOC_RMT_MEM_WORDS_PER_CHANNEL - 1, false, RMT_CLK_SRC_DEFAULT); + test_rmt_partial_receive(SOC_RMT_MEM_WORDS_PER_CHANNEL, SOC_RMT_MEM_WORDS_PER_CHANNEL, false, RMT_CLK_SRC_DEFAULT); + test_rmt_partial_receive(SOC_RMT_MEM_WORDS_PER_CHANNEL, SOC_RMT_MEM_WORDS_PER_CHANNEL + 1, false, RMT_CLK_SRC_DEFAULT); +} + #endif // SOC_RMT_SUPPORT_RX_PINGPONG TEST_RMT_CALLBACK_ATTR