diff --git a/components/driver/Kconfig b/components/driver/Kconfig index 61ee6aa290..ef88b4940e 100644 --- a/components/driver/Kconfig +++ b/components/driver/Kconfig @@ -352,6 +352,15 @@ menu "Driver Configurations" Ensure the RMT interrupt is IRAM-Safe by allowing the interrupt handler to be executable when the cache is disabled (e.g. SPI Flash write). + config RMT_RECV_FUNC_IN_IRAM + bool "Place RMT receive function into IRAM" + default n + select GDMA_CTRL_FUNC_IN_IRAM if SOC_RMT_SUPPORT_DMA # RMT needs to start the GDMA in the receive function + help + Place RMT receive function into IRAM, + so that the receive function can be IRAM-safe and able to be called when the flash cache is disabled. + Enabling this option can improve driver performance as well. + config RMT_SUPPRESS_DEPRECATE_WARN bool "Suppress legacy driver deprecated warning" default n diff --git a/components/driver/linker.lf b/components/driver/linker.lf index 21ca22924f..222bb1f1f3 100644 --- a/components/driver/linker.lf +++ b/components/driver/linker.lf @@ -21,3 +21,7 @@ entries: if MCPWM_CTRL_FUNC_IN_IRAM = y: mcpwm_cmpr: mcpwm_comparator_set_compare_value (noflash) mcpwm_timer: mcpwm_timer_set_period (noflash) + if RMT_RECV_FUNC_IN_IRAM = y: + rmt_rx: rmt_receive (noflash) + if SOC_RMT_SUPPORT_DMA = y: + rmt_rx: rmt_rx_mount_dma_buffer (noflash) diff --git a/components/driver/rmt/include/driver/rmt_rx.h b/components/driver/rmt/include/driver/rmt_rx.h index 13eebcd1b0..325a755560 100644 --- a/components/driver/rmt/include/driver/rmt_rx.h +++ b/components/driver/rmt/include/driver/rmt_rx.h @@ -72,6 +72,8 @@ esp_err_t rmt_new_rx_channel(const rmt_rx_channel_config_t *config, rmt_channel_ * * @note This function is non-blocking, it initiates a new receive job and then returns. * User should check the received data from the `on_recv_done` callback that registered by `rmt_rx_register_event_callbacks()`. + * @note This function can also be called in ISR context. + * @note If you want this function to work even when the flash cache is disabled, please enable the `CONFIG_RMT_RECV_FUNC_IN_IRAM` option. * * @param[in] rx_channel RMT RX channel that created by `rmt_new_rx_channel()` * @param[in] buffer The buffer to store the received RMT symbols diff --git a/components/driver/rmt/rmt_private.h b/components/driver/rmt/rmt_private.h index 7b448d456d..6f94b0d614 100644 --- a/components/driver/rmt/rmt_private.h +++ b/components/driver/rmt/rmt_private.h @@ -27,7 +27,7 @@ extern "C" { #endif -#if CONFIG_RMT_ISR_IRAM_SAFE +#if CONFIG_RMT_ISR_IRAM_SAFE || CONFIG_RMT_RECV_FUNC_IN_IRAM #define RMT_MEM_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT) #else #define RMT_MEM_ALLOC_CAPS MALLOC_CAP_DEFAULT diff --git a/components/driver/rmt/rmt_rx.c b/components/driver/rmt/rmt_rx.c index 1564efd9e1..c5361af9de 100644 --- a/components/driver/rmt/rmt_rx.c +++ b/components/driver/rmt/rmt_rx.c @@ -342,16 +342,16 @@ esp_err_t rmt_rx_register_event_callbacks(rmt_channel_handle_t channel, const rm esp_err_t rmt_receive(rmt_channel_handle_t channel, void *buffer, size_t buffer_size, const rmt_receive_config_t *config) { - ESP_RETURN_ON_FALSE(channel && buffer && buffer_size && config, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); - ESP_RETURN_ON_FALSE(channel->direction == RMT_CHANNEL_DIRECTION_RX, ESP_ERR_INVALID_ARG, TAG, "invalid channel direction"); + ESP_RETURN_ON_FALSE_ISR(channel && buffer && buffer_size && config, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); + ESP_RETURN_ON_FALSE_ISR(channel->direction == RMT_CHANNEL_DIRECTION_RX, ESP_ERR_INVALID_ARG, TAG, "invalid channel direction"); rmt_rx_channel_t *rx_chan = __containerof(channel, rmt_rx_channel_t, base); if (channel->dma_chan) { - ESP_RETURN_ON_FALSE(esp_ptr_internal(buffer), ESP_ERR_INVALID_ARG, TAG, "buffer must locate in internal RAM for DMA use"); + ESP_RETURN_ON_FALSE_ISR(esp_ptr_internal(buffer), ESP_ERR_INVALID_ARG, TAG, "buffer must locate in internal RAM for DMA use"); } if (channel->dma_chan) { - ESP_RETURN_ON_FALSE(buffer_size <= rx_chan->num_dma_nodes * RMT_DMA_DESC_BUF_MAX_SIZE, - ESP_ERR_INVALID_ARG, TAG, "buffer size exceeds DMA capacity"); + ESP_RETURN_ON_FALSE_ISR(buffer_size <= rx_chan->num_dma_nodes * RMT_DMA_DESC_BUF_MAX_SIZE, + ESP_ERR_INVALID_ARG, TAG, "buffer size exceeds DMA capacity"); } rmt_group_t *group = channel->group; rmt_hal_context_t *hal = &group->hal; @@ -359,13 +359,13 @@ esp_err_t rmt_receive(rmt_channel_handle_t channel, void *buffer, size_t buffer_ uint32_t filter_reg_value = ((uint64_t)group->resolution_hz * config->signal_range_min_ns) / 1000000000UL; uint32_t idle_reg_value = ((uint64_t)channel->resolution_hz * config->signal_range_max_ns) / 1000000000UL; - ESP_RETURN_ON_FALSE(filter_reg_value <= RMT_LL_MAX_FILTER_VALUE, ESP_ERR_INVALID_ARG, TAG, "signal_range_min_ns too big"); - ESP_RETURN_ON_FALSE(idle_reg_value <= RMT_LL_MAX_IDLE_VALUE, ESP_ERR_INVALID_ARG, TAG, "signal_range_max_ns too big"); + ESP_RETURN_ON_FALSE_ISR(filter_reg_value <= RMT_LL_MAX_FILTER_VALUE, ESP_ERR_INVALID_ARG, TAG, "signal_range_min_ns too big"); + ESP_RETURN_ON_FALSE_ISR(idle_reg_value <= RMT_LL_MAX_IDLE_VALUE, ESP_ERR_INVALID_ARG, TAG, "signal_range_max_ns too big"); // check if we're in a proper state to start the receiver rmt_fsm_t expected_fsm = RMT_FSM_ENABLE; - ESP_RETURN_ON_FALSE(atomic_compare_exchange_strong(&channel->fsm, &expected_fsm, RMT_FSM_RUN_WAIT), - ESP_ERR_INVALID_STATE, TAG, "channel not in enable state"); + ESP_RETURN_ON_FALSE_ISR(atomic_compare_exchange_strong(&channel->fsm, &expected_fsm, RMT_FSM_RUN_WAIT), + ESP_ERR_INVALID_STATE, TAG, "channel not in enable state"); // fill in the transaction descriptor rmt_rx_trans_desc_t *t = &rx_chan->trans_desc; @@ -383,7 +383,7 @@ esp_err_t rmt_receive(rmt_channel_handle_t channel, void *buffer, size_t buffer_ } rx_chan->mem_off = 0; - portENTER_CRITICAL(&channel->spinlock); + portENTER_CRITICAL_SAFE(&channel->spinlock); // reset memory writer offset rmt_ll_rx_reset_pointer(hal->regs, channel_id); rmt_ll_rx_set_mem_owner(hal->regs, channel_id, RMT_LL_MEM_OWNER_HW); @@ -393,7 +393,7 @@ esp_err_t rmt_receive(rmt_channel_handle_t channel, void *buffer, size_t buffer_ rmt_ll_rx_set_idle_thres(hal->regs, channel_id, idle_reg_value); // turn on RMT RX machine rmt_ll_rx_enable(hal->regs, channel_id, true); - portEXIT_CRITICAL(&channel->spinlock); + portEXIT_CRITICAL_SAFE(&channel->spinlock); // saying we're in running state, this state will last until the receiving is done // i.e., we will switch back to the enable state in the receive done interrupt handler @@ -577,6 +577,9 @@ static bool IRAM_ATTR rmt_isr_handle_rx_done(rmt_rx_channel_t *rx_chan) } trans_desc->copy_dest_off += copy_size; trans_desc->received_symbol_num += copy_size / sizeof(rmt_symbol_word_t); + // switch back to the enable state, then user can call `rmt_receive` to start a new receive + atomic_store(&channel->fsm, RMT_FSM_ENABLE); + // notify the user with receive RMT symbols if (rx_chan->on_recv_done) { rmt_rx_done_event_data_t edata = { @@ -587,8 +590,6 @@ static bool IRAM_ATTR rmt_isr_handle_rx_done(rmt_rx_channel_t *rx_chan) need_yield = true; } } - // switch back to the enable state, then user can call `rmt_receive` to start a new receive - atomic_store(&channel->fsm, RMT_FSM_ENABLE); return need_yield; } @@ -683,6 +684,9 @@ static bool IRAM_ATTR rmt_dma_rx_eof_cb(gdma_channel_handle_t dma_chan, gdma_eve rmt_ll_rx_enable(hal->regs, channel_id, false); portEXIT_CRITICAL_ISR(&channel->spinlock); + // switch back to the enable state, then user can call `rmt_receive` to start a new receive + atomic_store(&channel->fsm, RMT_FSM_ENABLE); + if (rx_chan->on_recv_done) { rmt_rx_done_event_data_t edata = { .received_symbols = trans_desc->buffer, @@ -692,8 +696,7 @@ static bool IRAM_ATTR rmt_dma_rx_eof_cb(gdma_channel_handle_t dma_chan, gdma_eve need_yield = true; } } - // switch back to the enable state, then user can call `rmt_receive` to start a new receive - atomic_store(&channel->fsm, RMT_FSM_ENABLE); + return need_yield; } #endif // SOC_RMT_SUPPORT_DMA diff --git a/components/driver/test_apps/rmt/main/test_rmt_iram.c b/components/driver/test_apps/rmt/main/test_rmt_iram.c index 2efd2103ee..f5d7ad6725 100644 --- a/components/driver/test_apps/rmt/main/test_rmt_iram.c +++ b/components/driver/test_apps/rmt/main/test_rmt_iram.c @@ -90,22 +90,27 @@ TEST_CASE("rmt_tx_iram_safe_with_dma", "[rmt]") } #endif +#define TEST_RMT_SYMBOLS 2 static void IRAM_ATTR test_simulate_input_post_cache_disable(void *args) { int gpio_num = (int)args; - // simulate input signal, should only be recognized as one RMT symbol - gpio_set_level(gpio_num, 0); - esp_rom_delay_us(50); - gpio_set_level(gpio_num, 1); - esp_rom_delay_us(50); - gpio_set_level(gpio_num, 0); - esp_rom_delay_us(20000); + // simulate input signal, should only be recognized as two RMT symbols + for (int i = 0; i < TEST_RMT_SYMBOLS; i++) { + gpio_set_level(gpio_num, 0); + esp_rom_delay_us(50); + gpio_set_level(gpio_num, 1); + esp_rom_delay_us(50); + gpio_set_level(gpio_num, 0); + esp_rom_delay_us(20000); + } } typedef struct { TaskHandle_t task_to_notify; size_t received_symbol_num; + rmt_receive_config_t rx_config; + rmt_symbol_word_t remote_codes[128]; } test_nec_rx_user_data_t; IRAM_ATTR @@ -113,8 +118,15 @@ static bool test_rmt_rx_done_callback(rmt_channel_handle_t channel, const rmt_rx { BaseType_t high_task_wakeup = pdFALSE; test_nec_rx_user_data_t *test_user_data = (test_nec_rx_user_data_t *)user_data; - test_user_data->received_symbol_num = edata->num_symbols; - vTaskNotifyGiveFromISR(test_user_data->task_to_notify, &high_task_wakeup); + test_user_data->received_symbol_num += edata->num_symbols; + // should receive one RMT symbol at a time + if (edata->num_symbols == 1) { + if (test_user_data->received_symbol_num == TEST_RMT_SYMBOLS) { + vTaskNotifyGiveFromISR(test_user_data->task_to_notify, &high_task_wakeup); + } else { + rmt_receive(channel, test_user_data->remote_codes, sizeof(test_user_data->remote_codes), &test_user_data->rx_config); + } + } return high_task_wakeup == pdTRUE; } @@ -141,27 +153,25 @@ static void test_rmt_rx_iram_safe(size_t mem_block_symbols, bool with_dma, rmt_c }; test_nec_rx_user_data_t test_user_data = { .task_to_notify = xTaskGetCurrentTaskHandle(), + .received_symbol_num = 0, + .rx_config = { + .signal_range_min_ns = 1250, + .signal_range_max_ns = 12000000, + }, }; TEST_ESP_OK(rmt_rx_register_event_callbacks(rx_channel, &cbs, &test_user_data)); printf("enable rx channel\r\n"); TEST_ESP_OK(rmt_enable(rx_channel)); - rmt_symbol_word_t remote_codes[128]; - - rmt_receive_config_t receive_config = { - .signal_range_min_ns = 1250, - .signal_range_max_ns = 12000000, - }; - // ready to receive - TEST_ESP_OK(rmt_receive(rx_channel, remote_codes, sizeof(remote_codes), &receive_config)); + TEST_ESP_OK(rmt_receive(rx_channel, test_user_data.remote_codes, sizeof(test_user_data.remote_codes), &test_user_data.rx_config)); // disable the flash cache, and simulate input signal by GPIO unity_utils_run_cache_disable_stub(test_simulate_input_post_cache_disable, 0); TEST_ASSERT_NOT_EQUAL(0, ulTaskNotifyTake(pdFALSE, pdMS_TO_TICKS(1000))); - TEST_ASSERT_EQUAL(1, test_user_data.received_symbol_num); + TEST_ASSERT_EQUAL(TEST_RMT_SYMBOLS, test_user_data.received_symbol_num); printf("disable rx channels\r\n"); TEST_ESP_OK(rmt_disable(rx_channel)); diff --git a/components/driver/test_apps/rmt/sdkconfig.ci.iram_safe b/components/driver/test_apps/rmt/sdkconfig.ci.iram_safe index 4d5f62954e..45e49434e1 100644 --- a/components/driver/test_apps/rmt/sdkconfig.ci.iram_safe +++ b/components/driver/test_apps/rmt/sdkconfig.ci.iram_safe @@ -1,5 +1,6 @@ CONFIG_COMPILER_DUMP_RTL_FILES=y CONFIG_RMT_ISR_IRAM_SAFE=y +CONFIG_RMT_RECV_FUNC_IN_IRAM=y CONFIG_GPIO_CTRL_FUNC_IN_IRAM=y CONFIG_COMPILER_OPTIMIZATION_NONE=y # place non-ISR FreeRTOS functions in Flash diff --git a/components/hal/esp32/include/hal/rmt_ll.h b/components/hal/esp32/include/hal/rmt_ll.h index 68de11d8d1..d69998f38e 100644 --- a/components/hal/esp32/include/hal/rmt_ll.h +++ b/components/hal/esp32/include/hal/rmt_ll.h @@ -368,6 +368,7 @@ static inline void rmt_ll_rx_set_mem_blocks(rmt_dev_t *dev, uint32_t channel, ui * @param channel RMT RX channel number * @param thres Time length threshold */ +__attribute__((always_inline)) static inline void rmt_ll_rx_set_idle_thres(rmt_dev_t *dev, uint32_t channel, uint32_t thres) { HAL_FORCE_MODIFY_U32_REG_FIELD(dev->conf_ch[channel].conf0, idle_thres, thres); @@ -393,6 +394,7 @@ static inline void rmt_ll_rx_set_mem_owner(rmt_dev_t *dev, uint32_t channel, rmt * @param channel RMT RX chanenl number * @param enable True to enable, False to disable */ +__attribute__((always_inline)) static inline void rmt_ll_rx_enable_filter(rmt_dev_t *dev, uint32_t channel, bool enable) { dev->conf_ch[channel].conf1.rx_filter_en = enable; @@ -405,6 +407,7 @@ static inline void rmt_ll_rx_enable_filter(rmt_dev_t *dev, uint32_t channel, boo * @param channel RMT RX channel number * @param thres Filter threshold */ +__attribute__((always_inline)) static inline void rmt_ll_rx_set_filter_thres(rmt_dev_t *dev, uint32_t channel, uint32_t thres) { HAL_FORCE_MODIFY_U32_REG_FIELD(dev->conf_ch[channel].conf1, rx_filter_thres, thres); diff --git a/components/hal/esp32c3/include/hal/rmt_ll.h b/components/hal/esp32c3/include/hal/rmt_ll.h index 1c3c4c907f..970b3570d2 100644 --- a/components/hal/esp32c3/include/hal/rmt_ll.h +++ b/components/hal/esp32c3/include/hal/rmt_ll.h @@ -438,6 +438,7 @@ static inline void rmt_ll_rx_set_channel_clock_div(rmt_dev_t *dev, uint32_t chan * @param dev Peripheral instance address * @param channel RMT RX channel number */ +__attribute__((always_inline)) static inline void rmt_ll_rx_reset_pointer(rmt_dev_t *dev, uint32_t channel) { dev->rx_conf[channel].conf1.mem_wr_rst = 1; @@ -480,6 +481,7 @@ static inline void rmt_ll_rx_set_mem_blocks(rmt_dev_t *dev, uint32_t channel, ui * @param channel RMT RX channel number * @param thres Time length threshold */ +__attribute__((always_inline)) static inline void rmt_ll_rx_set_idle_thres(rmt_dev_t *dev, uint32_t channel, uint32_t thres) { dev->rx_conf[channel].conf0.idle_thres = thres; @@ -505,6 +507,7 @@ static inline void rmt_ll_rx_set_mem_owner(rmt_dev_t *dev, uint32_t channel, rmt * @param channel RMT RX chanenl number * @param enable True to enable, False to disable */ +__attribute__((always_inline)) static inline void rmt_ll_rx_enable_filter(rmt_dev_t *dev, uint32_t channel, bool enable) { dev->rx_conf[channel].conf1.rx_filter_en = enable; @@ -517,6 +520,7 @@ static inline void rmt_ll_rx_enable_filter(rmt_dev_t *dev, uint32_t channel, boo * @param channel RMT RX channel number * @param thres Filter threshold */ +__attribute__((always_inline)) static inline void rmt_ll_rx_set_filter_thres(rmt_dev_t *dev, uint32_t channel, uint32_t thres) { HAL_FORCE_MODIFY_U32_REG_FIELD(dev->rx_conf[channel].conf1, rx_filter_thres, thres); diff --git a/components/hal/esp32c6/include/hal/rmt_ll.h b/components/hal/esp32c6/include/hal/rmt_ll.h index 7f7f24f9be..06075b330f 100644 --- a/components/hal/esp32c6/include/hal/rmt_ll.h +++ b/components/hal/esp32c6/include/hal/rmt_ll.h @@ -453,6 +453,7 @@ static inline void rmt_ll_rx_set_channel_clock_div(rmt_dev_t *dev, uint32_t chan * @param dev Peripheral instance address * @param channel RMT RX channel number */ +__attribute__((always_inline)) static inline void rmt_ll_rx_reset_pointer(rmt_dev_t *dev, uint32_t channel) { dev->chmconf[channel].conf1.mem_wr_rst_chm = 1; @@ -495,6 +496,7 @@ static inline void rmt_ll_rx_set_mem_blocks(rmt_dev_t *dev, uint32_t channel, ui * @param channel RMT RX channel number * @param thres Time length threshold */ +__attribute__((always_inline)) static inline void rmt_ll_rx_set_idle_thres(rmt_dev_t *dev, uint32_t channel, uint32_t thres) { dev->chmconf[channel].conf0.idle_thres_chm = thres; @@ -520,6 +522,7 @@ static inline void rmt_ll_rx_set_mem_owner(rmt_dev_t *dev, uint32_t channel, rmt * @param channel RMT RX chanenl number * @param enable True to enable, False to disable */ +__attribute__((always_inline)) static inline void rmt_ll_rx_enable_filter(rmt_dev_t *dev, uint32_t channel, bool enable) { dev->chmconf[channel].conf1.rx_filter_en_chm = enable; @@ -532,6 +535,7 @@ static inline void rmt_ll_rx_enable_filter(rmt_dev_t *dev, uint32_t channel, boo * @param channel RMT RX channel number * @param thres Filter threshold */ +__attribute__((always_inline)) static inline void rmt_ll_rx_set_filter_thres(rmt_dev_t *dev, uint32_t channel, uint32_t thres) { HAL_FORCE_MODIFY_U32_REG_FIELD(dev->chmconf[channel].conf1, rx_filter_thres_chm, thres); diff --git a/components/hal/esp32h2/include/hal/rmt_ll.h b/components/hal/esp32h2/include/hal/rmt_ll.h index d290163f59..105825f88f 100644 --- a/components/hal/esp32h2/include/hal/rmt_ll.h +++ b/components/hal/esp32h2/include/hal/rmt_ll.h @@ -450,6 +450,7 @@ static inline void rmt_ll_rx_set_channel_clock_div(rmt_dev_t *dev, uint32_t chan * @param dev Peripheral instance address * @param channel RMT RX channel number */ +__attribute__((always_inline)) static inline void rmt_ll_rx_reset_pointer(rmt_dev_t *dev, uint32_t channel) { dev->chmconf[channel].conf1.mem_wr_rst_chm = 1; @@ -492,6 +493,7 @@ static inline void rmt_ll_rx_set_mem_blocks(rmt_dev_t *dev, uint32_t channel, ui * @param channel RMT RX channel number * @param thres Time length threshold */ +__attribute__((always_inline)) static inline void rmt_ll_rx_set_idle_thres(rmt_dev_t *dev, uint32_t channel, uint32_t thres) { dev->chmconf[channel].conf0.idle_thres_chm = thres; @@ -517,6 +519,7 @@ static inline void rmt_ll_rx_set_mem_owner(rmt_dev_t *dev, uint32_t channel, rmt * @param channel RMT RX chanenl number * @param enable True to enable, False to disable */ +__attribute__((always_inline)) static inline void rmt_ll_rx_enable_filter(rmt_dev_t *dev, uint32_t channel, bool enable) { dev->chmconf[channel].conf1.rx_filter_en_chm = enable; @@ -529,6 +532,7 @@ static inline void rmt_ll_rx_enable_filter(rmt_dev_t *dev, uint32_t channel, boo * @param channel RMT RX channel number * @param thres Filter threshold */ +__attribute__((always_inline)) static inline void rmt_ll_rx_set_filter_thres(rmt_dev_t *dev, uint32_t channel, uint32_t thres) { HAL_FORCE_MODIFY_U32_REG_FIELD(dev->chmconf[channel].conf1, rx_filter_thres_chm, thres); diff --git a/components/hal/esp32s2/include/hal/rmt_ll.h b/components/hal/esp32s2/include/hal/rmt_ll.h index fe8028802c..841648312f 100644 --- a/components/hal/esp32s2/include/hal/rmt_ll.h +++ b/components/hal/esp32s2/include/hal/rmt_ll.h @@ -88,7 +88,7 @@ static inline void rmt_ll_enable_mem_access_nonfifo(rmt_dev_t *dev, bool enable) * @param divider_numerator Numerator part of the divider */ static inline void rmt_ll_set_group_clock_src(rmt_dev_t *dev, uint32_t channel, rmt_clock_source_t src, - uint32_t divider_integral, uint32_t divider_denominator, uint32_t divider_numerator) + uint32_t divider_integral, uint32_t divider_denominator, uint32_t divider_numerator) { (void)divider_integral; (void)divider_denominator; @@ -473,6 +473,7 @@ static inline void rmt_ll_rx_set_mem_blocks(rmt_dev_t *dev, uint32_t channel, ui * @param channel RMT RX channel number * @param thres Time length threshold */ +__attribute__((always_inline)) static inline void rmt_ll_rx_set_idle_thres(rmt_dev_t *dev, uint32_t channel, uint32_t thres) { HAL_FORCE_MODIFY_U32_REG_FIELD(dev->conf_ch[channel].conf0, idle_thres_chn, thres); @@ -498,6 +499,7 @@ static inline void rmt_ll_rx_set_mem_owner(rmt_dev_t *dev, uint32_t channel, rmt * @param channel RMT RX chanenl number * @param enable True to enable, False to disable */ +__attribute__((always_inline)) static inline void rmt_ll_rx_enable_filter(rmt_dev_t *dev, uint32_t channel, bool enable) { dev->conf_ch[channel].conf1.rx_filter_en_chn = enable; @@ -510,6 +512,7 @@ static inline void rmt_ll_rx_enable_filter(rmt_dev_t *dev, uint32_t channel, boo * @param channel RMT RX channel number * @param thres Filter threshold */ +__attribute__((always_inline)) static inline void rmt_ll_rx_set_filter_thres(rmt_dev_t *dev, uint32_t channel, uint32_t thres) { HAL_FORCE_MODIFY_U32_REG_FIELD(dev->conf_ch[channel].conf1, rx_filter_thres_chn, thres); diff --git a/components/hal/esp32s3/include/hal/rmt_ll.h b/components/hal/esp32s3/include/hal/rmt_ll.h index 70812539f0..0dd673edd5 100644 --- a/components/hal/esp32s3/include/hal/rmt_ll.h +++ b/components/hal/esp32s3/include/hal/rmt_ll.h @@ -463,6 +463,7 @@ static inline void rmt_ll_rx_set_channel_clock_div(rmt_dev_t *dev, uint32_t chan * @param dev Peripheral instance address * @param channel RMT RX channel number */ +__attribute__((always_inline)) static inline void rmt_ll_rx_reset_pointer(rmt_dev_t *dev, uint32_t channel) { dev->chmconf[channel].conf1.mem_wr_rst_chm = 1; @@ -518,6 +519,7 @@ static inline void rmt_ll_rx_set_mem_blocks(rmt_dev_t *dev, uint32_t channel, ui * @param channel RMT RX channel number * @param thres Time length threshold */ +__attribute__((always_inline)) static inline void rmt_ll_rx_set_idle_thres(rmt_dev_t *dev, uint32_t channel, uint32_t thres) { dev->chmconf[channel].conf0.idle_thres_chm = thres; @@ -543,6 +545,7 @@ static inline void rmt_ll_rx_set_mem_owner(rmt_dev_t *dev, uint32_t channel, rmt * @param channel RMT RX chanenl number * @param enable True to enable, False to disable */ +__attribute__((always_inline)) static inline void rmt_ll_rx_enable_filter(rmt_dev_t *dev, uint32_t channel, bool enable) { dev->chmconf[channel].conf1.rx_filter_en_chm = enable; @@ -555,6 +558,7 @@ static inline void rmt_ll_rx_enable_filter(rmt_dev_t *dev, uint32_t channel, boo * @param channel RMT RX channel number * @param thres Filter threshold */ +__attribute__((always_inline)) static inline void rmt_ll_rx_set_filter_thres(rmt_dev_t *dev, uint32_t channel, uint32_t thres) { HAL_FORCE_MODIFY_U32_REG_FIELD(dev->chmconf[channel].conf1, rx_filter_thres_chm, thres); diff --git a/docs/en/api-reference/peripherals/rmt.rst b/docs/en/api-reference/peripherals/rmt.rst index f1585ecf11..a3b8664570 100644 --- a/docs/en/api-reference/peripherals/rmt.rst +++ b/docs/en/api-reference/peripherals/rmt.rst @@ -550,7 +550,9 @@ There is a Kconfig option :ref:`CONFIG_RMT_ISR_IRAM_SAFE` that has the following 2. Place all functions used by the ISR into IRAM [2]_ 3. Place the driver object into DRAM in case it is mapped to PSRAM by accident -This Kconfig option allows the interrupt to run while the cache is disabled but comes at the cost of increased IRAM consumption. +This Kconfig option allows the interrupt handler to run while the cache is disabled but comes at the cost of increased IRAM consumption. + +Another Kconfig option :ref:`CONFIG_RMT_RECV_FUNC_IN_IRAM` can place :cpp:func:`rmt_receive` into the IRAM as well. So that the receive function can be used even when the flash cache is disabled. .. _rmt-thread-safety: @@ -560,6 +562,10 @@ Thread Safety The factory function :cpp:func:`rmt_new_tx_channel`, :cpp:func:`rmt_new_rx_channel` and :cpp:func:`rmt_new_sync_manager` are guaranteed to be thread-safe by the driver, which means, user can call them from different RTOS tasks without protection by extra locks. Other functions that take the :cpp:type:`rmt_channel_handle_t` and :cpp:type:`rmt_sync_manager_handle_t` as the first positional parameter, are not thread-safe. which means the user should avoid calling them from multiple tasks. +The following functions are allowed to use under ISR context as well. + +- :cpp:func:`rmt_receive` + .. _rmt-kconfig-options: Kconfig Options @@ -567,6 +573,7 @@ Kconfig Options - :ref:`CONFIG_RMT_ISR_IRAM_SAFE` controls whether the default ISR handler can work when cache is disabled, see also :ref:`rmt-iram-safe` for more information. - :ref:`CONFIG_RMT_ENABLE_DEBUG_LOG` is used to enable the debug log at the cost of increased firmware binary size. +- :ref:`CONFIG_RMT_RECV_FUNC_IN_IRAM` controls where to place the RMT receive function (IRAM or Flash), see :ref:`rmt-iram-safe` for more information. Application Examples -------------------- diff --git a/docs/zh_CN/api-reference/peripherals/rmt.rst b/docs/zh_CN/api-reference/peripherals/rmt.rst index 5a9c0f997a..3acf8141af 100644 --- a/docs/zh_CN/api-reference/peripherals/rmt.rst +++ b/docs/zh_CN/api-reference/peripherals/rmt.rst @@ -552,6 +552,8 @@ IRAM 安全 启用该选项可以保证 cache 禁用时的中断运行,但会相应增加 IRAM 占用。 +另外一个 Kconfig 选项 :ref:`CONFIG_RMT_RECV_FUNC_IN_IRAM` 可以将 :cpp:func:`rmt_receive` 函数放进内部的 IRAM 中,从而当 flash cache 被关闭的时候,这个函数也能够被使用。 + .. _rmt-thread-safety: 线程安全 @@ -560,6 +562,10 @@ IRAM 安全 RMT 驱动程序会确保工厂函数 :cpp:func:`rmt_new_tx_channel`、:cpp:func:`rmt_new_rx_channel` 和 :cpp:func:`rmt_new_sync_manager` 的线程安全。使用时,可以直接从不同的 RTOS 任务中调用此类函数,无需额外锁保护。 其他以 :cpp:type:`rmt_channel_handle_t` 和 :cpp:type:`rmt_sync_manager_handle_t` 作为第一个位置参数的函数均非线程安全,在没有设置互斥锁保护的任务中,应避免从多个任务中调用这类函数。 +以下函数允许在 ISR 上下文中使用: + +- :cpp:func:`rmt_receive` + .. _rmt-kconfig-options: Kconfig 选项 @@ -567,6 +573,7 @@ Kconfig 选项 - :ref:`CONFIG_RMT_ISR_IRAM_SAFE` 控制默认 ISR 处理程序能否在禁用 cache 的情况下工作。详情请参阅 :ref:`rmt-iram-safe`。 - :ref:`CONFIG_RMT_ENABLE_DEBUG_LOG` 用于启用调试日志输出,启用此选项将增加固件的二进制文件大小。 +- :ref:`CONFIG_RMT_RECV_FUNC_IN_IRAM` 用于控制 RMT 接收函数被链接到系统内存的哪个位置(IRAM 还是 Flash)。详情请参阅 :ref:`rmt-iram-safe`。 应用示例 --------------------