docs(rmt): clarification on memory and isr lantency

Closes https://github.com/espressif/esp-idf/issues/11651
Closes https://github.com/espressif/esp-idf/issues/13129
This commit is contained in:
morris 2024-03-13 18:31:47 +08:00
parent 5a682c3bbb
commit 7b135c4b8a
3 changed files with 16 additions and 13 deletions

View File

@ -89,7 +89,8 @@ esp_err_t rmt_new_tx_channel(const rmt_tx_channel_config_t *config, rmt_channel_
* Based on the setting of `rmt_transmit_config_t::queue_nonblocking`,
* if there're too many transactions pending in the queue, this function can block until it has free slot,
* otherwise just return quickly.
* @note The data to be transmitted will be encoded into RMT symbols by the specific `encoder`.
* @note The payload data to be transmitted will be encoded into RMT symbols by the specific `encoder`.
* @note You CAN'T modify the `payload` during the transmission, it should be kept valid until the transmission is finished.
*
* @param[in] tx_channel RMT TX channel that created by `rmt_new_tx_channel()`
* @param[in] encoder RMT encoder that created by various factory APIs like `rmt_new_bytes_encoder()`

View File

@ -263,7 +263,7 @@ Once you created an encoder, you can initiate a TX transaction by calling :cpp:f
- Increase the :cpp:member:`rmt_tx_channel_config_t::mem_block_symbols`. This approach does not work if the DMA backend is also enabled.
- Customize an encoder and construct an infinite loop in the encoding function. See also :ref:`rmt-rmt-encoder`.
Internally, :cpp:func:`rmt_transmit` constructs a transaction descriptor and sends it to a job queue, which is dispatched in the ISR. So it is possible that the transaction is not started yet when :cpp:func:`rmt_transmit` returns. To ensure all pending transactions to complete, the user can use :cpp:func:`rmt_tx_wait_all_done`.
Internally, :cpp:func:`rmt_transmit` constructs a transaction descriptor and sends it to a job queue, which is dispatched in the ISR. So it is possible that the transaction is not started yet when :cpp:func:`rmt_transmit` returns. You cannot recycle or modify the payload buffer until the transaction is finished. You can get the transaction completion event by registering a callback function via :cpp:func:`rmt_tx_register_event_callbacks`. To ensure all pending transactions to complete, you can also use :cpp:func:`rmt_tx_wait_all_done`.
.. _rmt-multiple-channels-simultaneous-transmission:
@ -594,13 +594,14 @@ Application Examples
FAQ
---
* Why the RMT encoder results in more data than expected?
* Why the RMT transmits more data than expected?
The RMT encoding takes place in the ISR context. If your RMT encoding session takes a long time (e.g., by logging debug information) or the encoding session is deferred somehow because of interrupt latency, then it is possible the transmitting becomes **faster** than the encoding. As a result, the encoder can not prepare the next data in time, leading to the transmitter sending the previous data again. There is no way to ask the transmitter to stop and wait. You can mitigate the issue by combining the following ways:
The encoding for the RMT transmission is carried out within the ISR context. Should the RMT encoding process be prolonged (for example, through logging or tracing the procedure) or if it is delayed due to interrupt latency and preemptive interrupts, the hardware transmitter might read from the memory before the encoder has written to it. Consequently, the transmitter would end up sending outdated data. Although it's not possible to instruct the transmitter to pause and wait, this issue can be mitigated by employing a combination of the following strategies:
- Increase the :cpp:member:`rmt_tx_channel_config_t::mem_block_symbols`, in steps of {IDF_TARGET_SOC_RMT_MEM_WORDS_PER_CHANNEL}.
- Place the encoding function in the IRAM.
- Enables the :cpp:member:`rmt_tx_channel_config_t::with_dma` if it is available for your chip.
- Increase the :cpp:member:`rmt_tx_channel_config_t::mem_block_symbols`, in steps of {IDF_TARGET_SOC_RMT_MEM_WORDS_PER_CHANNEL}.
- Place the encoding function in the IRAM with ``IRAM_ATTR`` attribute.
- Enable the :cpp:member:`rmt_tx_channel_config_t::with_dma` if DMA is available.
- Install the RMT driver on a separate CPU core to avoid competing for the same CPU resources with other interrupt heavy peripherals (e.g. WiFi, Bluetooth).
API Reference
-------------

View File

@ -263,7 +263,7 @@ RMT 是一种特殊的通信外设,无法像 SPI 和 I2C 那样发送原始字
- 增加 :cpp:member:`rmt_tx_channel_config_t::mem_block_symbols`。若此时启用了 DMA 后端,该方法将失效。
- 自定义编码器,并在编码函数中构造一个无限循环,详情请参阅 :ref:`rmt-rmt-encoder`
:cpp:func:`rmt_transmit` 会在其内部构建一个事务描述符,并将其发送到作业队列中,该队列将在 ISR 中调度。因此,在 :cpp:func:`rmt_transmit` 返回时,事务可能尚未启动。为确保完成所有挂起的事务,请调用 :cpp:func:`rmt_tx_wait_all_done`
:cpp:func:`rmt_transmit` 会在其内部构建一个事务描述符,并将其发送到作业队列中,该队列通常会在 ISR 上下文中被调度。因此,在 :cpp:func:`rmt_transmit` 返回时,该事务可能尚未启动。注意,你不能在事务结束前就去回收或者修改 payload 中的内容。通过 :cpp:func:`rmt_tx_register_event_callbacks` 来注册事件回调,可以在事务完成的时候被通知。为确保完成所有挂起的事务,你还可以调用 :cpp:func:`rmt_tx_wait_all_done`
.. _rmt-multiple-channels-simultaneous-transmission:
@ -594,13 +594,14 @@ Kconfig 选项
FAQ
---
* RMT 编码器为什么会产生比预期更多的数据?
* RMT 为什么会发送比预期更多的数据?
RMT 编码在 ISR 上下文中发生。如果 RMT 编码会话耗时较长(例如,记录调试信息),或者由于中断延迟导致编码会话延迟执行,则传输速率可能会超过编码速率。此时,编码器无法及时准备下一组数据,致使传输器再次发送先前的数据。由于传输器无法停止并等待,可以通过以下方法来缓解此问题:
RMT 的传输层编码是在 ISR 上下文中完成的,如果 RMT 编码耗时较长(例如,增加了过多的调试追踪信息),或者由于中断延迟和抢占导致编码工作被推迟执行,导致传输器在编码器更新内存数据之前就读取了老数据,致使传输器再次发送先前的数据。我们无法告诉硬件传输器自动等待新数据的更新,但是可以通过以下方法来缓解此问题:
- 增加 :cpp:member:`rmt_tx_channel_config_t::mem_block_symbols` 的值,步长为 {IDF_TARGET_SOC_RMT_MEM_WORDS_PER_CHANNEL}。
- 将编码函数放置在 IRAM 中。
- 如果所用芯片支持 :cpp:member:`rmt_tx_channel_config_t::with_dma`,请启用该选项。
- 增加 :cpp:member:`rmt_tx_channel_config_t::mem_block_symbols` 的值,步长为 {IDF_TARGET_SOC_RMT_MEM_WORDS_PER_CHANNEL}。
- 将编码函数放置在 IRAM 中。
- 如果所用芯片支持 :cpp:member:`rmt_tx_channel_config_t::with_dma`,请启用该选项。
- 将RMT驱动安装在另外一个CPU核上避免和其他高中断频率的外设竞争同一个CPU资源。
API 参考
-------------