Merge branch 'feat/allow_setting_rmt_group_prescale' into 'master'

refactor(rmt): set group clock prescale dynamically

Closes IDFGH-13921

See merge request espressif/esp-idf!34640
This commit is contained in:
Chen Ji Chang 2025-01-17 14:40:28 +08:00
commit e3cf10564d
15 changed files with 167 additions and 51 deletions

View File

@ -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
*/
@ -158,12 +158,64 @@ void rmt_release_group_handle(rmt_group_t *group)
}
}
esp_err_t rmt_select_periph_clock(rmt_channel_handle_t chan, rmt_clock_source_t clk_src)
#if !SOC_RMT_CHANNEL_CLK_INDEPENDENT
static esp_err_t s_rmt_set_group_prescale(rmt_channel_t *chan, uint32_t expect_resolution_hz, uint32_t *ret_channel_prescale)
{
uint32_t periph_src_clk_hz = 0;
rmt_group_t *group = chan->group;
int group_id = group->group_id;
ESP_RETURN_ON_ERROR(esp_clk_tree_src_get_freq_hz(group->clk_src, ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, &periph_src_clk_hz), TAG, "get clock source freq failed");
uint32_t group_resolution_hz = 0;
uint32_t group_prescale = 0;
uint32_t channel_prescale = 0;
if (group->resolution_hz == 0) {
while (++group_prescale <= RMT_LL_GROUP_CLOCK_MAX_INTEGER_PRESCALE) {
group_resolution_hz = periph_src_clk_hz / group_prescale;
channel_prescale = (group_resolution_hz + expect_resolution_hz / 2) / expect_resolution_hz;
// use the first value found during the search that satisfies the division requirement (highest frequency)
if (channel_prescale > 0 && channel_prescale <= RMT_LL_CHANNEL_CLOCK_MAX_PRESCALE) {
break;
}
}
} else {
group_prescale = periph_src_clk_hz / group->resolution_hz;
channel_prescale = (group->resolution_hz + expect_resolution_hz / 2) / expect_resolution_hz;
}
ESP_RETURN_ON_FALSE(group_prescale > 0 && group_prescale <= RMT_LL_GROUP_CLOCK_MAX_INTEGER_PRESCALE, ESP_ERR_INVALID_ARG, TAG,
"group prescale out of the range");
ESP_RETURN_ON_FALSE(channel_prescale > 0 && channel_prescale <= RMT_LL_CHANNEL_CLOCK_MAX_PRESCALE, ESP_ERR_INVALID_ARG, TAG,
"channel prescale out of the range");
// group prescale is shared by all rmt_channel, only set once. use critical section to avoid race condition.
bool prescale_conflict = false;
group_resolution_hz = periph_src_clk_hz / group_prescale;
portENTER_CRITICAL(&group->spinlock);
if (group->resolution_hz == 0) {
group->resolution_hz = group_resolution_hz;
RMT_CLOCK_SRC_ATOMIC() {
rmt_ll_set_group_clock_src(group->hal.regs, chan->channel_id, group->clk_src, group_prescale, 1, 0);
rmt_ll_enable_group_clock(group->hal.regs, true);
}
} else {
prescale_conflict = (group->resolution_hz != group_resolution_hz);
}
portEXIT_CRITICAL(&group->spinlock);
ESP_RETURN_ON_FALSE(!prescale_conflict, ESP_ERR_INVALID_ARG, TAG,
"group resolution conflict, already is %"PRIu32" but attempt to %"PRIu32"", group->resolution_hz, group_resolution_hz);
ESP_LOGD(TAG, "group (%d) clock resolution:%"PRIu32"Hz", group_id, group->resolution_hz);
*ret_channel_prescale = channel_prescale;
return ESP_OK;
}
#endif // SOC_RMT_CHANNEL_CLK_INDEPENDENT
esp_err_t rmt_select_periph_clock(rmt_channel_handle_t chan, rmt_clock_source_t clk_src, uint32_t expect_channel_resolution)
{
esp_err_t ret = ESP_OK;
rmt_group_t *group = chan->group;
int channel_id = chan->channel_id;
uint32_t periph_src_clk_hz = 0;
bool clock_selection_conflict = false;
// check if we need to update the group clock source, group clock source is shared by all channels
portENTER_CRITICAL(&group->spinlock);
@ -173,7 +225,7 @@ esp_err_t rmt_select_periph_clock(rmt_channel_handle_t chan, rmt_clock_source_t
clock_selection_conflict = (group->clk_src != clk_src);
}
portEXIT_CRITICAL(&group->spinlock);
ESP_RETURN_ON_FALSE(!clock_selection_conflict, ESP_ERR_INVALID_STATE, TAG,
ESP_RETURN_ON_FALSE(!clock_selection_conflict, ESP_ERR_INVALID_ARG, TAG,
"group clock conflict, already is %d but attempt to %d", group->clk_src, clk_src);
// TODO: [clk_tree] to use a generic clock enable/disable or acquire/release function for all clock source
@ -185,10 +237,6 @@ esp_err_t rmt_select_periph_clock(rmt_channel_handle_t chan, rmt_clock_source_t
}
#endif // SOC_RMT_SUPPORT_RC_FAST
// get clock source frequency
ESP_RETURN_ON_ERROR(esp_clk_tree_src_get_freq_hz((soc_module_clk_t)clk_src, ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, &periph_src_clk_hz),
TAG, "get clock source frequency failed");
#if CONFIG_PM_ENABLE
// if DMA is not used, we're using CPU to push the data to the RMT FIFO
// if the CPU frequency goes down, the transfer+encoding scheme could be unstable because CPU can't fill the data in time
@ -203,19 +251,40 @@ esp_err_t rmt_select_periph_clock(rmt_channel_handle_t chan, rmt_clock_source_t
}
#endif // SOC_RMT_SUPPORT_APB
sprintf(chan->pm_lock_name, "rmt_%d_%d", group->group_id, channel_id); // e.g. rmt_0_0
sprintf(chan->pm_lock_name, "rmt_%d_%d", group->group_id, chan->channel_id); // e.g. rmt_0_0
ret = esp_pm_lock_create(pm_lock_type, 0, chan->pm_lock_name, &chan->pm_lock);
ESP_RETURN_ON_ERROR(ret, TAG, "create pm lock failed");
#endif // CONFIG_PM_ENABLE
esp_clk_tree_enable_src((soc_module_clk_t)clk_src, true);
// no division for group clock source, to achieve highest resolution
uint32_t real_div;
#if SOC_RMT_CHANNEL_CLK_INDEPENDENT
uint32_t periph_src_clk_hz = 0;
// get clock source frequency
ESP_RETURN_ON_ERROR(esp_clk_tree_src_get_freq_hz((soc_module_clk_t)clk_src, ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, &periph_src_clk_hz),
TAG, "get clock source frequency failed");
RMT_CLOCK_SRC_ATOMIC() {
rmt_ll_set_group_clock_src(group->hal.regs, channel_id, clk_src, 1, 1, 0);
rmt_ll_set_group_clock_src(group->hal.regs, chan->channel_id, clk_src, 1, 1, 0);
rmt_ll_enable_group_clock(group->hal.regs, true);
}
group->resolution_hz = periph_src_clk_hz;
ESP_LOGD(TAG, "group clock resolution:%"PRIu32, group->resolution_hz);
real_div = (group->resolution_hz + expect_channel_resolution / 2) / expect_channel_resolution;
#else
// set division for group clock source, to achieve highest resolution while guaranteeing the channel resolution.
ESP_RETURN_ON_ERROR(s_rmt_set_group_prescale(chan, expect_channel_resolution, &real_div), TAG, "set rmt group prescale failed");
#endif // SOC_RMT_CHANNEL_CLK_INDEPENDENT
if (chan->direction == RMT_CHANNEL_DIRECTION_TX) {
rmt_ll_tx_set_channel_clock_div(group->hal.regs, chan->channel_id, real_div);
} else {
rmt_ll_rx_set_channel_clock_div(group->hal.regs, chan->channel_id, real_div);
}
// resolution lost due to division, calculate the real resolution
chan->resolution_hz = group->resolution_hz / real_div;
if (chan->resolution_hz != expect_channel_resolution) {
ESP_LOGW(TAG, "channel resolution loss, real=%"PRIu32, chan->resolution_hz);
}
return ret;
}

View File

@ -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
*/
@ -19,6 +19,7 @@
#include "hal/rmt_hal.h"
#include "hal/dma_types.h"
#include "hal/cache_ll.h"
#include "hal/hal_utils.h"
#include "esp_intr_alloc.h"
#include "esp_heap_caps.h"
#include "esp_clk_tree.h"
@ -113,7 +114,7 @@ struct rmt_group_t {
portMUX_TYPE spinlock; // to protect per-group register level concurrent access
rmt_hal_context_t hal; // hal layer for each group
rmt_clock_source_t clk_src; // record the group clock source, group clock is shared by all channels
uint32_t resolution_hz; // resolution of group clock
uint32_t resolution_hz; // resolution of group clock. clk_src_hz / prescale = resolution_hz
uint32_t occupy_mask; // a set bit in the mask indicates the channel is not available
rmt_tx_channel_t *tx_channels[SOC_RMT_TX_CANDIDATES_PER_GROUP]; // array of RMT TX channels
rmt_rx_channel_t *rx_channels[SOC_RMT_RX_CANDIDATES_PER_GROUP]; // array of RMT RX channels
@ -219,17 +220,18 @@ rmt_group_t *rmt_acquire_group_handle(int group_id);
void rmt_release_group_handle(rmt_group_t *group);
/**
* @brief Set clock source for RMT peripheral
* @brief Set clock source and resolution for RMT peripheral
*
* @param chan RMT channel handle
* @param clk_src Clock source
* @param expect_channel_resolution Expected channel resolution
* @return
* - ESP_OK: Set clock source successfully
* - ESP_ERR_NOT_SUPPORTED: Set clock source failed because the clk_src is not supported
* - ESP_ERR_INVALID_STATE: Set clock source failed because the clk_src is different from other RMT channel
* - ESP_FAIL: Set clock source failed because of other error
*/
esp_err_t rmt_select_periph_clock(rmt_channel_handle_t chan, rmt_clock_source_t clk_src);
esp_err_t rmt_select_periph_clock(rmt_channel_handle_t chan, rmt_clock_source_t clk_src, uint32_t expect_channel_resolution);
/**
* @brief Set interrupt priority to RMT group

View File

@ -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
*/
@ -276,16 +276,9 @@ esp_err_t rmt_new_rx_channel(const rmt_rx_channel_config_t *config, rmt_channel_
ESP_GOTO_ON_ERROR(ret, err, TAG, "install rx interrupt failed");
}
// select the clock source
ESP_GOTO_ON_ERROR(rmt_select_periph_clock(&rx_channel->base, config->clk_src), err, TAG, "set group clock failed");
// set channel clock resolution, find the divider to get the closest resolution
uint32_t real_div = (group->resolution_hz + config->resolution_hz / 2) / config->resolution_hz;
rmt_ll_rx_set_channel_clock_div(hal->regs, channel_id, real_div);
// resolution loss due to division, calculate the real resolution
rx_channel->base.resolution_hz = group->resolution_hz / real_div;
if (rx_channel->base.resolution_hz != config->resolution_hz) {
ESP_LOGW(TAG, "channel resolution loss, real=%"PRIu32, rx_channel->base.resolution_hz);
}
rx_channel->base.direction = RMT_CHANNEL_DIRECTION_RX;
// select the clock source and set clock resolution
ESP_GOTO_ON_ERROR(rmt_select_periph_clock(&rx_channel->base, config->clk_src, config->resolution_hz), err, TAG, "set clock resolution failed");
rx_channel->filter_clock_resolution_hz = group->resolution_hz;
// On esp32 and esp32s2, the counting clock used by the RX filter always comes from APB clock
@ -323,7 +316,6 @@ esp_err_t rmt_new_rx_channel(const rmt_rx_channel_config_t *config, rmt_channel_
// initialize other members of rx channel
portMUX_INITIALIZE(&rx_channel->base.spinlock);
atomic_init(&rx_channel->base.fsm, RMT_FSM_INIT);
rx_channel->base.direction = RMT_CHANNEL_DIRECTION_RX;
rx_channel->base.hw_mem_base = &RMTMEM.channels[channel_id + RMT_RX_CHANNEL_OFFSET_IN_GROUP].symbols[0];
// polymorphic methods
rx_channel->base.del = rmt_del_rx_channel;

View File

@ -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
*/
@ -331,16 +331,9 @@ esp_err_t rmt_new_tx_channel(const rmt_tx_channel_config_t *config, rmt_channel_
ESP_GOTO_ON_ERROR(rmt_tx_init_dma_link(tx_channel, config), err, TAG, "install tx DMA failed");
}
#endif
// select the clock source
ESP_GOTO_ON_ERROR(rmt_select_periph_clock(&tx_channel->base, config->clk_src), err, TAG, "set group clock failed");
// set channel clock resolution, find the divider to get the closest resolution
uint32_t real_div = (group->resolution_hz + config->resolution_hz / 2) / config->resolution_hz;
rmt_ll_tx_set_channel_clock_div(hal->regs, channel_id, real_div);
// resolution lost due to division, calculate the real resolution
tx_channel->base.resolution_hz = group->resolution_hz / real_div;
if (tx_channel->base.resolution_hz != config->resolution_hz) {
ESP_LOGW(TAG, "channel resolution loss, real=%"PRIu32, tx_channel->base.resolution_hz);
}
tx_channel->base.direction = RMT_CHANNEL_DIRECTION_TX;
// select the clock source and set clock resolution
ESP_GOTO_ON_ERROR(rmt_select_periph_clock(&tx_channel->base, config->clk_src, config->resolution_hz), err, TAG, "set clock resolution failed");
rmt_ll_tx_set_mem_blocks(hal->regs, channel_id, tx_channel->base.mem_block_num);
// set limit threshold, after transmit ping_pong_symbols size, an interrupt event would be generated
@ -376,7 +369,6 @@ esp_err_t rmt_new_tx_channel(const rmt_tx_channel_config_t *config, rmt_channel_
portMUX_INITIALIZE(&tx_channel->base.spinlock);
atomic_init(&tx_channel->base.fsm, RMT_FSM_INIT);
tx_channel->base.direction = RMT_CHANNEL_DIRECTION_TX;
tx_channel->base.hw_mem_base = &RMTMEM.channels[channel_id + RMT_TX_CHANNEL_OFFSET_IN_GROUP].symbols[0];
// polymorphic methods
tx_channel->base.del = rmt_del_tx_channel;

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -155,3 +155,34 @@ TEST_CASE("rmt interrupt priority", "[rmt]")
TEST_ESP_OK(rmt_del_channel(rx_channel));
TEST_ESP_OK(rmt_del_channel(another_rx_channel));
}
#if !SOC_RMT_CHANNEL_CLK_INDEPENDENT
TEST_CASE("rmt multiple channels with different resolution", "[rmt]")
{
rmt_tx_channel_config_t tx_channel_cfg = {
.mem_block_symbols = SOC_RMT_MEM_WORDS_PER_CHANNEL,
.gpio_num = TEST_RMT_GPIO_NUM_A,
.clk_src = RMT_CLK_SRC_DEFAULT,
.resolution_hz = 20 * 1000, // 20KHz
.trans_queue_depth = 1,
};
rmt_channel_handle_t tx_channel = NULL;
rmt_rx_channel_config_t rx_channel_cfg = {
.mem_block_symbols = SOC_RMT_MEM_WORDS_PER_CHANNEL,
.gpio_num = TEST_RMT_GPIO_NUM_B,
.clk_src = RMT_CLK_SRC_DEFAULT,
.resolution_hz = 40 * 1000 * 1000, // 40MHz
};
rmt_channel_handle_t rx_channel = NULL;
TEST_ESP_OK(rmt_new_tx_channel(&tx_channel_cfg, &tx_channel));
TEST_ESP_ERR(ESP_ERR_INVALID_ARG, rmt_new_rx_channel(&rx_channel_cfg, &rx_channel));
rx_channel_cfg.resolution_hz = 1 * 1000 * 1000; // 1MHz
TEST_ESP_OK(rmt_new_rx_channel(&rx_channel_cfg, &rx_channel));
TEST_ESP_OK(rmt_del_channel(tx_channel));
TEST_ESP_OK(rmt_del_channel(rx_channel));
}
#endif //SOC_RMT_CHANNEL_CLK_INDEPENDENT

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2019-2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2019-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2020-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -37,6 +37,11 @@ extern "C" {
#define RMT_LL_MAX_FILTER_VALUE 255
#define RMT_LL_MAX_IDLE_VALUE 32767
// Maximum values due to limited register bit width
#define RMT_LL_CHANNEL_CLOCK_MAX_PRESCALE 256
#define RMT_LL_GROUP_CLOCK_MAX_INTEGER_PRESCALE 256
#define RMT_LL_GROUP_CLOCK_MAX_FRACTAL_PRESCALE 64
typedef enum {
RMT_LL_MEM_OWNER_SW = 0,
RMT_LL_MEM_OWNER_HW = 1,

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -38,6 +38,11 @@ extern "C" {
#define RMT_LL_MAX_FILTER_VALUE 255
#define RMT_LL_MAX_IDLE_VALUE 32767
// Maximum values due to limited register bit width
#define RMT_LL_CHANNEL_CLOCK_MAX_PRESCALE 256
#define RMT_LL_GROUP_CLOCK_MAX_INTEGER_PRESCALE 256
#define RMT_LL_GROUP_CLOCK_MAX_FRACTAL_PRESCALE 64
typedef enum {
RMT_LL_MEM_OWNER_SW = 0,
RMT_LL_MEM_OWNER_HW = 1,

View File

@ -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
*/
@ -38,6 +38,11 @@ extern "C" {
#define RMT_LL_MAX_FILTER_VALUE 255
#define RMT_LL_MAX_IDLE_VALUE 32767
// Maximum values due to limited register bit width
#define RMT_LL_CHANNEL_CLOCK_MAX_PRESCALE 256
#define RMT_LL_GROUP_CLOCK_MAX_INTEGER_PRESCALE 256
#define RMT_LL_GROUP_CLOCK_MAX_FRACTAL_PRESCALE 64
typedef enum {
RMT_LL_MEM_OWNER_SW = 0,
RMT_LL_MEM_OWNER_HW = 1,

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -38,6 +38,11 @@ extern "C" {
#define RMT_LL_MAX_FILTER_VALUE 255
#define RMT_LL_MAX_IDLE_VALUE 32767
// Maximum values due to limited register bit width
#define RMT_LL_CHANNEL_CLOCK_MAX_PRESCALE 256
#define RMT_LL_GROUP_CLOCK_MAX_INTEGER_PRESCALE 256
#define RMT_LL_GROUP_CLOCK_MAX_FRACTAL_PRESCALE 64
typedef enum {
RMT_LL_MEM_OWNER_SW = 0,
RMT_LL_MEM_OWNER_HW = 1,

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -37,6 +37,11 @@ extern "C" {
#define RMT_LL_MAX_FILTER_VALUE 255
#define RMT_LL_MAX_IDLE_VALUE 32767
// Maximum values due to limited register bit width
#define RMT_LL_CHANNEL_CLOCK_MAX_PRESCALE 256
#define RMT_LL_GROUP_CLOCK_MAX_INTEGER_PRESCALE 256
#define RMT_LL_GROUP_CLOCK_MAX_FRACTAL_PRESCALE 64
typedef enum {
RMT_LL_MEM_OWNER_SW = 0,
RMT_LL_MEM_OWNER_HW = 1,

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2019-2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2019-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/

View File

@ -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
*/
@ -37,6 +37,11 @@ extern "C" {
#define RMT_LL_MAX_FILTER_VALUE 255
#define RMT_LL_MAX_IDLE_VALUE 32767
// Maximum values due to limited register bit width
#define RMT_LL_CHANNEL_CLOCK_MAX_PRESCALE 256
#define RMT_LL_GROUP_CLOCK_MAX_INTEGER_PRESCALE 256
#define RMT_LL_GROUP_CLOCK_MAX_FRACTAL_PRESCALE 64
typedef enum {
RMT_LL_MEM_OWNER_SW = 0,
RMT_LL_MEM_OWNER_HW = 1,

View File

@ -144,7 +144,7 @@ Once the :cpp:type:`rmt_rx_channel_config_t` structure is populated with mandato
.. note::
Due to a software limitation in the GPIO driver, when both TX and RX channels are bound to the same GPIO, ensure the RX Channel is initialized before the TX Channel. If the TX Channel was set up first, then during the RX Channel setup, the previous RMT TX Channel signal will be overridden by the GPIO control signal.
When multiple RMT channels are allocated at the same time, the groups prescale is determined based on the resolution of the first channel. The driver then selects the appropriate prescale from low to high. To avoid prescale conflicts when allocating multiple channels, allocate channels in order of their target resolution, either from highest to lowest or lowest to highest.
Uninstall RMT Channel
~~~~~~~~~~~~~~~~~~~~~

View File

@ -144,7 +144,7 @@ RMT 接收器可以对输入信号采样,将其转换为 RMT 数据格式,
.. note::
由于 GPIO 驱动程序中的软件限制,当 TX 和 RX 通道都绑定到同一 GPIO 时,请确保在 TX 通道之前初始化 RX 通道。如果先设置 TX 通道,那么在 RX 通道设置期间GPIO 控制信号将覆盖先前的 RMT TX 通道信号
同时分配多个 RMT 通道时RMT 组的分频系数将以第一个通道的分辨率来计算,驱动会从低到高寻找合适的分频系数。若分配多个通道时出现分频系数冲突,请调整分配通道的顺序,按照目标分辨率的大小按序申请通道(从大到小或者从小到大)
卸载 RMT 通道
~~~~~~~~~~~~~~~~~~~~~