Merge branch 'feature/support_rmt_esp32p4' into 'master'

RMT driver support on ESP32-P4

Closes IDF-7476 and IDF-7730

See merge request espressif/esp-idf!25680
This commit is contained in:
morris
2023-09-20 23:11:11 +08:00
42 changed files with 1882 additions and 593 deletions

View File

@@ -299,32 +299,7 @@ menu "Driver Configurations"
orsource "./pcnt/Kconfig.pcnt" orsource "./pcnt/Kconfig.pcnt"
menu "RMT Configuration" orsource "./rmt/Kconfig.rmt"
depends on SOC_RMT_SUPPORTED
config RMT_ISR_IRAM_SAFE
bool "RMT ISR IRAM-Safe"
default n
select GDMA_ISR_IRAM_SAFE if SOC_RMT_SUPPORT_DMA # RMT basic functionality relies on GDMA callback
select GDMA_CTRL_FUNC_IN_IRAM if SOC_RMT_SUPPORT_DMA # RMT needs to restart the GDMA in the interrupt
help
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_SUPPRESS_DEPRECATE_WARN
bool "Suppress legacy driver deprecated warning"
default n
help
Wether to suppress the deprecation warnings when using legacy rmt driver (driver/rmt.h).
If you want to continue using the legacy driver, and don't want to see related deprecation warnings,
you can enable this option.
config RMT_ENABLE_DEBUG_LOG
bool "Enable debug log"
default n
help
Wether to enable the debug log message for RMT driver.
Note that, this option only controls the RMT driver log, won't affect other drivers.
endmenu # RMT Configuration
orsource "./mcpwm/Kconfig.mcpwm" orsource "./mcpwm/Kconfig.mcpwm"

View File

@@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@@ -58,6 +58,18 @@ static const char *TAG = "rmt(legacy)";
#define RMT_DECODE_RX_CHANNEL(encode_chan) ((encode_chan - RMT_RX_CHANNEL_ENCODING_START)) #define RMT_DECODE_RX_CHANNEL(encode_chan) ((encode_chan - RMT_RX_CHANNEL_ENCODING_START))
#define RMT_ENCODE_RX_CHANNEL(decode_chan) ((decode_chan + RMT_RX_CHANNEL_ENCODING_START)) #define RMT_ENCODE_RX_CHANNEL(decode_chan) ((decode_chan + RMT_RX_CHANNEL_ENCODING_START))
#if SOC_PERIPH_CLK_CTRL_SHARED
#define RMT_CLOCK_SRC_ATOMIC() PERIPH_RCC_ATOMIC()
#else
#define RMT_CLOCK_SRC_ATOMIC()
#endif
#if !SOC_RCC_IS_INDEPENDENT
#define RMT_RCC_ATOMIC() PERIPH_RCC_ATOMIC()
#else
#define RMT_RCC_ATOMIC()
#endif
typedef struct { typedef struct {
rmt_hal_context_t hal; rmt_hal_context_t hal;
_lock_t rmt_driver_isr_lock; _lock_t rmt_driver_isr_lock;
@@ -125,8 +137,10 @@ static void rmt_module_enable(void)
{ {
RMT_ENTER_CRITICAL(); RMT_ENTER_CRITICAL();
if (rmt_contex.rmt_module_enabled == false) { if (rmt_contex.rmt_module_enabled == false) {
periph_module_reset(rmt_periph_signals.groups[0].module); RMT_RCC_ATOMIC() {
periph_module_enable(rmt_periph_signals.groups[0].module); rmt_ll_enable_bus_clock(0, true);
rmt_ll_reset_register(0);
}
rmt_contex.rmt_module_enabled = true; rmt_contex.rmt_module_enabled = true;
} }
RMT_EXIT_CRITICAL(); RMT_EXIT_CRITICAL();
@@ -137,7 +151,9 @@ static void rmt_module_disable(void)
{ {
RMT_ENTER_CRITICAL(); RMT_ENTER_CRITICAL();
if (rmt_contex.rmt_module_enabled == true) { if (rmt_contex.rmt_module_enabled == true) {
periph_module_disable(rmt_periph_signals.groups[0].module); RMT_RCC_ATOMIC() {
rmt_ll_enable_bus_clock(0, false);
}
rmt_contex.rmt_module_enabled = false; rmt_contex.rmt_module_enabled = false;
} }
RMT_EXIT_CRITICAL(); RMT_EXIT_CRITICAL();
@@ -415,7 +431,9 @@ esp_err_t rmt_set_source_clk(rmt_channel_t channel, rmt_source_clk_t base_clk)
ESP_RETURN_ON_FALSE(channel < RMT_CHANNEL_MAX, ESP_ERR_INVALID_ARG, TAG, RMT_CHANNEL_ERROR_STR); ESP_RETURN_ON_FALSE(channel < RMT_CHANNEL_MAX, ESP_ERR_INVALID_ARG, TAG, RMT_CHANNEL_ERROR_STR);
RMT_ENTER_CRITICAL(); RMT_ENTER_CRITICAL();
// `rmt_clock_source_t` and `rmt_source_clk_t` are binary compatible, as the underlying enum entries come from the same `soc_module_clk_t` // `rmt_clock_source_t` and `rmt_source_clk_t` are binary compatible, as the underlying enum entries come from the same `soc_module_clk_t`
RMT_CLOCK_SRC_ATOMIC() {
rmt_ll_set_group_clock_src(rmt_contex.hal.regs, channel, (rmt_clock_source_t)base_clk, 1, 0, 0); rmt_ll_set_group_clock_src(rmt_contex.hal.regs, channel, (rmt_clock_source_t)base_clk, 1, 0, 0);
}
RMT_EXIT_CRITICAL(); RMT_EXIT_CRITICAL();
return ESP_OK; return ESP_OK;
} }
@@ -552,6 +570,7 @@ static esp_err_t rmt_internal_config(rmt_dev_t *dev, const rmt_config_t *rmt_par
uint32_t carrier_freq_hz = rmt_param->tx_config.carrier_freq_hz; uint32_t carrier_freq_hz = rmt_param->tx_config.carrier_freq_hz;
bool carrier_en = rmt_param->tx_config.carrier_en; bool carrier_en = rmt_param->tx_config.carrier_en;
uint32_t rmt_source_clk_hz; uint32_t rmt_source_clk_hz;
rmt_clock_source_t clk_src = RMT_BASECLK_DEFAULT;
ESP_RETURN_ON_FALSE(rmt_is_channel_number_valid(channel, mode), ESP_ERR_INVALID_ARG, TAG, RMT_CHANNEL_ERROR_STR); ESP_RETURN_ON_FALSE(rmt_is_channel_number_valid(channel, mode), ESP_ERR_INVALID_ARG, TAG, RMT_CHANNEL_ERROR_STR);
ESP_RETURN_ON_FALSE(mem_cnt + channel <= SOC_RMT_CHANNELS_PER_GROUP && mem_cnt > 0, ESP_ERR_INVALID_ARG, TAG, RMT_MEM_CNT_ERROR_STR); ESP_RETURN_ON_FALSE(mem_cnt + channel <= SOC_RMT_CHANNELS_PER_GROUP && mem_cnt > 0, ESP_ERR_INVALID_ARG, TAG, RMT_MEM_CNT_ERROR_STR);
@@ -567,19 +586,18 @@ static esp_err_t rmt_internal_config(rmt_dev_t *dev, const rmt_config_t *rmt_par
if (rmt_param->flags & RMT_CHANNEL_FLAGS_AWARE_DFS) { if (rmt_param->flags & RMT_CHANNEL_FLAGS_AWARE_DFS) {
#if SOC_RMT_SUPPORT_XTAL #if SOC_RMT_SUPPORT_XTAL
// clock src: XTAL_CLK // clock src: XTAL_CLK
esp_clk_tree_src_get_freq_hz((soc_module_clk_t)RMT_BASECLK_XTAL, ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, &rmt_source_clk_hz); clk_src = RMT_BASECLK_XTAL;
rmt_ll_set_group_clock_src(dev, channel, (rmt_clock_source_t)RMT_BASECLK_XTAL, 1, 0, 0);
#elif SOC_RMT_SUPPORT_REF_TICK #elif SOC_RMT_SUPPORT_REF_TICK
// clock src: REF_CLK // clock src: REF_CLK
esp_clk_tree_src_get_freq_hz((soc_module_clk_t)RMT_BASECLK_REF, ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, &rmt_source_clk_hz); clk_src = RMT_BASECLK_REF;
rmt_ll_set_group_clock_src(dev, channel, (rmt_clock_source_t)RMT_BASECLK_REF, 1, 0, 0);
#else #else
#error "No clock source is aware of DFS" #error "No clock source is aware of DFS"
#endif #endif
} else { }
// fallback to use default clock source esp_clk_tree_src_get_freq_hz((soc_module_clk_t)clk_src, ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, &rmt_source_clk_hz);
esp_clk_tree_src_get_freq_hz((soc_module_clk_t)RMT_BASECLK_DEFAULT, ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, &rmt_source_clk_hz); RMT_CLOCK_SRC_ATOMIC() {
rmt_ll_set_group_clock_src(dev, channel, (rmt_clock_source_t)RMT_BASECLK_DEFAULT, 1, 0, 0); rmt_ll_set_group_clock_src(dev, channel, clk_src, 1, 0, 0);
rmt_ll_enable_group_clock(dev, true);
} }
RMT_EXIT_CRITICAL(); RMT_EXIT_CRITICAL();

View File

@@ -34,7 +34,7 @@ static const char *TIMER_TAG = "timer_group";
#define TIMER_ENTER_CRITICAL(mux) portENTER_CRITICAL_SAFE(mux); #define TIMER_ENTER_CRITICAL(mux) portENTER_CRITICAL_SAFE(mux);
#define TIMER_EXIT_CRITICAL(mux) portEXIT_CRITICAL_SAFE(mux); #define TIMER_EXIT_CRITICAL(mux) portEXIT_CRITICAL_SAFE(mux);
#if CONFIG_IDF_TARGET_ESP32P4 #if SOC_PERIPH_CLK_CTRL_SHARED
#define GPTIMER_CLOCK_SRC_ATOMIC() PERIPH_RCC_ATOMIC() #define GPTIMER_CLOCK_SRC_ATOMIC() PERIPH_RCC_ATOMIC()
#else #else
#define GPTIMER_CLOCK_SRC_ATOMIC() #define GPTIMER_CLOCK_SRC_ATOMIC()

View File

@@ -32,7 +32,7 @@
static const char *TAG = "gptimer"; static const char *TAG = "gptimer";
#if CONFIG_IDF_TARGET_ESP32P4 #if SOC_PERIPH_CLK_CTRL_SHARED
#define GPTIMER_CLOCK_SRC_ATOMIC() PERIPH_RCC_ATOMIC() #define GPTIMER_CLOCK_SRC_ATOMIC() PERIPH_RCC_ATOMIC()
#else #else
#define GPTIMER_CLOCK_SRC_ATOMIC() #define GPTIMER_CLOCK_SRC_ATOMIC()

View File

@@ -0,0 +1,26 @@
menu "RMT Configuration"
depends on SOC_RMT_SUPPORTED
config RMT_ISR_IRAM_SAFE
bool "RMT ISR IRAM-Safe"
default n
select GDMA_ISR_IRAM_SAFE if SOC_RMT_SUPPORT_DMA # RMT basic functionality relies on GDMA callback
select GDMA_CTRL_FUNC_IN_IRAM if SOC_RMT_SUPPORT_DMA # RMT needs to restart the GDMA in the interrupt
help
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_SUPPRESS_DEPRECATE_WARN
bool "Suppress legacy driver deprecated warning"
default n
help
Wether to suppress the deprecation warnings when using legacy rmt driver (driver/rmt.h).
If you want to continue using the legacy driver, and don't want to see related deprecation warnings,
you can enable this option.
config RMT_ENABLE_DEBUG_LOG
bool "Enable debug log"
default n
help
Wether to enable the debug log message for RMT driver.
Note that, this option only controls the RMT driver log, won't affect other drivers.
endmenu # RMT Configuration

View File

@@ -24,6 +24,18 @@
static const char *TAG = "rmt"; static const char *TAG = "rmt";
#if SOC_PERIPH_CLK_CTRL_SHARED
#define RMT_CLOCK_SRC_ATOMIC() PERIPH_RCC_ATOMIC()
#else
#define RMT_CLOCK_SRC_ATOMIC()
#endif
#if !SOC_RCC_IS_INDEPENDENT
#define RMT_RCC_ATOMIC() PERIPH_RCC_ATOMIC()
#else
#define RMT_RCC_ATOMIC()
#endif
typedef struct rmt_platform_t { typedef struct rmt_platform_t {
_lock_t mutex; // platform level mutex lock _lock_t mutex; // platform level mutex lock
rmt_group_t *groups[SOC_RMT_GROUPS]; // array of RMT group instances rmt_group_t *groups[SOC_RMT_GROUPS]; // array of RMT group instances
@@ -50,11 +62,13 @@ rmt_group_t *rmt_acquire_group_handle(int group_id)
group->occupy_mask = UINT32_MAX & ~((1 << SOC_RMT_CHANNELS_PER_GROUP) - 1); group->occupy_mask = UINT32_MAX & ~((1 << SOC_RMT_CHANNELS_PER_GROUP) - 1);
// group clock won't be configured at this stage, it will be set when allocate the first channel // group clock won't be configured at this stage, it will be set when allocate the first channel
group->clk_src = 0; group->clk_src = 0;
// enable APB access RMT registers // group interrupt priority is shared between all channels, it will be set when allocate the first channel
periph_module_enable(rmt_periph_signals.groups[group_id].module); group->intr_priority = RMT_GROUP_INTR_PRIORITY_UNINITIALIZED;
periph_module_reset(rmt_periph_signals.groups[group_id].module); // enable the bus clock for the RMT peripheral
// "uninitialize" group intr_priority, read comments in `rmt_new_tx_channel()` for detail RMT_RCC_ATOMIC() {
group->intr_priority = RMT_GROUP_INTR_PRIORITY_UNINITALIZED; rmt_ll_enable_bus_clock(group_id, true);
rmt_ll_reset_register(group_id);
}
// hal layer initialize // hal layer initialize
rmt_hal_init(&group->hal); rmt_hal_init(&group->hal);
} }
@@ -78,15 +92,23 @@ void rmt_release_group_handle(rmt_group_t *group)
int group_id = group->group_id; int group_id = group->group_id;
rmt_clock_source_t clk_src = group->clk_src; rmt_clock_source_t clk_src = group->clk_src;
bool do_deinitialize = false; bool do_deinitialize = false;
rmt_hal_context_t *hal = &group->hal;
_lock_acquire(&s_platform.mutex); _lock_acquire(&s_platform.mutex);
s_platform.group_ref_counts[group_id]--; s_platform.group_ref_counts[group_id]--;
if (s_platform.group_ref_counts[group_id] == 0) { if (s_platform.group_ref_counts[group_id] == 0) {
do_deinitialize = true; do_deinitialize = true;
s_platform.groups[group_id] = NULL; s_platform.groups[group_id] = NULL;
// disable core clock
RMT_CLOCK_SRC_ATOMIC() {
rmt_ll_enable_group_clock(hal->regs, false);
}
// hal layer deinitialize // hal layer deinitialize
rmt_hal_deinit(&group->hal); rmt_hal_deinit(hal);
periph_module_disable(rmt_periph_signals.groups[group_id].module); // disable bus clock
RMT_RCC_ATOMIC() {
rmt_ll_enable_bus_clock(group_id, false);
}
free(group); free(group);
} }
_lock_release(&s_platform.mutex); _lock_release(&s_platform.mutex);
@@ -165,7 +187,10 @@ esp_err_t rmt_select_periph_clock(rmt_channel_handle_t chan, rmt_clock_source_t
#endif // CONFIG_PM_ENABLE #endif // CONFIG_PM_ENABLE
// no division for group clock source, to achieve highest resolution // no division for group clock source, to achieve highest resolution
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, channel_id, clk_src, 1, 1, 0);
rmt_ll_enable_group_clock(group->hal.regs, true);
}
group->resolution_hz = periph_src_clk_hz; group->resolution_hz = periph_src_clk_hz;
ESP_LOGD(TAG, "group clock resolution:%"PRIu32, group->resolution_hz); ESP_LOGD(TAG, "group clock resolution:%"PRIu32, group->resolution_hz);
return ret; return ret;
@@ -211,7 +236,7 @@ bool rmt_set_intr_priority_to_group(rmt_group_t *group, int intr_priority)
{ {
bool priority_conflict = false; bool priority_conflict = false;
portENTER_CRITICAL(&group->spinlock); portENTER_CRITICAL(&group->spinlock);
if (group->intr_priority == RMT_GROUP_INTR_PRIORITY_UNINITALIZED) { if (group->intr_priority == RMT_GROUP_INTR_PRIORITY_UNINITIALIZED) {
// intr_priority never allocated, accept user's value unconditionally // intr_priority never allocated, accept user's value unconditionally
// intr_priority could only be set once here // intr_priority could only be set once here
group->intr_priority = intr_priority; group->intr_priority = intr_priority;
@@ -240,7 +265,8 @@ bool rmt_set_intr_priority_to_group(rmt_group_t *group, int intr_priority)
return priority_conflict; return priority_conflict;
} }
int rmt_get_isr_flags(rmt_group_t *group) { int rmt_get_isr_flags(rmt_group_t *group)
{
int isr_flags = RMT_INTR_ALLOC_FLAG; int isr_flags = RMT_INTR_ALLOC_FLAG;
if (group->intr_priority) { if (group->intr_priority) {
// Use user-specified priority bit // Use user-specified priority bit

View File

@@ -62,8 +62,8 @@ static size_t IRAM_ATTR rmt_encode_bytes(rmt_encoder_t *encoder, rmt_channel_han
rmt_tx_channel_t *tx_chan = __containerof(channel, rmt_tx_channel_t, base); rmt_tx_channel_t *tx_chan = __containerof(channel, rmt_tx_channel_t, base);
const uint8_t *nd = (const uint8_t *)primary_data; const uint8_t *nd = (const uint8_t *)primary_data;
rmt_encode_state_t state = RMT_ENCODING_RESET; rmt_encode_state_t state = RMT_ENCODING_RESET;
dma_descriptor_t *desc0 = NULL; rmt_dma_descriptor_t *desc0 = NULL;
dma_descriptor_t *desc1 = NULL; rmt_dma_descriptor_t *desc1 = NULL;
size_t byte_index = bytes_encoder->last_byte_index; size_t byte_index = bytes_encoder->last_byte_index;
size_t bit_index = bytes_encoder->last_bit_index; size_t bit_index = bytes_encoder->last_bit_index;
@@ -72,7 +72,12 @@ static size_t IRAM_ATTR rmt_encode_bytes(rmt_encoder_t *encoder, rmt_channel_han
// how many symbols we can save for this round // how many symbols we can save for this round
size_t mem_have = tx_chan->mem_end - tx_chan->mem_off; size_t mem_have = tx_chan->mem_end - tx_chan->mem_off;
// where to put the encoded symbols? DMA buffer or RMT HW memory // where to put the encoded symbols? DMA buffer or RMT HW memory
rmt_symbol_word_t *mem_to = channel->dma_chan ? channel->dma_mem_base : channel->hw_mem_base; rmt_symbol_word_t *mem_to_nc = NULL;
if (channel->dma_chan) {
mem_to_nc = (rmt_symbol_word_t *)RMT_GET_NON_CACHE_ADDR(channel->dma_mem_base);
} else {
mem_to_nc = channel->hw_mem_base;
}
// how many symbols will be encoded in this round // how many symbols will be encoded in this round
size_t encode_len = MIN(mem_want, mem_have); size_t encode_len = MIN(mem_want, mem_have);
bool encoding_truncated = mem_have < mem_want; bool encoding_truncated = mem_have < mem_want;
@@ -81,9 +86,9 @@ static size_t IRAM_ATTR rmt_encode_bytes(rmt_encoder_t *encoder, rmt_channel_han
if (channel->dma_chan) { if (channel->dma_chan) {
// mark the start descriptor // mark the start descriptor
if (tx_chan->mem_off < tx_chan->ping_pong_symbols) { if (tx_chan->mem_off < tx_chan->ping_pong_symbols) {
desc0 = &tx_chan->dma_nodes[0]; desc0 = &tx_chan->dma_nodes_nc[0];
} else { } else {
desc0 = &tx_chan->dma_nodes[1]; desc0 = &tx_chan->dma_nodes_nc[1];
} }
} }
@@ -97,9 +102,9 @@ static size_t IRAM_ATTR rmt_encode_bytes(rmt_encoder_t *encoder, rmt_channel_han
} }
while ((len > 0) && (bit_index < 8)) { while ((len > 0) && (bit_index < 8)) {
if (cur_byte & (1 << bit_index)) { if (cur_byte & (1 << bit_index)) {
mem_to[tx_chan->mem_off++] = bytes_encoder->bit1; mem_to_nc[tx_chan->mem_off++] = bytes_encoder->bit1;
} else { } else {
mem_to[tx_chan->mem_off++] = bytes_encoder->bit0; mem_to_nc[tx_chan->mem_off++] = bytes_encoder->bit0;
} }
len--; len--;
bit_index++; bit_index++;
@@ -113,9 +118,9 @@ static size_t IRAM_ATTR rmt_encode_bytes(rmt_encoder_t *encoder, rmt_channel_han
if (channel->dma_chan) { if (channel->dma_chan) {
// mark the end descriptor // mark the end descriptor
if (tx_chan->mem_off < tx_chan->ping_pong_symbols) { if (tx_chan->mem_off < tx_chan->ping_pong_symbols) {
desc1 = &tx_chan->dma_nodes[0]; desc1 = &tx_chan->dma_nodes_nc[0];
} else { } else {
desc1 = &tx_chan->dma_nodes[1]; desc1 = &tx_chan->dma_nodes_nc[1];
} }
// cross line, means desc0 has prepared with sufficient data buffer // cross line, means desc0 has prepared with sufficient data buffer
@@ -168,8 +173,8 @@ static size_t IRAM_ATTR rmt_encode_copy(rmt_encoder_t *encoder, rmt_channel_hand
rmt_tx_channel_t *tx_chan = __containerof(channel, rmt_tx_channel_t, base); rmt_tx_channel_t *tx_chan = __containerof(channel, rmt_tx_channel_t, base);
rmt_symbol_word_t *symbols = (rmt_symbol_word_t *)primary_data; rmt_symbol_word_t *symbols = (rmt_symbol_word_t *)primary_data;
rmt_encode_state_t state = RMT_ENCODING_RESET; rmt_encode_state_t state = RMT_ENCODING_RESET;
dma_descriptor_t *desc0 = NULL; rmt_dma_descriptor_t *desc0 = NULL;
dma_descriptor_t *desc1 = NULL; rmt_dma_descriptor_t *desc1 = NULL;
size_t symbol_index = copy_encoder->last_symbol_index; size_t symbol_index = copy_encoder->last_symbol_index;
// how many symbols will be copied by the encoder // how many symbols will be copied by the encoder
@@ -177,7 +182,12 @@ static size_t IRAM_ATTR rmt_encode_copy(rmt_encoder_t *encoder, rmt_channel_hand
// how many symbols we can save for this round // how many symbols we can save for this round
size_t mem_have = tx_chan->mem_end - tx_chan->mem_off; size_t mem_have = tx_chan->mem_end - tx_chan->mem_off;
// where to put the encoded symbols? DMA buffer or RMT HW memory // where to put the encoded symbols? DMA buffer or RMT HW memory
rmt_symbol_word_t *mem_to = channel->dma_chan ? channel->dma_mem_base : channel->hw_mem_base; rmt_symbol_word_t *mem_to_nc = NULL;
if (channel->dma_chan) {
mem_to_nc = (rmt_symbol_word_t *)RMT_GET_NON_CACHE_ADDR(channel->dma_mem_base);
} else {
mem_to_nc = channel->hw_mem_base;
}
// how many symbols will be encoded in this round // how many symbols will be encoded in this round
size_t encode_len = MIN(mem_want, mem_have); size_t encode_len = MIN(mem_want, mem_have);
bool encoding_truncated = mem_have < mem_want; bool encoding_truncated = mem_have < mem_want;
@@ -186,24 +196,24 @@ static size_t IRAM_ATTR rmt_encode_copy(rmt_encoder_t *encoder, rmt_channel_hand
if (channel->dma_chan) { if (channel->dma_chan) {
// mark the start descriptor // mark the start descriptor
if (tx_chan->mem_off < tx_chan->ping_pong_symbols) { if (tx_chan->mem_off < tx_chan->ping_pong_symbols) {
desc0 = &tx_chan->dma_nodes[0]; desc0 = &tx_chan->dma_nodes_nc[0];
} else { } else {
desc0 = &tx_chan->dma_nodes[1]; desc0 = &tx_chan->dma_nodes_nc[1];
} }
} }
size_t len = encode_len; size_t len = encode_len;
while (len > 0) { while (len > 0) {
mem_to[tx_chan->mem_off++] = symbols[symbol_index++]; mem_to_nc[tx_chan->mem_off++] = symbols[symbol_index++];
len--; len--;
} }
if (channel->dma_chan) { if (channel->dma_chan) {
// mark the end descriptor // mark the end descriptor
if (tx_chan->mem_off < tx_chan->ping_pong_symbols) { if (tx_chan->mem_off < tx_chan->ping_pong_symbols) {
desc1 = &tx_chan->dma_nodes[0]; desc1 = &tx_chan->dma_nodes_nc[0];
} else { } else {
desc1 = &tx_chan->dma_nodes[1]; desc1 = &tx_chan->dma_nodes_nc[1];
} }
// cross line, means desc0 has prepared with sufficient data buffer // cross line, means desc0 has prepared with sufficient data buffer

View File

@@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@@ -13,9 +13,11 @@
#include "freertos/idf_additions.h" #include "freertos/idf_additions.h"
#include "esp_err.h" #include "esp_err.h"
#include "soc/soc_caps.h" #include "soc/soc_caps.h"
#include "soc/gdma_channel.h"
#include "hal/rmt_types.h" #include "hal/rmt_types.h"
#include "hal/rmt_hal.h" #include "hal/rmt_hal.h"
#include "hal/dma_types.h" #include "hal/dma_types.h"
#include "hal/cache_ll.h"
#include "esp_intr_alloc.h" #include "esp_intr_alloc.h"
#include "esp_heap_caps.h" #include "esp_heap_caps.h"
#include "esp_pm.h" #include "esp_pm.h"
@@ -44,7 +46,6 @@ extern "C" {
#define RMT_TX_CHANNEL_OFFSET_IN_GROUP 0 #define RMT_TX_CHANNEL_OFFSET_IN_GROUP 0
#define RMT_RX_CHANNEL_OFFSET_IN_GROUP (SOC_RMT_CHANNELS_PER_GROUP - SOC_RMT_TX_CANDIDATES_PER_GROUP) #define RMT_RX_CHANNEL_OFFSET_IN_GROUP (SOC_RMT_CHANNELS_PER_GROUP - SOC_RMT_TX_CANDIDATES_PER_GROUP)
#define RMT_ALLOW_INTR_PRIORITY_MASK ESP_INTR_FLAG_LOWMED #define RMT_ALLOW_INTR_PRIORITY_MASK ESP_INTR_FLAG_LOWMED
// DMA buffer size must align to `rmt_symbol_word_t` // DMA buffer size must align to `rmt_symbol_word_t`
@@ -52,8 +53,20 @@ extern "C" {
#define RMT_DMA_NODES_PING_PONG 2 // two nodes ping-pong #define RMT_DMA_NODES_PING_PONG 2 // two nodes ping-pong
#define RMT_PM_LOCK_NAME_LEN_MAX 16 #define RMT_PM_LOCK_NAME_LEN_MAX 16
#define RMT_GROUP_INTR_PRIORITY_UNINITIALIZED (-1)
#define RMT_GROUP_INTR_PRIORITY_UNINITALIZED (-1) #if SOC_GDMA_TRIG_PERIPH_RMT0_BUS == SOC_GDMA_BUS_AHB
#define RMT_DMA_DESC_ALIGN 32
typedef dma_descriptor_align4_t rmt_dma_descriptor_t;
#else
#error "Unsupported RMT DMA bus"
#endif
#ifdef CACHE_LL_L2MEM_NON_CACHE_ADDR
#define RMT_GET_NON_CACHE_ADDR(addr) ((addr) ? CACHE_LL_L2MEM_NON_CACHE_ADDR(addr) : 0)
#else
#define RMT_GET_NON_CACHE_ADDR(addr) (addr)
#endif
typedef struct { typedef struct {
struct { struct {
@@ -151,7 +164,8 @@ struct rmt_tx_channel_t {
rmt_tx_trans_desc_t *cur_trans; // points to current transaction rmt_tx_trans_desc_t *cur_trans; // points to current transaction
void *user_data; // user context void *user_data; // user context
rmt_tx_done_callback_t on_trans_done; // callback, invoked on trans done rmt_tx_done_callback_t on_trans_done; // callback, invoked on trans done
dma_descriptor_t dma_nodes[RMT_DMA_NODES_PING_PONG]; // DMA descriptor nodes, make up a circular link list rmt_dma_descriptor_t *dma_nodes; // DMA descriptor nodes
rmt_dma_descriptor_t *dma_nodes_nc; // DMA descriptor nodes accessed in non-cached way
rmt_tx_trans_desc_t trans_desc_pool[]; // transfer descriptor pool rmt_tx_trans_desc_t trans_desc_pool[]; // transfer descriptor pool
}; };
@@ -164,13 +178,14 @@ typedef struct {
struct rmt_rx_channel_t { struct rmt_rx_channel_t {
rmt_channel_t base; // channel base class rmt_channel_t base; // channel base class
size_t mem_off; // starting offset to fetch the symbols in RMTMEM size_t mem_off; // starting offset to fetch the symbols in RMT-MEM
size_t ping_pong_symbols; // ping-pong size (half of the RMT channel memory) size_t ping_pong_symbols; // ping-pong size (half of the RMT channel memory)
rmt_rx_done_callback_t on_recv_done; // callback, invoked on receive done rmt_rx_done_callback_t on_recv_done; // callback, invoked on receive done
void *user_data; // user context void *user_data; // user context
rmt_rx_trans_desc_t trans_desc; // transaction description rmt_rx_trans_desc_t trans_desc; // transaction description
size_t num_dma_nodes; // number of DMA nodes, determined by how big the memory block that user configures size_t num_dma_nodes; // number of DMA nodes, determined by how big the memory block that user configures
dma_descriptor_t dma_nodes[]; // DMA link nodes rmt_dma_descriptor_t *dma_nodes; // DMA link nodes
rmt_dma_descriptor_t *dma_nodes_nc; // DMA descriptor nodes accessed in non-cached way
}; };
/** /**
@@ -201,7 +216,6 @@ 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); esp_err_t rmt_select_periph_clock(rmt_channel_handle_t chan, rmt_clock_source_t clk_src);
/** /**
* @brief Set interrupt priority to RMT group * @brief Set interrupt priority to RMT group
* @param group RMT group to set interrupt priority to * @param group RMT group to set interrupt priority to

View File

@@ -21,10 +21,12 @@
#include "soc/rmt_periph.h" #include "soc/rmt_periph.h"
#include "soc/rtc.h" #include "soc/rtc.h"
#include "hal/rmt_ll.h" #include "hal/rmt_ll.h"
#include "hal/cache_hal.h"
#include "hal/gpio_hal.h" #include "hal/gpio_hal.h"
#include "driver/gpio.h" #include "driver/gpio.h"
#include "driver/rmt_rx.h" #include "driver/rmt_rx.h"
#include "rmt_private.h" #include "rmt_private.h"
#include "rom/cache.h"
#define ALIGN_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1)) #define ALIGN_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1))
@@ -39,26 +41,26 @@ static void rmt_rx_default_isr(void *args);
#if SOC_RMT_SUPPORT_DMA #if SOC_RMT_SUPPORT_DMA
static bool rmt_dma_rx_eof_cb(gdma_channel_handle_t dma_chan, gdma_event_data_t *event_data, void *user_data); static bool rmt_dma_rx_eof_cb(gdma_channel_handle_t dma_chan, gdma_event_data_t *event_data, void *user_data);
static void rmt_rx_mount_dma_buffer(dma_descriptor_t *desc_array, size_t array_size, const void *buffer, size_t buffer_size) static void rmt_rx_mount_dma_buffer(rmt_dma_descriptor_t *desc_array, rmt_dma_descriptor_t *desc_array_nc, size_t array_size, const void *buffer, size_t buffer_size)
{ {
size_t prepared_length = 0; size_t prepared_length = 0;
uint8_t *data = (uint8_t *)buffer; uint8_t *data = (uint8_t *)buffer;
int dma_node_i = 0; int dma_node_i = 0;
dma_descriptor_t *desc = NULL; rmt_dma_descriptor_t *desc = NULL;
while (buffer_size > RMT_DMA_DESC_BUF_MAX_SIZE) { while (buffer_size > RMT_DMA_DESC_BUF_MAX_SIZE) {
desc = &desc_array[dma_node_i]; desc = &desc_array_nc[dma_node_i];
desc->dw0.suc_eof = 0; desc->dw0.suc_eof = 0;
desc->dw0.size = RMT_DMA_DESC_BUF_MAX_SIZE; desc->dw0.size = RMT_DMA_DESC_BUF_MAX_SIZE;
desc->dw0.length = 0; desc->dw0.length = 0;
desc->dw0.owner = DMA_DESCRIPTOR_BUFFER_OWNER_DMA; desc->dw0.owner = DMA_DESCRIPTOR_BUFFER_OWNER_DMA;
desc->buffer = &data[prepared_length]; desc->buffer = &data[prepared_length];
desc->next = &desc_array[dma_node_i + 1]; desc->next = &desc_array[dma_node_i + 1]; // note, we must use the cache address for the "next" pointer
prepared_length += RMT_DMA_DESC_BUF_MAX_SIZE; prepared_length += RMT_DMA_DESC_BUF_MAX_SIZE;
buffer_size -= RMT_DMA_DESC_BUF_MAX_SIZE; buffer_size -= RMT_DMA_DESC_BUF_MAX_SIZE;
dma_node_i++; dma_node_i++;
} }
if (buffer_size) { if (buffer_size) {
desc = &desc_array[dma_node_i]; desc = &desc_array_nc[dma_node_i];
desc->dw0.suc_eof = 0; desc->dw0.suc_eof = 0;
desc->dw0.size = buffer_size; desc->dw0.size = buffer_size;
desc->dw0.length = 0; desc->dw0.length = 0;
@@ -77,11 +79,6 @@ static esp_err_t rmt_rx_init_dma_link(rmt_rx_channel_t *rx_channel, const rmt_rx
#if SOC_GDMA_TRIG_PERIPH_RMT0_BUS == SOC_GDMA_BUS_AHB #if SOC_GDMA_TRIG_PERIPH_RMT0_BUS == SOC_GDMA_BUS_AHB
ESP_RETURN_ON_ERROR(gdma_new_ahb_channel(&dma_chan_config, &rx_channel->base.dma_chan), TAG, "allocate RX DMA channel failed"); ESP_RETURN_ON_ERROR(gdma_new_ahb_channel(&dma_chan_config, &rx_channel->base.dma_chan), TAG, "allocate RX DMA channel failed");
#endif #endif
gdma_strategy_config_t gdma_strategy_conf = {
.auto_update_desc = true,
.owner_check = true,
};
gdma_apply_strategy(rx_channel->base.dma_chan, &gdma_strategy_conf);
gdma_rx_event_callbacks_t cbs = { gdma_rx_event_callbacks_t cbs = {
.on_recv_eof = rmt_dma_rx_eof_cb, .on_recv_eof = rmt_dma_rx_eof_cb,
}; };
@@ -173,6 +170,9 @@ static esp_err_t rmt_rx_destroy(rmt_rx_channel_t *rx_channel)
// de-register channel from RMT group // de-register channel from RMT group
rmt_rx_unregister_from_group(&rx_channel->base, rx_channel->base.group); rmt_rx_unregister_from_group(&rx_channel->base, rx_channel->base.group);
} }
if (rx_channel->dma_nodes) {
free(rx_channel->dma_nodes);
}
free(rx_channel); free(rx_channel);
return ESP_OK; return ESP_OK;
} }
@@ -197,18 +197,21 @@ esp_err_t rmt_new_rx_channel(const rmt_rx_channel_config_t *config, rmt_channel_
ESP_GOTO_ON_FALSE(config->flags.with_dma == 0, ESP_ERR_NOT_SUPPORTED, err, TAG, "DMA not supported"); ESP_GOTO_ON_FALSE(config->flags.with_dma == 0, ESP_ERR_NOT_SUPPORTED, err, TAG, "DMA not supported");
#endif // SOC_RMT_SUPPORT_DMA #endif // SOC_RMT_SUPPORT_DMA
size_t num_dma_nodes = 0;
if (config->flags.with_dma) {
num_dma_nodes = config->mem_block_symbols * sizeof(rmt_symbol_word_t) / RMT_DMA_DESC_BUF_MAX_SIZE + 1;
}
// malloc channel memory // malloc channel memory
uint32_t mem_caps = RMT_MEM_ALLOC_CAPS; uint32_t mem_caps = RMT_MEM_ALLOC_CAPS;
if (config->flags.with_dma) { rx_channel = heap_caps_calloc(1, sizeof(rmt_rx_channel_t), mem_caps);
// DMA descriptors must be placed in internal SRAM
mem_caps |= MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA;
}
rx_channel = heap_caps_calloc(1, sizeof(rmt_rx_channel_t) + num_dma_nodes * sizeof(dma_descriptor_t), mem_caps);
ESP_GOTO_ON_FALSE(rx_channel, ESP_ERR_NO_MEM, err, TAG, "no mem for rx channel"); ESP_GOTO_ON_FALSE(rx_channel, ESP_ERR_NO_MEM, err, TAG, "no mem for rx channel");
// create DMA descriptor
size_t num_dma_nodes = 0;
if (config->flags.with_dma) {
mem_caps |= MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA;
num_dma_nodes = config->mem_block_symbols * sizeof(rmt_symbol_word_t) / RMT_DMA_DESC_BUF_MAX_SIZE + 1;
// DMA descriptors must be placed in internal SRAM
rx_channel->dma_nodes = heap_caps_aligned_calloc(RMT_DMA_DESC_ALIGN, num_dma_nodes, sizeof(rmt_dma_descriptor_t), mem_caps);
ESP_GOTO_ON_FALSE(rx_channel->dma_nodes, ESP_ERR_NO_MEM, err, TAG, "no mem for rx channel DMA nodes");
// we will use the non-cached address to manipulate the DMA descriptor, for simplicity
rx_channel->dma_nodes_nc = (rmt_dma_descriptor_t *)RMT_GET_NON_CACHE_ADDR(rx_channel->dma_nodes);
}
rx_channel->num_dma_nodes = num_dma_nodes; rx_channel->num_dma_nodes = num_dma_nodes;
// register the channel to group // register the channel to group
ESP_GOTO_ON_ERROR(rmt_rx_register_to_group(rx_channel, config), err, TAG, "register channel failed"); ESP_GOTO_ON_ERROR(rmt_rx_register_to_group(rx_channel, config), err, TAG, "register channel failed");
@@ -348,6 +351,12 @@ esp_err_t rmt_receive(rmt_channel_handle_t channel, void *buffer, size_t buffer_
if (channel->dma_chan) { 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(esp_ptr_internal(buffer), ESP_ERR_INVALID_ARG, TAG, "buffer must locate in internal RAM for DMA use");
#if CONFIG_IDF_TARGET_ESP32P4
uint32_t data_cache_line_mask = cache_hal_get_cache_line_size(CACHE_TYPE_DATA) - 1;
ESP_RETURN_ON_FALSE(((uintptr_t)buffer & data_cache_line_mask) == 0, ESP_ERR_INVALID_ARG, TAG, "buffer must be aligned to cache line size");
ESP_RETURN_ON_FALSE((buffer_size & data_cache_line_mask) == 0, ESP_ERR_INVALID_ARG, TAG, "buffer size must be aligned to cache line size");
#endif
} }
if (channel->dma_chan) { if (channel->dma_chan) {
ESP_RETURN_ON_FALSE(buffer_size <= rx_chan->num_dma_nodes * RMT_DMA_DESC_BUF_MAX_SIZE, ESP_RETURN_ON_FALSE(buffer_size <= rx_chan->num_dma_nodes * RMT_DMA_DESC_BUF_MAX_SIZE,
@@ -371,9 +380,9 @@ esp_err_t rmt_receive(rmt_channel_handle_t channel, void *buffer, size_t buffer_
if (channel->dma_chan) { if (channel->dma_chan) {
#if SOC_RMT_SUPPORT_DMA #if SOC_RMT_SUPPORT_DMA
rmt_rx_mount_dma_buffer(rx_chan->dma_nodes, rx_chan->num_dma_nodes, buffer, buffer_size); rmt_rx_mount_dma_buffer(rx_chan->dma_nodes, rx_chan->dma_nodes_nc, rx_chan->num_dma_nodes, buffer, buffer_size);
gdma_reset(channel->dma_chan); gdma_reset(channel->dma_chan);
gdma_start(channel->dma_chan, (intptr_t)rx_chan->dma_nodes); gdma_start(channel->dma_chan, (intptr_t)rx_chan->dma_nodes); // note, we must use the cached descriptor address to start the DMA
#endif #endif
} }
@@ -624,12 +633,12 @@ static void IRAM_ATTR rmt_rx_default_isr(void *args)
} }
#if SOC_RMT_SUPPORT_DMA #if SOC_RMT_SUPPORT_DMA
static size_t IRAM_ATTR rmt_rx_get_received_symbol_num_from_dma(dma_descriptor_t *desc) static size_t IRAM_ATTR rmt_rx_get_received_symbol_num_from_dma(rmt_dma_descriptor_t *desc_nc)
{ {
size_t received_bytes = 0; size_t received_bytes = 0;
while (desc) { while (desc_nc) {
received_bytes += desc->dw0.length; received_bytes += desc_nc->dw0.length;
desc = desc->next; desc_nc = (rmt_dma_descriptor_t *)RMT_GET_NON_CACHE_ADDR(desc_nc->next);
} }
received_bytes = ALIGN_UP(received_bytes, sizeof(rmt_symbol_word_t)); received_bytes = ALIGN_UP(received_bytes, sizeof(rmt_symbol_word_t));
return received_bytes / sizeof(rmt_symbol_word_t); return received_bytes / sizeof(rmt_symbol_word_t);
@@ -650,10 +659,18 @@ 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); rmt_ll_rx_enable(hal->regs, channel_id, false);
portEXIT_CRITICAL_ISR(&channel->spinlock); portEXIT_CRITICAL_ISR(&channel->spinlock);
#if CONFIG_IDF_TARGET_ESP32P4
int invalidate_map = CACHE_MAP_L1_DCACHE;
if (esp_ptr_external_ram((const void *)trans_desc->buffer)) {
invalidate_map |= CACHE_MAP_L2_CACHE;
}
Cache_Invalidate_Addr(invalidate_map, (uint32_t)trans_desc->buffer, trans_desc->buffer_size);
#endif
if (rx_chan->on_recv_done) { if (rx_chan->on_recv_done) {
rmt_rx_done_event_data_t edata = { rmt_rx_done_event_data_t edata = {
.received_symbols = trans_desc->buffer, .received_symbols = trans_desc->buffer,
.num_symbols = rmt_rx_get_received_symbol_num_from_dma(rx_chan->dma_nodes), .num_symbols = rmt_rx_get_received_symbol_num_from_dma(rx_chan->dma_nodes_nc),
}; };
if (rx_chan->on_recv_done(channel, &edata, rx_chan->user_data)) { if (rx_chan->on_recv_done(channel, &edata, rx_chan->user_data)) {
need_yield = true; need_yield = true;

View File

@@ -46,29 +46,26 @@ static bool rmt_dma_tx_eof_cb(gdma_channel_handle_t dma_chan, gdma_event_data_t
static esp_err_t rmt_tx_init_dma_link(rmt_tx_channel_t *tx_channel, const rmt_tx_channel_config_t *config) static esp_err_t rmt_tx_init_dma_link(rmt_tx_channel_t *tx_channel, const rmt_tx_channel_config_t *config)
{ {
rmt_symbol_word_t *dma_mem_base = heap_caps_calloc(1, sizeof(rmt_symbol_word_t) * config->mem_block_symbols, RMT_MEM_ALLOC_CAPS | MALLOC_CAP_DMA); rmt_symbol_word_t *dma_mem_base = heap_caps_calloc(1, sizeof(rmt_symbol_word_t) * config->mem_block_symbols,
RMT_MEM_ALLOC_CAPS | MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL);
ESP_RETURN_ON_FALSE(dma_mem_base, ESP_ERR_NO_MEM, TAG, "no mem for tx DMA buffer"); ESP_RETURN_ON_FALSE(dma_mem_base, ESP_ERR_NO_MEM, TAG, "no mem for tx DMA buffer");
tx_channel->base.dma_mem_base = dma_mem_base; tx_channel->base.dma_mem_base = dma_mem_base;
for (int i = 0; i < RMT_DMA_NODES_PING_PONG; i++) { for (int i = 0; i < RMT_DMA_NODES_PING_PONG; i++) {
// each descriptor shares half of the DMA buffer // each descriptor shares half of the DMA buffer
tx_channel->dma_nodes[i].buffer = dma_mem_base + tx_channel->ping_pong_symbols * i; tx_channel->dma_nodes_nc[i].buffer = dma_mem_base + tx_channel->ping_pong_symbols * i;
tx_channel->dma_nodes[i].dw0.size = tx_channel->ping_pong_symbols * sizeof(rmt_symbol_word_t); tx_channel->dma_nodes_nc[i].dw0.size = tx_channel->ping_pong_symbols * sizeof(rmt_symbol_word_t);
// the ownership will be switched to DMA in `rmt_tx_do_transaction()` // the ownership will be switched to DMA in `rmt_tx_do_transaction()`
tx_channel->dma_nodes[i].dw0.owner = DMA_DESCRIPTOR_BUFFER_OWNER_CPU; tx_channel->dma_nodes_nc[i].dw0.owner = DMA_DESCRIPTOR_BUFFER_OWNER_CPU;
// each node can generate the DMA eof interrupt, and the driver will do a ping-pong trick in the eof callback // each node can generate the DMA eof interrupt, and the driver will do a ping-pong trick in the eof callback
tx_channel->dma_nodes[i].dw0.suc_eof = 1; tx_channel->dma_nodes_nc[i].dw0.suc_eof = 1;
} }
gdma_channel_alloc_config_t dma_chan_config = { gdma_channel_alloc_config_t dma_chan_config = {
.direction = GDMA_CHANNEL_DIRECTION_TX, .direction = GDMA_CHANNEL_DIRECTION_TX,
}; };
#if SOC_GDMA_TRIG_PERIPH_RMT0_BUS == SOC_GDMA_BUS_AHB #if SOC_GDMA_TRIG_PERIPH_RMT0_BUS == SOC_GDMA_BUS_AHB
ESP_RETURN_ON_ERROR(gdma_new_ahb_channel(&dma_chan_config, &tx_channel->base.dma_chan), TAG, "allocate TX DMA channel failed"); ESP_RETURN_ON_ERROR(gdma_new_ahb_channel(&dma_chan_config, &tx_channel->base.dma_chan), TAG, "allocate TX DMA channel failed");
#endif #endif
gdma_strategy_config_t gdma_strategy_conf = {
.auto_update_desc = true,
.owner_check = true,
};
gdma_apply_strategy(tx_channel->base.dma_chan, &gdma_strategy_conf);
gdma_tx_event_callbacks_t cbs = { gdma_tx_event_callbacks_t cbs = {
.on_trans_eof = rmt_dma_tx_eof_cb, .on_trans_eof = rmt_dma_tx_eof_cb,
}; };
@@ -199,6 +196,9 @@ static esp_err_t rmt_tx_destroy(rmt_tx_channel_t *tx_channel)
// de-register channel from RMT group // de-register channel from RMT group
rmt_tx_unregister_from_group(&tx_channel->base, tx_channel->base.group); rmt_tx_unregister_from_group(&tx_channel->base, tx_channel->base.group);
} }
if (tx_channel->dma_nodes) {
free(tx_channel->dma_nodes);
}
free(tx_channel); free(tx_channel);
return ESP_OK; return ESP_OK;
} }
@@ -231,12 +231,17 @@ esp_err_t rmt_new_tx_channel(const rmt_tx_channel_config_t *config, rmt_channel_
// malloc channel memory // malloc channel memory
uint32_t mem_caps = RMT_MEM_ALLOC_CAPS; uint32_t mem_caps = RMT_MEM_ALLOC_CAPS;
tx_channel = heap_caps_calloc(1, sizeof(rmt_tx_channel_t) + sizeof(rmt_tx_trans_desc_t) * config->trans_queue_depth, mem_caps);
ESP_GOTO_ON_FALSE(tx_channel, ESP_ERR_NO_MEM, err, TAG, "no mem for tx channel");
// create DMA descriptors
if (config->flags.with_dma) { if (config->flags.with_dma) {
// DMA descriptors must be placed in internal SRAM // DMA descriptors must be placed in internal SRAM
mem_caps |= MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA; mem_caps |= MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA;
tx_channel->dma_nodes = heap_caps_aligned_calloc(RMT_DMA_DESC_ALIGN, RMT_DMA_NODES_PING_PONG, sizeof(rmt_dma_descriptor_t), mem_caps);
ESP_GOTO_ON_FALSE(tx_channel->dma_nodes, ESP_ERR_NO_MEM, err, TAG, "no mem for tx DMA nodes");
// we will use the non-cached address to manipulate the DMA descriptor, for simplicity
tx_channel->dma_nodes_nc = (rmt_dma_descriptor_t *)RMT_GET_NON_CACHE_ADDR(tx_channel->dma_nodes);
} }
tx_channel = heap_caps_calloc(1, sizeof(rmt_tx_channel_t) + sizeof(rmt_tx_trans_desc_t) * config->trans_queue_depth, mem_caps);
ESP_GOTO_ON_FALSE(tx_channel, ESP_ERR_NO_MEM, err, TAG, "no mem for tx channel");
// create transaction queues // create transaction queues
ESP_GOTO_ON_ERROR(rmt_tx_create_trans_queue(tx_channel, config), err, TAG, "install trans queues failed"); ESP_GOTO_ON_ERROR(rmt_tx_create_trans_queue(tx_channel, config), err, TAG, "install trans queues failed");
// register the channel to group // register the channel to group
@@ -318,9 +323,9 @@ esp_err_t rmt_new_tx_channel(const rmt_tx_channel_config_t *config, rmt_channel_
tx_channel->base.disable = rmt_tx_disable; tx_channel->base.disable = rmt_tx_disable;
// return general channel handle // return general channel handle
*ret_chan = &tx_channel->base; *ret_chan = &tx_channel->base;
ESP_LOGD(TAG, "new tx channel(%d,%d) at %p, gpio=%d, res=%"PRIu32"Hz, hw_mem_base=%p, dma_mem_base=%p, ping_pong_size=%zu, queue_depth=%zu", ESP_LOGD(TAG, "new tx channel(%d,%d) at %p, gpio=%d, res=%"PRIu32"Hz, hw_mem_base=%p, dma_mem_base=%p, dma_nodes_nc=%p,ping_pong_size=%zu, queue_depth=%zu",
group_id, channel_id, tx_channel, config->gpio_num, tx_channel->base.resolution_hz, group_id, channel_id, tx_channel, config->gpio_num, tx_channel->base.resolution_hz,
tx_channel->base.hw_mem_base, tx_channel->base.dma_mem_base, tx_channel->ping_pong_symbols, tx_channel->queue_size); tx_channel->base.hw_mem_base, tx_channel->base.dma_mem_base, tx_channel->dma_nodes_nc, tx_channel->ping_pong_symbols, tx_channel->queue_size);
return ESP_OK; return ESP_OK;
err: err:
@@ -548,12 +553,17 @@ static void IRAM_ATTR rmt_tx_mark_eof(rmt_tx_channel_t *tx_chan)
rmt_channel_t *channel = &tx_chan->base; rmt_channel_t *channel = &tx_chan->base;
rmt_group_t *group = channel->group; rmt_group_t *group = channel->group;
int channel_id = channel->channel_id; int channel_id = channel->channel_id;
rmt_symbol_word_t *mem_to = channel->dma_chan ? channel->dma_mem_base : channel->hw_mem_base; rmt_symbol_word_t *mem_to_nc = NULL;
rmt_tx_trans_desc_t *cur_trans = tx_chan->cur_trans; rmt_tx_trans_desc_t *cur_trans = tx_chan->cur_trans;
dma_descriptor_t *desc = NULL; rmt_dma_descriptor_t *desc_nc = NULL;
if (channel->dma_chan) {
mem_to_nc = (rmt_symbol_word_t *)RMT_GET_NON_CACHE_ADDR(channel->dma_mem_base);
} else {
mem_to_nc = channel->hw_mem_base;
}
// a RMT word whose duration is zero means a "stop" pattern // a RMT word whose duration is zero means a "stop" pattern
mem_to[tx_chan->mem_off++] = (rmt_symbol_word_t) { mem_to_nc[tx_chan->mem_off++] = (rmt_symbol_word_t) {
.duration0 = 0, .duration0 = 0,
.level0 = cur_trans->flags.eot_level, .level0 = cur_trans->flags.eot_level,
.duration1 = 0, .duration1 = 0,
@@ -563,16 +573,16 @@ static void IRAM_ATTR rmt_tx_mark_eof(rmt_tx_channel_t *tx_chan)
size_t off = 0; size_t off = 0;
if (channel->dma_chan) { if (channel->dma_chan) {
if (tx_chan->mem_off <= tx_chan->ping_pong_symbols) { if (tx_chan->mem_off <= tx_chan->ping_pong_symbols) {
desc = &tx_chan->dma_nodes[0]; desc_nc = &tx_chan->dma_nodes_nc[0];
off = tx_chan->mem_off; off = tx_chan->mem_off;
} else { } else {
desc = &tx_chan->dma_nodes[1]; desc_nc = &tx_chan->dma_nodes_nc[1];
off = tx_chan->mem_off - tx_chan->ping_pong_symbols; off = tx_chan->mem_off - tx_chan->ping_pong_symbols;
} }
desc->dw0.owner = DMA_DESCRIPTOR_BUFFER_OWNER_DMA; desc_nc->dw0.owner = DMA_DESCRIPTOR_BUFFER_OWNER_DMA;
desc->dw0.length = off * sizeof(rmt_symbol_word_t); desc_nc->dw0.length = off * sizeof(rmt_symbol_word_t);
// break down the DMA descriptor link // break down the DMA descriptor link
desc->next = NULL; desc_nc->next = NULL;
} else { } else {
portENTER_CRITICAL_ISR(&group->spinlock); portENTER_CRITICAL_ISR(&group->spinlock);
// This is the end of a sequence of encoding sessions, disable the threshold interrupt as no more data will be put into RMT memory block // This is the end of a sequence of encoding sessions, disable the threshold interrupt as no more data will be put into RMT memory block
@@ -586,6 +596,7 @@ static size_t IRAM_ATTR rmt_encode_check_result(rmt_tx_channel_t *tx_chan, rmt_t
rmt_encode_state_t encode_state = RMT_ENCODING_RESET; rmt_encode_state_t encode_state = RMT_ENCODING_RESET;
rmt_encoder_handle_t encoder = t->encoder; rmt_encoder_handle_t encoder = t->encoder;
size_t encoded_symbols = encoder->encode(encoder, &tx_chan->base, t->payload, t->payload_bytes, &encode_state); size_t encoded_symbols = encoder->encode(encoder, &tx_chan->base, t->payload, t->payload_bytes, &encode_state);
if (encode_state & RMT_ENCODING_COMPLETE) { if (encode_state & RMT_ENCODING_COMPLETE) {
t->flags.encoding_done = true; t->flags.encoding_done = true;
// inserting EOF symbol if there's extra space // inserting EOF symbol if there's extra space
@@ -615,12 +626,12 @@ static void IRAM_ATTR rmt_tx_do_transaction(rmt_tx_channel_t *tx_chan, rmt_tx_tr
#if SOC_RMT_SUPPORT_DMA #if SOC_RMT_SUPPORT_DMA
if (channel->dma_chan) { if (channel->dma_chan) {
gdma_reset(channel->dma_chan); gdma_reset(channel->dma_chan);
// chain the descritpros into a ring, and will break it in `rmt_encode_eof()` // chain the descriptors into a ring, and will break it in `rmt_encode_eof()`
for (int i = 0; i < RMT_DMA_NODES_PING_PONG; i++) { for (int i = 0; i < RMT_DMA_NODES_PING_PONG; i++) {
tx_chan->dma_nodes[i].next = &tx_chan->dma_nodes[i + 1]; tx_chan->dma_nodes_nc[i].next = &tx_chan->dma_nodes[i + 1]; // note, we must use the cache address for the next pointer
tx_chan->dma_nodes[i].dw0.owner = DMA_DESCRIPTOR_BUFFER_OWNER_CPU; tx_chan->dma_nodes_nc[i].dw0.owner = DMA_DESCRIPTOR_BUFFER_OWNER_CPU;
} }
tx_chan->dma_nodes[1].next = &tx_chan->dma_nodes[0]; tx_chan->dma_nodes_nc[1].next = &tx_chan->dma_nodes[0];
} }
#endif // SOC_RMT_SUPPORT_DMA #endif // SOC_RMT_SUPPORT_DMA
@@ -672,7 +683,7 @@ static void IRAM_ATTR rmt_tx_do_transaction(rmt_tx_channel_t *tx_chan, rmt_tx_tr
#if SOC_RMT_SUPPORT_DMA #if SOC_RMT_SUPPORT_DMA
if (channel->dma_chan) { if (channel->dma_chan) {
gdma_start(channel->dma_chan, (intptr_t)tx_chan->dma_nodes); gdma_start(channel->dma_chan, (intptr_t)tx_chan->dma_nodes); // note, we must use the cached descriptor address to start the DMA
// delay a while, wait for DMA data going to RMT memory block // delay a while, wait for DMA data going to RMT memory block
esp_rom_delay_us(1); esp_rom_delay_us(1);
} }
@@ -1040,10 +1051,13 @@ static void IRAM_ATTR rmt_tx_default_isr(void *args)
static bool IRAM_ATTR rmt_dma_tx_eof_cb(gdma_channel_handle_t dma_chan, gdma_event_data_t *event_data, void *user_data) static bool IRAM_ATTR rmt_dma_tx_eof_cb(gdma_channel_handle_t dma_chan, gdma_event_data_t *event_data, void *user_data)
{ {
rmt_tx_channel_t *tx_chan = (rmt_tx_channel_t *)user_data; rmt_tx_channel_t *tx_chan = (rmt_tx_channel_t *)user_data;
dma_descriptor_t *eof_desc = (dma_descriptor_t *)event_data->tx_eof_desc_addr; rmt_dma_descriptor_t *eof_desc_nc = (rmt_dma_descriptor_t *)RMT_GET_NON_CACHE_ADDR(event_data->tx_eof_desc_addr);
rmt_dma_descriptor_t *n = (rmt_dma_descriptor_t *)RMT_GET_NON_CACHE_ADDR(eof_desc_nc->next); // next points to a cache address, needs to convert it to a non-cached one
if (n) {
rmt_dma_descriptor_t *nn = (rmt_dma_descriptor_t *)RMT_GET_NON_CACHE_ADDR(n->next);
// if the DMA descriptor link is still a ring (i.e. hasn't broken down by `rmt_tx_mark_eof()`), then we treat it as a valid ping-pong event // if the DMA descriptor link is still a ring (i.e. hasn't broken down by `rmt_tx_mark_eof()`), then we treat it as a valid ping-pong event
if (eof_desc->next && eof_desc->next->next) { if (nn) {
// continue pingpong transmission // continue ping-pong transmission
rmt_tx_trans_desc_t *t = tx_chan->cur_trans; rmt_tx_trans_desc_t *t = tx_chan->cur_trans;
size_t encoded_symbols = t->transmitted_symbol_num; size_t encoded_symbols = t->transmitted_symbol_num;
if (t->flags.encoding_done) { if (t->flags.encoding_done) {
@@ -1057,6 +1071,7 @@ static bool IRAM_ATTR rmt_dma_tx_eof_cb(gdma_channel_handle_t dma_chan, gdma_eve
// tell DMA that we have a new descriptor attached // tell DMA that we have a new descriptor attached
gdma_append(dma_chan); gdma_append(dma_chan);
} }
}
return false; return false;
} }
#endif // SOC_RMT_SUPPORT_DMA #endif // SOC_RMT_SUPPORT_DMA

View File

@@ -1,2 +1,2 @@
| Supported Targets | ESP32 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S2 | ESP32-S3 | | Supported Targets | ESP32 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | | ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- |

View File

@@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@@ -17,6 +17,7 @@
#include "esp_rom_gpio.h" #include "esp_rom_gpio.h"
#include "ir_tools.h" #include "ir_tools.h"
#include "driver/rmt.h" #include "driver/rmt.h"
#include "soc/rmt_periph.h"
#define RMT_RX_CHANNEL_ENCODING_START (SOC_RMT_CHANNELS_PER_GROUP-SOC_RMT_TX_CANDIDATES_PER_GROUP) #define RMT_RX_CHANNEL_ENCODING_START (SOC_RMT_CHANNELS_PER_GROUP-SOC_RMT_TX_CANDIDATES_PER_GROUP)
#define RMT_TX_CHANNEL_ENCODING_END (SOC_RMT_TX_CANDIDATES_PER_GROUP-1) #define RMT_TX_CHANNEL_ENCODING_END (SOC_RMT_TX_CANDIDATES_PER_GROUP-1)
@@ -72,8 +73,12 @@ static void rmt_setup_testbench(int tx_channel, int rx_channel, uint32_t flags)
// Routing internal signals by IO Matrix (bind rmt tx and rx signal on the same GPIO) // Routing internal signals by IO Matrix (bind rmt tx and rx signal on the same GPIO)
gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[RMT_DATA_IO], PIN_FUNC_GPIO); gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[RMT_DATA_IO], PIN_FUNC_GPIO);
TEST_ESP_OK(gpio_set_direction(RMT_DATA_IO, GPIO_MODE_INPUT_OUTPUT)); TEST_ESP_OK(gpio_set_direction(RMT_DATA_IO, GPIO_MODE_INPUT_OUTPUT));
esp_rom_gpio_connect_out_signal(RMT_DATA_IO, RMT_SIG_OUT0_IDX + tx_channel, 0, 0); if (tx_channel >= 0) {
esp_rom_gpio_connect_in_signal(RMT_DATA_IO, RMT_SIG_IN0_IDX + rx_channel, 0); esp_rom_gpio_connect_out_signal(RMT_DATA_IO, rmt_periph_signals.groups[0].channels[tx_channel].tx_sig, 0, 0);
}
if (rx_channel >= 0) {
esp_rom_gpio_connect_in_signal(RMT_DATA_IO, rmt_periph_signals.groups[0].channels[rx_channel].rx_sig, 0);
}
// install driver // install driver
if (tx_channel >= 0) { if (tx_channel >= 0) {
@@ -161,7 +166,6 @@ TEST_CASE("RMT miscellaneous functions", "[rmt]")
TEST_ASSERT_EQUAL_INT(RMT_BASECLK_XTAL, src_clk); TEST_ASSERT_EQUAL_INT(RMT_BASECLK_XTAL, src_clk);
#endif #endif
TEST_ESP_OK(rmt_set_tx_carrier(channel, 0, 10, 10, 1)); TEST_ESP_OK(rmt_set_tx_carrier(channel, 0, 10, 10, 1));
TEST_ESP_OK(rmt_set_idle_level(channel, 1, 0)); TEST_ESP_OK(rmt_set_idle_level(channel, 1, 0));

View File

@@ -1,2 +1,2 @@
| Supported Targets | ESP32 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S2 | ESP32-S3 | | Supported Targets | ESP32 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | | ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- |

View File

@@ -0,0 +1,9 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#define TEST_RMT_GPIO_NUM_A 0
#define TEST_RMT_GPIO_NUM_B 2

View File

@@ -12,12 +12,13 @@
#include "driver/rmt_tx.h" #include "driver/rmt_tx.h"
#include "driver/rmt_rx.h" #include "driver/rmt_rx.h"
#include "soc/soc_caps.h" #include "soc/soc_caps.h"
#include "test_board.h"
TEST_CASE("rmt channel install & uninstall", "[rmt]") TEST_CASE("rmt channel install & uninstall", "[rmt]")
{ {
rmt_tx_channel_config_t tx_channel_cfg = { rmt_tx_channel_config_t tx_channel_cfg = {
.mem_block_symbols = SOC_RMT_MEM_WORDS_PER_CHANNEL, .mem_block_symbols = SOC_RMT_MEM_WORDS_PER_CHANNEL,
.gpio_num = 0, .gpio_num = TEST_RMT_GPIO_NUM_A,
.clk_src = RMT_CLK_SRC_DEFAULT, .clk_src = RMT_CLK_SRC_DEFAULT,
.resolution_hz = 1000000, .resolution_hz = 1000000,
.trans_queue_depth = 1, .trans_queue_depth = 1,
@@ -25,7 +26,7 @@ TEST_CASE("rmt channel install & uninstall", "[rmt]")
rmt_channel_handle_t tx_channels[SOC_RMT_TX_CANDIDATES_PER_GROUP] = {}; rmt_channel_handle_t tx_channels[SOC_RMT_TX_CANDIDATES_PER_GROUP] = {};
rmt_rx_channel_config_t rx_channel_cfg = { rmt_rx_channel_config_t rx_channel_cfg = {
.mem_block_symbols = SOC_RMT_MEM_WORDS_PER_CHANNEL, .mem_block_symbols = SOC_RMT_MEM_WORDS_PER_CHANNEL,
.gpio_num = 2, .gpio_num = TEST_RMT_GPIO_NUM_B,
.clk_src = RMT_CLK_SRC_DEFAULT, .clk_src = RMT_CLK_SRC_DEFAULT,
.resolution_hz = 1000000, .resolution_hz = 1000000,
}; };
@@ -98,3 +99,60 @@ TEST_CASE("rmt channel install & uninstall", "[rmt]")
} }
#endif // SOC_RMT_SUPPORT_DMA #endif // SOC_RMT_SUPPORT_DMA
} }
TEST_CASE("RMT interrupt priority", "[rmt]")
{
rmt_tx_channel_config_t tx_channel_cfg = {
.mem_block_symbols = SOC_RMT_MEM_WORDS_PER_CHANNEL,
.clk_src = RMT_CLK_SRC_DEFAULT,
.resolution_hz = 1000000, // 1MHz, 1 tick = 1us
.trans_queue_depth = 4,
.gpio_num = 0,
.intr_priority = 3
};
// --- Check if specifying interrupt priority works
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));
rmt_channel_handle_t another_tx_channel = NULL;
rmt_tx_channel_config_t another_tx_channel_cfg = tx_channel_cfg;
// --- Check if rmt interrupt priority valid check works
another_tx_channel_cfg.intr_priority = 4;
TEST_ESP_ERR(rmt_new_tx_channel(&another_tx_channel_cfg, &another_tx_channel), ESP_ERR_INVALID_ARG);
// --- Check if rmt interrupt priority conflict check works
another_tx_channel_cfg.intr_priority = 1; ///< Specifying a conflict intr_priority
TEST_ESP_ERR(rmt_new_tx_channel(&another_tx_channel_cfg, &another_tx_channel), ESP_ERR_INVALID_ARG);
another_tx_channel_cfg.intr_priority = 0; ///< Do not specify an intr_priority, should not conflict
TEST_ESP_OK(rmt_new_tx_channel(&another_tx_channel_cfg, &another_tx_channel));
rmt_rx_channel_config_t rx_channel_cfg = {
.mem_block_symbols = SOC_RMT_MEM_WORDS_PER_CHANNEL,
.clk_src = RMT_CLK_SRC_DEFAULT,
.resolution_hz = 1000000, // 1MHz, 1 tick = 1us
.gpio_num = 0,
.flags.with_dma = false, // Interrupt will only be allocated when dma disabled
.flags.io_loop_back = true, // the GPIO will act like a loopback
.intr_priority = 3,
};
// --- Check if specifying interrupt priority works
printf("install rx channel\r\n");
rmt_channel_handle_t rx_channel = NULL;
TEST_ESP_OK(rmt_new_rx_channel(&rx_channel_cfg, &rx_channel));
rmt_channel_handle_t another_rx_channel = NULL;
rmt_rx_channel_config_t another_rx_channel_cfg = rx_channel_cfg;
// --- Check if rmt interrupt priority valid check works
another_rx_channel_cfg.intr_priority = 4; ///< Specifying a invalid intr_priority
TEST_ESP_ERR(rmt_new_rx_channel(&another_rx_channel_cfg, &another_rx_channel), ESP_ERR_INVALID_ARG);
// --- Check if rmt interrupt priority conflict check works
another_rx_channel_cfg.intr_priority = 1; ///< Specifying a conflict intr_priority
TEST_ESP_ERR(rmt_new_rx_channel(&another_rx_channel_cfg, &another_rx_channel), ESP_ERR_INVALID_ARG);
another_rx_channel_cfg.intr_priority = 0; ///< Do not specify an intr_priority, should not conflict
TEST_ESP_OK(rmt_new_rx_channel(&another_rx_channel_cfg, &another_rx_channel));
TEST_ESP_OK(rmt_del_channel(tx_channel));
TEST_ESP_OK(rmt_del_channel(another_tx_channel));
TEST_ESP_OK(rmt_del_channel(rx_channel));
TEST_ESP_OK(rmt_del_channel(another_rx_channel));
}

View File

@@ -16,6 +16,7 @@
#include "esp_timer.h" #include "esp_timer.h"
#include "soc/soc_caps.h" #include "soc/soc_caps.h"
#include "test_util_rmt_encoders.h" #include "test_util_rmt_encoders.h"
#include "test_board.h"
static void IRAM_ATTR test_delay_post_cache_disable(void *args) static void IRAM_ATTR test_delay_post_cache_disable(void *args)
{ {
@@ -29,7 +30,7 @@ static void test_rmt_tx_iram_safe(size_t mem_block_symbols, bool with_dma)
.clk_src = RMT_CLK_SRC_DEFAULT, .clk_src = RMT_CLK_SRC_DEFAULT,
.resolution_hz = 10000000, // 10MHz, 1 tick = 0.1us (led strip needs a high resolution) .resolution_hz = 10000000, // 10MHz, 1 tick = 0.1us (led strip needs a high resolution)
.trans_queue_depth = 4, .trans_queue_depth = 4,
.gpio_num = 0, .gpio_num = TEST_RMT_GPIO_NUM_A,
.flags.with_dma = with_dma, .flags.with_dma = with_dma,
}; };
printf("install tx channel\r\n"); printf("install tx channel\r\n");
@@ -86,8 +87,6 @@ TEST_CASE("rmt tx iram safe", "[rmt]")
#endif #endif
} }
static void IRAM_ATTR test_simulate_input_post_cache_disable(void *args) static void IRAM_ATTR test_simulate_input_post_cache_disable(void *args)
{ {
int gpio_num = (int)args; int gpio_num = (int)args;
@@ -121,7 +120,7 @@ static void test_rmt_rx_iram_safe(size_t mem_block_symbols, bool with_dma, rmt_c
.clk_src = clk_src, .clk_src = clk_src,
.resolution_hz = 1000000, // 1MHz, 1 tick = 1us .resolution_hz = 1000000, // 1MHz, 1 tick = 1us
.mem_block_symbols = mem_block_symbols, .mem_block_symbols = mem_block_symbols,
.gpio_num = 0, .gpio_num = TEST_RMT_GPIO_NUM_A,
.flags.with_dma = with_dma, .flags.with_dma = with_dma,
.flags.io_loop_back = true, // the GPIO will act like a loopback .flags.io_loop_back = true, // the GPIO will act like a loopback
}; };

View File

@@ -13,6 +13,7 @@
#include "driver/rmt_rx.h" #include "driver/rmt_rx.h"
#include "soc/soc_caps.h" #include "soc/soc_caps.h"
#include "test_util_rmt_encoders.h" #include "test_util_rmt_encoders.h"
#include "test_board.h"
#if CONFIG_RMT_ISR_IRAM_SAFE #if CONFIG_RMT_ISR_IRAM_SAFE
#define TEST_RMT_CALLBACK_ATTR IRAM_ATTR #define TEST_RMT_CALLBACK_ATTR IRAM_ATTR
@@ -42,11 +43,16 @@ static bool test_rmt_rx_done_callback(rmt_channel_handle_t channel, const rmt_rx
static void test_rmt_rx_nec_carrier(size_t mem_block_symbols, bool with_dma, rmt_clock_source_t clk_src) static void test_rmt_rx_nec_carrier(size_t mem_block_symbols, bool with_dma, rmt_clock_source_t clk_src)
{ {
uint32_t const test_rx_buffer_symbols = 128;
rmt_symbol_word_t *remote_codes = heap_caps_aligned_calloc(64, test_rx_buffer_symbols, sizeof(rmt_symbol_word_t),
MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA);
TEST_ASSERT_NOT_NULL(remote_codes);
rmt_rx_channel_config_t rx_channel_cfg = { rmt_rx_channel_config_t rx_channel_cfg = {
.clk_src = clk_src, .clk_src = clk_src,
.resolution_hz = 1000000, // 1MHz, 1 tick = 1us .resolution_hz = 1000000, // 1MHz, 1 tick = 1us
.mem_block_symbols = mem_block_symbols, .mem_block_symbols = mem_block_symbols,
.gpio_num = 0, .gpio_num = TEST_RMT_GPIO_NUM_A,
.flags.with_dma = with_dma, .flags.with_dma = with_dma,
.flags.io_loop_back = true, // the GPIO will act like a loopback .flags.io_loop_back = true, // the GPIO will act like a loopback
}; };
@@ -67,7 +73,7 @@ static void test_rmt_rx_nec_carrier(size_t mem_block_symbols, bool with_dma, rmt
.resolution_hz = 1000000, // 1MHz, 1 tick = 1us .resolution_hz = 1000000, // 1MHz, 1 tick = 1us
.mem_block_symbols = SOC_RMT_MEM_WORDS_PER_CHANNEL, .mem_block_symbols = SOC_RMT_MEM_WORDS_PER_CHANNEL,
.trans_queue_depth = 4, .trans_queue_depth = 4,
.gpio_num = 0, .gpio_num = TEST_RMT_GPIO_NUM_A,
.flags.io_loop_back = true, // TX channel and RX channel will bounded to the same GPIO .flags.io_loop_back = true, // TX channel and RX channel will bounded to the same GPIO
}; };
printf("install tx channel\r\n"); printf("install tx channel\r\n");
@@ -86,15 +92,13 @@ static void test_rmt_rx_nec_carrier(size_t mem_block_symbols, bool with_dma, rmt
printf("enable rx channel\r\n"); printf("enable rx channel\r\n");
TEST_ESP_OK(rmt_enable(rx_channel)); TEST_ESP_OK(rmt_enable(rx_channel));
rmt_symbol_word_t remote_codes[128];
rmt_receive_config_t receive_config = { rmt_receive_config_t receive_config = {
.signal_range_min_ns = 1250, .signal_range_min_ns = 1250,
.signal_range_max_ns = 12000000, .signal_range_max_ns = 12000000,
}; };
// ready to receive // ready to receive
TEST_ESP_OK(rmt_receive(rx_channel, remote_codes, sizeof(remote_codes), &receive_config)); TEST_ESP_OK(rmt_receive(rx_channel, remote_codes, test_rx_buffer_symbols * sizeof(rmt_symbol_word_t), &receive_config));
printf("send NEC frame without carrier\r\n"); printf("send NEC frame without carrier\r\n");
TEST_ESP_OK(rmt_transmit(tx_channel, nec_encoder, (uint16_t[]) { TEST_ESP_OK(rmt_transmit(tx_channel, nec_encoder, (uint16_t[]) {
0x0440, 0x3003 // address, command 0x0440, 0x3003 // address, command
@@ -102,7 +106,7 @@ static void test_rmt_rx_nec_carrier(size_t mem_block_symbols, bool with_dma, rmt
TEST_ASSERT_NOT_EQUAL(0, ulTaskNotifyTake(pdFALSE, pdMS_TO_TICKS(1000))); TEST_ASSERT_NOT_EQUAL(0, ulTaskNotifyTake(pdFALSE, pdMS_TO_TICKS(1000)));
TEST_ASSERT_EQUAL(34, test_user_data.received_symbol_num); TEST_ASSERT_EQUAL(34, test_user_data.received_symbol_num);
TEST_ESP_OK(rmt_receive(rx_channel, remote_codes, sizeof(remote_codes), &receive_config)); TEST_ESP_OK(rmt_receive(rx_channel, remote_codes, test_rx_buffer_symbols * sizeof(rmt_symbol_word_t), &receive_config));
printf("send NEC frame without carrier\r\n"); printf("send NEC frame without carrier\r\n");
TEST_ESP_OK(rmt_transmit(tx_channel, nec_encoder, (uint16_t[]) { TEST_ESP_OK(rmt_transmit(tx_channel, nec_encoder, (uint16_t[]) {
0x0440, 0x3003 // address, command 0x0440, 0x3003 // address, command
@@ -112,7 +116,7 @@ static void test_rmt_rx_nec_carrier(size_t mem_block_symbols, bool with_dma, rmt
#if SOC_RMT_SUPPORT_RX_PINGPONG #if SOC_RMT_SUPPORT_RX_PINGPONG
// ready to receive // ready to receive
TEST_ESP_OK(rmt_receive(rx_channel, remote_codes, sizeof(remote_codes), &receive_config)); TEST_ESP_OK(rmt_receive(rx_channel, remote_codes, test_rx_buffer_symbols * sizeof(rmt_symbol_word_t), &receive_config));
printf("send customized NEC frame without carrier\r\n"); printf("send customized NEC frame without carrier\r\n");
TEST_ESP_OK(rmt_transmit(tx_channel, nec_encoder, (uint16_t[]) { TEST_ESP_OK(rmt_transmit(tx_channel, nec_encoder, (uint16_t[]) {
0xFF00, 0xFF00, 0xFF00, 0xFF00 0xFF00, 0xFF00, 0xFF00, 0xFF00
@@ -121,7 +125,7 @@ static void test_rmt_rx_nec_carrier(size_t mem_block_symbols, bool with_dma, rmt
TEST_ASSERT_EQUAL(66, test_user_data.received_symbol_num); TEST_ASSERT_EQUAL(66, test_user_data.received_symbol_num);
#else #else
// ready to receive // ready to receive
TEST_ESP_OK(rmt_receive(rx_channel, remote_codes, sizeof(remote_codes), &receive_config)); TEST_ESP_OK(rmt_receive(rx_channel, remote_codes, test_rx_buffer_symbols * sizeof(rmt_symbol_word_t), &receive_config));
printf("send customized NEC frame without carrier\r\n"); printf("send customized NEC frame without carrier\r\n");
// the maximum symbols can receive is its memory block capacity // the maximum symbols can receive is its memory block capacity
TEST_ESP_OK(rmt_transmit(tx_channel, nec_encoder, (uint16_t[]) { TEST_ESP_OK(rmt_transmit(tx_channel, nec_encoder, (uint16_t[]) {
@@ -144,7 +148,7 @@ static void test_rmt_rx_nec_carrier(size_t mem_block_symbols, bool with_dma, rmt
carrier_cfg.frequency_hz = 25000; carrier_cfg.frequency_hz = 25000;
TEST_ESP_OK(rmt_apply_carrier(rx_channel, &carrier_cfg)); TEST_ESP_OK(rmt_apply_carrier(rx_channel, &carrier_cfg));
TEST_ESP_OK(rmt_receive(rx_channel, remote_codes, sizeof(remote_codes), &receive_config)); TEST_ESP_OK(rmt_receive(rx_channel, remote_codes, test_rx_buffer_symbols * sizeof(rmt_symbol_word_t), &receive_config));
printf("send NEC frame with carrier\r\n"); printf("send NEC frame with carrier\r\n");
TEST_ESP_OK(rmt_transmit(tx_channel, nec_encoder, (uint16_t[]) { TEST_ESP_OK(rmt_transmit(tx_channel, nec_encoder, (uint16_t[]) {
0x0440, 0x3003 // address, command 0x0440, 0x3003 // address, command
@@ -153,7 +157,7 @@ static void test_rmt_rx_nec_carrier(size_t mem_block_symbols, bool with_dma, rmt
TEST_ASSERT_EQUAL(34, test_user_data.received_symbol_num); TEST_ASSERT_EQUAL(34, test_user_data.received_symbol_num);
#if SOC_RMT_SUPPORT_RX_PINGPONG #if SOC_RMT_SUPPORT_RX_PINGPONG
TEST_ESP_OK(rmt_receive(rx_channel, remote_codes, sizeof(remote_codes), &receive_config)); TEST_ESP_OK(rmt_receive(rx_channel, remote_codes, test_rx_buffer_symbols * sizeof(rmt_symbol_word_t), &receive_config));
printf("send customized frame with carrier\r\n"); printf("send customized frame with carrier\r\n");
TEST_ESP_OK(rmt_transmit(tx_channel, nec_encoder, (uint16_t[]) { TEST_ESP_OK(rmt_transmit(tx_channel, nec_encoder, (uint16_t[]) {
0xFF00, 0xFF00, 0xFF00, 0xFF00 0xFF00, 0xFF00, 0xFF00, 0xFF00
@@ -167,7 +171,7 @@ static void test_rmt_rx_nec_carrier(size_t mem_block_symbols, bool with_dma, rmt
TEST_ESP_OK(rmt_apply_carrier(rx_channel, NULL)); TEST_ESP_OK(rmt_apply_carrier(rx_channel, NULL));
#endif // SOC_RMT_SUPPORT_RX_DEMODULATION #endif // SOC_RMT_SUPPORT_RX_DEMODULATION
TEST_ESP_OK(rmt_receive(rx_channel, remote_codes, sizeof(remote_codes), &receive_config)); TEST_ESP_OK(rmt_receive(rx_channel, remote_codes, test_rx_buffer_symbols * sizeof(rmt_symbol_word_t), &receive_config));
printf("send NEC frame without carrier\r\n"); printf("send NEC frame without carrier\r\n");
TEST_ESP_OK(rmt_transmit(tx_channel, nec_encoder, (uint16_t[]) { TEST_ESP_OK(rmt_transmit(tx_channel, nec_encoder, (uint16_t[]) {
0x0440, 0x3003 // address, command 0x0440, 0x3003 // address, command
@@ -183,6 +187,7 @@ static void test_rmt_rx_nec_carrier(size_t mem_block_symbols, bool with_dma, rmt
TEST_ESP_OK(rmt_del_channel(rx_channel)); TEST_ESP_OK(rmt_del_channel(rx_channel));
TEST_ESP_OK(rmt_del_channel(tx_channel)); TEST_ESP_OK(rmt_del_channel(tx_channel));
TEST_ESP_OK(rmt_del_encoder(nec_encoder)); TEST_ESP_OK(rmt_del_encoder(nec_encoder));
free(remote_codes);
} }
TEST_CASE("rmt rx nec with carrier", "[rmt]") TEST_CASE("rmt rx nec with carrier", "[rmt]")
@@ -196,40 +201,3 @@ TEST_CASE("rmt rx nec with carrier", "[rmt]")
test_rmt_rx_nec_carrier(128, true, RMT_CLK_SRC_DEFAULT); test_rmt_rx_nec_carrier(128, true, RMT_CLK_SRC_DEFAULT);
#endif #endif
} }
TEST_CASE("RMT RX test specifying interrupt priority", "[rmt]")
{
rmt_clock_source_t clk_srcs[] = SOC_RMT_CLKS;
rmt_rx_channel_config_t rx_channel_cfg = {
.clk_src = clk_srcs[0],
.resolution_hz = 1000000, // 1MHz, 1 tick = 1us
.mem_block_symbols = SOC_RMT_MEM_WORDS_PER_CHANNEL,
.gpio_num = 0,
.flags.with_dma = false, // Interrupt will only be allocated when dma disabled
.flags.io_loop_back = true, // the GPIO will act like a loopback
.intr_priority = 3,
};
// --- Check if specifying interrupt priority works
printf("install rx channel\r\n");
rmt_channel_handle_t rx_channel = NULL;
TEST_ESP_OK(rmt_new_rx_channel(&rx_channel_cfg, &rx_channel));
rmt_channel_handle_t another_rx_channel = NULL;
rmt_rx_channel_config_t another_rx_channel_cfg = rx_channel_cfg;
// --- Check if rmt interrupt priority valid check works
another_rx_channel_cfg.intr_priority = 4; ///< Specifying a invalid intr_priority
TEST_ESP_ERR(rmt_new_rx_channel(&another_rx_channel_cfg, &another_rx_channel), ESP_ERR_INVALID_ARG);
// --- Check if rmt interrupt priority conflict check works
another_rx_channel_cfg.intr_priority = 1; ///< Specifying a conflict intr_priority
TEST_ESP_ERR(rmt_new_rx_channel(&another_rx_channel_cfg, &another_rx_channel), ESP_ERR_INVALID_ARG);
another_rx_channel_cfg.intr_priority = 0; ///< Do not specify an intr_priority, should not conflict
TEST_ESP_OK(rmt_new_rx_channel(&another_rx_channel_cfg, &another_rx_channel));
// --- Check if channel works
TEST_ESP_OK(rmt_enable(rx_channel));
TEST_ESP_OK(rmt_enable(another_rx_channel));
// --- Post-test
TEST_ESP_OK(rmt_disable(rx_channel));
TEST_ESP_OK(rmt_disable(another_rx_channel));
TEST_ESP_OK(rmt_del_channel(rx_channel));
TEST_ESP_OK(rmt_del_channel(another_rx_channel));
}

View File

@@ -13,6 +13,7 @@
#include "esp_timer.h" #include "esp_timer.h"
#include "soc/soc_caps.h" #include "soc/soc_caps.h"
#include "test_util_rmt_encoders.h" #include "test_util_rmt_encoders.h"
#include "test_board.h"
#if CONFIG_RMT_ISR_IRAM_SAFE #if CONFIG_RMT_ISR_IRAM_SAFE
#define TEST_RMT_CALLBACK_ATTR IRAM_ATTR #define TEST_RMT_CALLBACK_ATTR IRAM_ATTR
@@ -27,7 +28,7 @@ TEST_CASE("rmt bytes encoder", "[rmt]")
.clk_src = RMT_CLK_SRC_DEFAULT, .clk_src = RMT_CLK_SRC_DEFAULT,
.resolution_hz = 1000000, // 1MHz, 1 tick = 1us .resolution_hz = 1000000, // 1MHz, 1 tick = 1us
.trans_queue_depth = 4, .trans_queue_depth = 4,
.gpio_num = 0, .gpio_num = TEST_RMT_GPIO_NUM_A,
.intr_priority = 3 .intr_priority = 3
}; };
printf("install tx channel\r\n"); printf("install tx channel\r\n");
@@ -89,7 +90,7 @@ static void test_rmt_channel_single_trans(size_t mem_block_symbols, bool with_dm
.clk_src = RMT_CLK_SRC_DEFAULT, .clk_src = RMT_CLK_SRC_DEFAULT,
.resolution_hz = 10000000, // 10MHz, 1 tick = 0.1us (led strip needs a high resolution) .resolution_hz = 10000000, // 10MHz, 1 tick = 0.1us (led strip needs a high resolution)
.trans_queue_depth = 4, .trans_queue_depth = 4,
.gpio_num = 0, .gpio_num = TEST_RMT_GPIO_NUM_A,
.flags.with_dma = with_dma, .flags.with_dma = with_dma,
.intr_priority = 2 .intr_priority = 2
}; };
@@ -144,7 +145,7 @@ static void test_rmt_ping_pong_trans(size_t mem_block_symbols, bool with_dma)
.clk_src = RMT_CLK_SRC_DEFAULT, .clk_src = RMT_CLK_SRC_DEFAULT,
.resolution_hz = 10000000, // 10MHz, 1 tick = 0.1us (led strip needs a high resolution) .resolution_hz = 10000000, // 10MHz, 1 tick = 0.1us (led strip needs a high resolution)
.trans_queue_depth = 4, .trans_queue_depth = 4,
.gpio_num = 0, .gpio_num = TEST_RMT_GPIO_NUM_A,
.flags.with_dma = with_dma, .flags.with_dma = with_dma,
.intr_priority = 1 .intr_priority = 1
}; };
@@ -215,7 +216,6 @@ TEST_CASE("rmt ping-pong transaction", "[rmt]")
#endif #endif
} }
TEST_RMT_CALLBACK_ATTR TEST_RMT_CALLBACK_ATTR
static bool test_rmt_tx_done_cb_check_event_data(rmt_channel_handle_t channel, const rmt_tx_done_event_data_t *edata, void *user_data) static bool test_rmt_tx_done_cb_check_event_data(rmt_channel_handle_t channel, const rmt_tx_done_event_data_t *edata, void *user_data)
{ {
@@ -231,7 +231,7 @@ static void test_rmt_trans_done_event(size_t mem_block_symbols, bool with_dma)
.clk_src = RMT_CLK_SRC_DEFAULT, .clk_src = RMT_CLK_SRC_DEFAULT,
.resolution_hz = 10000000, // 10MHz, 1 tick = 0.1us (led strip needs a high resolution) .resolution_hz = 10000000, // 10MHz, 1 tick = 0.1us (led strip needs a high resolution)
.trans_queue_depth = 1, .trans_queue_depth = 1,
.gpio_num = 0, .gpio_num = TEST_RMT_GPIO_NUM_A,
.flags.with_dma = with_dma, .flags.with_dma = with_dma,
.intr_priority = 3 .intr_priority = 3
}; };
@@ -305,7 +305,7 @@ static void test_rmt_loop_trans(size_t mem_block_symbols, bool with_dma)
.clk_src = RMT_CLK_SRC_DEFAULT, .clk_src = RMT_CLK_SRC_DEFAULT,
.resolution_hz = 10000000, // 10MHz, 1 tick = 0.1us (led strip needs a high resolution) .resolution_hz = 10000000, // 10MHz, 1 tick = 0.1us (led strip needs a high resolution)
.trans_queue_depth = 4, .trans_queue_depth = 4,
.gpio_num = 0, .gpio_num = TEST_RMT_GPIO_NUM_A,
.flags.with_dma = with_dma, .flags.with_dma = with_dma,
.intr_priority = 2 .intr_priority = 2
}; };
@@ -365,7 +365,7 @@ TEST_CASE("rmt infinite loop transaction", "[rmt]")
.clk_src = RMT_CLK_SRC_DEFAULT, .clk_src = RMT_CLK_SRC_DEFAULT,
.resolution_hz = 1000000, // 1MHz, 1 tick = 1us .resolution_hz = 1000000, // 1MHz, 1 tick = 1us
.mem_block_symbols = SOC_RMT_MEM_WORDS_PER_CHANNEL, .mem_block_symbols = SOC_RMT_MEM_WORDS_PER_CHANNEL,
.gpio_num = 2, .gpio_num = TEST_RMT_GPIO_NUM_B,
.trans_queue_depth = 3, .trans_queue_depth = 3,
.intr_priority = 1 .intr_priority = 1
}; };
@@ -444,7 +444,7 @@ static void test_rmt_tx_nec_carrier(size_t mem_block_symbols, bool with_dma)
.clk_src = RMT_CLK_SRC_DEFAULT, .clk_src = RMT_CLK_SRC_DEFAULT,
.resolution_hz = 1000000, // 1MHz, 1 tick = 1us .resolution_hz = 1000000, // 1MHz, 1 tick = 1us
.mem_block_symbols = mem_block_symbols, .mem_block_symbols = mem_block_symbols,
.gpio_num = 2, .gpio_num = TEST_RMT_GPIO_NUM_B,
.trans_queue_depth = 4, .trans_queue_depth = 4,
.flags.with_dma = with_dma, .flags.with_dma = with_dma,
.intr_priority = 3 .intr_priority = 3
@@ -503,7 +503,6 @@ TEST_CASE("rmt tx nec with carrier", "[rmt]")
#endif #endif
} }
TEST_RMT_CALLBACK_ATTR TEST_RMT_CALLBACK_ATTR
static bool test_rmt_tx_done_cb_record_time(rmt_channel_handle_t channel, const rmt_tx_done_event_data_t *edata, void *user_data) static bool test_rmt_tx_done_cb_record_time(rmt_channel_handle_t channel, const rmt_tx_done_event_data_t *edata, void *user_data)
{ {
@@ -526,7 +525,7 @@ static void test_rmt_multi_channels_trans(size_t channel0_mem_block_symbols, siz
}; };
printf("install tx channels\r\n"); printf("install tx channels\r\n");
rmt_channel_handle_t tx_channels[TEST_RMT_CHANS] = {NULL}; rmt_channel_handle_t tx_channels[TEST_RMT_CHANS] = {NULL};
int gpio_nums[TEST_RMT_CHANS] = {0, 2}; int gpio_nums[TEST_RMT_CHANS] = {TEST_RMT_GPIO_NUM_A, TEST_RMT_GPIO_NUM_B};
size_t mem_blk_syms[TEST_RMT_CHANS] = {channel0_mem_block_symbols, channel1_mem_block_symbols}; size_t mem_blk_syms[TEST_RMT_CHANS] = {channel0_mem_block_symbols, channel1_mem_block_symbols};
bool dma_flags[TEST_RMT_CHANS] = {channel0_with_dma, channel1_with_dma}; bool dma_flags[TEST_RMT_CHANS] = {channel0_with_dma, channel1_with_dma};
for (int i = 0; i < TEST_RMT_CHANS; i++) { for (int i = 0; i < TEST_RMT_CHANS; i++) {
@@ -655,38 +654,3 @@ TEST_CASE("rmt multiple channels transaction", "[rmt]")
test_rmt_multi_channels_trans(1024, SOC_RMT_MEM_WORDS_PER_CHANNEL, true, false); test_rmt_multi_channels_trans(1024, SOC_RMT_MEM_WORDS_PER_CHANNEL, true, false);
#endif #endif
} }
TEST_CASE("RMT TX test specifying interrupt priority", "[rmt]")
{
rmt_tx_channel_config_t tx_channel_cfg = {
.mem_block_symbols = SOC_RMT_MEM_WORDS_PER_CHANNEL,
.clk_src = RMT_CLK_SRC_DEFAULT,
.resolution_hz = 1000000, // 1MHz, 1 tick = 1us
.trans_queue_depth = 4,
.gpio_num = 0,
.intr_priority = 3
};
// --- Check if specifying interrupt priority works
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));
rmt_channel_handle_t another_tx_channel = NULL;
rmt_tx_channel_config_t another_tx_channel_cfg = tx_channel_cfg;
// --- Check if rmt interrupt priority valid check works
another_tx_channel_cfg.intr_priority = 4;
TEST_ESP_ERR(rmt_new_tx_channel(&another_tx_channel_cfg, &another_tx_channel), ESP_ERR_INVALID_ARG);
// --- Check if rmt interrupt priority conflict check works
another_tx_channel_cfg.intr_priority = 1; ///< Specifying a conflict intr_priority
TEST_ESP_ERR(rmt_new_tx_channel(&another_tx_channel_cfg, &another_tx_channel), ESP_ERR_INVALID_ARG);
another_tx_channel_cfg.intr_priority = 0; ///< Do not specify an intr_priority, should not conflict
TEST_ESP_OK(rmt_new_tx_channel(&another_tx_channel_cfg, &another_tx_channel));
// --- Check if channel works
TEST_ESP_OK(rmt_enable(tx_channel));
TEST_ESP_OK(rmt_enable(another_tx_channel));
// --- Post-test
TEST_ESP_OK(rmt_disable(tx_channel));
TEST_ESP_OK(rmt_disable(another_tx_channel));
TEST_ESP_OK(rmt_del_channel(tx_channel));
TEST_ESP_OK(rmt_del_channel(another_tx_channel));
}

View File

@@ -11,12 +11,6 @@
#include "driver/rmt_encoder.h" #include "driver/rmt_encoder.h"
#include "esp_attr.h" #include "esp_attr.h"
#if CONFIG_RMT_ISR_IRAM_SAFE
#define TEST_RMT_ENCODER_ATTR IRAM_ATTR
#else
#define TEST_RMT_ENCODER_ATTR
#endif
typedef struct { typedef struct {
rmt_encoder_t base; rmt_encoder_t base;
rmt_encoder_t *bytes_encoder; rmt_encoder_t *bytes_encoder;
@@ -25,8 +19,7 @@ typedef struct {
rmt_symbol_word_t reset_code; rmt_symbol_word_t reset_code;
} rmt_led_strip_encoder_t; } rmt_led_strip_encoder_t;
TEST_RMT_ENCODER_ATTR IRAM_ATTR static size_t rmt_encode_led_strip(rmt_encoder_t *encoder, rmt_channel_handle_t channel, const void *primary_data, size_t data_size, rmt_encode_state_t *ret_state)
static size_t rmt_encode_led_strip(rmt_encoder_t *encoder, rmt_channel_handle_t channel, const void *primary_data, size_t data_size, rmt_encode_state_t *ret_state)
{ {
rmt_led_strip_encoder_t *led_encoder = __containerof(encoder, rmt_led_strip_encoder_t, base); rmt_led_strip_encoder_t *led_encoder = __containerof(encoder, rmt_led_strip_encoder_t, base);
rmt_encode_state_t session_state = RMT_ENCODING_RESET; rmt_encode_state_t session_state = RMT_ENCODING_RESET;
@@ -119,7 +112,7 @@ typedef struct {
int state; int state;
} rmt_nec_protocol_encoder_t; } rmt_nec_protocol_encoder_t;
static size_t rmt_encode_nec_protocol(rmt_encoder_t *encoder, rmt_channel_handle_t channel, const void *primary_data, size_t data_size, rmt_encode_state_t *ret_state) IRAM_ATTR static size_t rmt_encode_nec_protocol(rmt_encoder_t *encoder, rmt_channel_handle_t channel, const void *primary_data, size_t data_size, rmt_encode_state_t *ret_state)
{ {
rmt_nec_protocol_encoder_t *nec_encoder = __containerof(encoder, rmt_nec_protocol_encoder_t, base); rmt_nec_protocol_encoder_t *nec_encoder = __containerof(encoder, rmt_nec_protocol_encoder_t, base);
rmt_encode_state_t session_state = RMT_ENCODING_RESET; rmt_encode_state_t session_state = RMT_ENCODING_RESET;

View File

@@ -447,11 +447,11 @@ static bool mcp_gdma_rx_eof_callback(gdma_channel_handle_t dma_chan, gdma_event_
if (atomic_compare_exchange_strong(&mcp_gdma->fsm, &expected_fsm, MCP_FSM_IDLE_WAIT)) { if (atomic_compare_exchange_strong(&mcp_gdma->fsm, &expected_fsm, MCP_FSM_IDLE_WAIT)) {
// if the data is in the cache, invalidate, then CPU can see the latest data // if the data is in the cache, invalidate, then CPU can see the latest data
#if MCP_NEEDS_INVALIDATE_DST_CACHE #if MCP_NEEDS_INVALIDATE_DST_CACHE
int write_back_map = CACHE_MAP_L1_DCACHE; int invalidate_map = CACHE_MAP_L1_DCACHE;
if (esp_ptr_external_ram((const void *)trans->memcpy_dst_addr)) { if (esp_ptr_external_ram((const void *)trans->memcpy_dst_addr)) {
write_back_map |= CACHE_MAP_L2_CACHE; invalidate_map |= CACHE_MAP_L2_CACHE;
} }
Cache_Invalidate_Addr(write_back_map, (uint32_t)trans->memcpy_dst_addr, trans->memcpy_size); Cache_Invalidate_Addr(invalidate_map, (uint32_t)trans->memcpy_dst_addr, trans->memcpy_size);
#endif #endif
// invoked callback registered by user // invoked callback registered by user

View File

@@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2019-2022 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2019-2023 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@@ -16,6 +16,7 @@
#include "hal/misc.h" #include "hal/misc.h"
#include "hal/assert.h" #include "hal/assert.h"
#include "soc/rmt_struct.h" #include "soc/rmt_struct.h"
#include "soc/dport_reg.h"
#include "hal/rmt_types.h" #include "hal/rmt_types.h"
#ifdef __cplusplus #ifdef __cplusplus
@@ -40,6 +41,41 @@ typedef enum {
RMT_LL_MEM_OWNER_HW = 1, RMT_LL_MEM_OWNER_HW = 1,
} rmt_ll_mem_owner_t; } rmt_ll_mem_owner_t;
/**
* @brief Enable the bus clock for RMT module
*
* @param group_id Group ID
* @param enable true to enable, false to disable
*/
static inline void rmt_ll_enable_bus_clock(int group_id, bool enable)
{
(void)group_id;
uint32_t reg_val = DPORT_READ_PERI_REG(DPORT_PERIP_CLK_EN_REG);
reg_val &= ~DPORT_RMT_CLK_EN;
reg_val |= enable << 9;
DPORT_WRITE_PERI_REG(DPORT_PERIP_CLK_EN_REG, reg_val);
}
/// use a macro to wrap the function, force the caller to use it in a critical section
/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance
#define rmt_ll_enable_bus_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; rmt_ll_enable_bus_clock(__VA_ARGS__)
/**
* @brief Reset the RMT module
*
* @param group_id Group ID
*/
static inline void rmt_ll_reset_register(int group_id)
{
(void)group_id;
DPORT_WRITE_PERI_REG(DPORT_PERIP_RST_EN_REG, DPORT_RMT_RST);
DPORT_WRITE_PERI_REG(DPORT_PERIP_RST_EN_REG, 0);
}
/// use a macro to wrap the function, force the caller to use it in a critical section
/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance
#define rmt_ll_reset_register(...) (void)__DECLARE_RCC_ATOMIC_ENV; rmt_ll_reset_register(__VA_ARGS__)
/** /**
* @brief Enable clock gate for register and memory * @brief Enable clock gate for register and memory
* *

View File

@@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@@ -16,6 +16,7 @@
#include "hal/misc.h" #include "hal/misc.h"
#include "hal/assert.h" #include "hal/assert.h"
#include "soc/rmt_struct.h" #include "soc/rmt_struct.h"
#include "soc/system_struct.h"
#include "hal/rmt_types.h" #include "hal/rmt_types.h"
#ifdef __cplusplus #ifdef __cplusplus
@@ -41,6 +42,38 @@ typedef enum {
RMT_LL_MEM_OWNER_HW = 1, RMT_LL_MEM_OWNER_HW = 1,
} rmt_ll_mem_owner_t; } rmt_ll_mem_owner_t;
/**
* @brief Enable the bus clock for RMT module
*
* @param group_id Group ID
* @param enable true to enable, false to disable
*/
static inline void rmt_ll_enable_bus_clock(int group_id, bool enable)
{
(void)group_id;
SYSTEM.perip_clk_en0.reg_rmt_clk_en = enable;
}
/// use a macro to wrap the function, force the caller to use it in a critical section
/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance
#define rmt_ll_enable_bus_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; rmt_ll_enable_bus_clock(__VA_ARGS__)
/**
* @brief Reset the RMT module
*
* @param group_id Group ID
*/
static inline void rmt_ll_reset_register(int group_id)
{
(void)group_id;
SYSTEM.perip_rst_en0.reg_rmt_rst = 1;
SYSTEM.perip_rst_en0.reg_rmt_rst = 0;
}
/// use a macro to wrap the function, force the caller to use it in a critical section
/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance
#define rmt_ll_reset_register(...) (void)__DECLARE_RCC_ATOMIC_ENV; rmt_ll_reset_register(__VA_ARGS__)
/** /**
* @brief Enable clock gate for register and memory * @brief Enable clock gate for register and memory
* *

View File

@@ -42,6 +42,30 @@ typedef enum {
RMT_LL_MEM_OWNER_HW = 1, RMT_LL_MEM_OWNER_HW = 1,
} rmt_ll_mem_owner_t; } rmt_ll_mem_owner_t;
/**
* @brief Enable the bus clock for RMT module
*
* @param group_id Group ID
* @param enable true to enable, false to disable
*/
static inline void rmt_ll_enable_bus_clock(int group_id, bool enable)
{
(void)group_id;
PCR.rmt_conf.rmt_clk_en = enable;
}
/**
* @brief Reset the RMT module
*
* @param group_id Group ID
*/
static inline void rmt_ll_reset_register(int group_id)
{
(void)group_id;
PCR.rmt_conf.rmt_rst_en = 1;
PCR.rmt_conf.rmt_rst_en = 0;
}
/** /**
* @brief Enable clock gate for register and memory * @brief Enable clock gate for register and memory
* *

View File

@@ -42,6 +42,30 @@ typedef enum {
RMT_LL_MEM_OWNER_HW = 1, RMT_LL_MEM_OWNER_HW = 1,
} rmt_ll_mem_owner_t; } rmt_ll_mem_owner_t;
/**
* @brief Enable the bus clock for RMT module
*
* @param group_id Group ID
* @param enable true to enable, false to disable
*/
static inline void rmt_ll_enable_bus_clock(int group_id, bool enable)
{
(void)group_id;
PCR.rmt_conf.rmt_clk_en = enable;
}
/**
* @brief Reset the RMT module
*
* @param group_id Group ID
*/
static inline void rmt_ll_reset_register(int group_id)
{
(void)group_id;
PCR.rmt_conf.rmt_rst_en = 1;
PCR.rmt_conf.rmt_rst_en = 0;
}
/** /**
* @brief Enable clock gate for register and memory * @brief Enable clock gate for register and memory
* *

View File

@@ -76,8 +76,6 @@ static inline uint32_t periph_ll_get_clk_en_mask(periph_module_t periph)
return HP_SYS_CLKRST_REG_SYSTIMER_CLK_EN; return HP_SYS_CLKRST_REG_SYSTIMER_CLK_EN;
case PERIPH_LEDC_MODULE: case PERIPH_LEDC_MODULE:
return HP_SYS_CLKRST_REG_LEDC_CLK_EN; return HP_SYS_CLKRST_REG_LEDC_CLK_EN;
case PERIPH_RMT_MODULE:
return HP_SYS_CLKRST_REG_RMT_CLK_EN;
case PERIPH_SARADC_MODULE: case PERIPH_SARADC_MODULE:
return HP_SYS_CLKRST_REG_ADC_CLK_EN; return HP_SYS_CLKRST_REG_ADC_CLK_EN;
case PERIPH_PVT_MODULE: case PERIPH_PVT_MODULE:
@@ -147,8 +145,6 @@ static inline uint32_t periph_ll_get_rst_en_mask(periph_module_t periph, bool en
return HP_SYS_CLKRST_REG_RST_EN_I2C0; return HP_SYS_CLKRST_REG_RST_EN_I2C0;
case PERIPH_I2C1_MODULE: case PERIPH_I2C1_MODULE:
return HP_SYS_CLKRST_REG_RST_EN_I2C1; return HP_SYS_CLKRST_REG_RST_EN_I2C1;
case PERIPH_RMT_MODULE:
return HP_SYS_CLKRST_REG_RST_EN_RMT;
case PERIPH_TWAI0_MODULE: case PERIPH_TWAI0_MODULE:
return HP_SYS_CLKRST_REG_RST_EN_CAN0; return HP_SYS_CLKRST_REG_RST_EN_CAN0;
case PERIPH_TWAI1_MODULE: case PERIPH_TWAI1_MODULE:
@@ -253,7 +249,6 @@ static inline uint32_t periph_ll_get_clk_en_reg(periph_module_t periph)
return HP_SYS_CLKRST_PERI_CLK_CTRL119_REG; return HP_SYS_CLKRST_PERI_CLK_CTRL119_REG;
case PERIPH_SYSTIMER_MODULE: case PERIPH_SYSTIMER_MODULE:
case PERIPH_LEDC_MODULE: case PERIPH_LEDC_MODULE:
case PERIPH_RMT_MODULE:
return HP_SYS_CLKRST_PERI_CLK_CTRL21_REG; return HP_SYS_CLKRST_PERI_CLK_CTRL21_REG;
case PERIPH_SARADC_MODULE: case PERIPH_SARADC_MODULE:
return HP_SYS_CLKRST_PERI_CLK_CTRL22_REG; return HP_SYS_CLKRST_PERI_CLK_CTRL22_REG;
@@ -299,7 +294,6 @@ static inline uint32_t periph_ll_get_rst_en_reg(periph_module_t periph)
case PERIPH_I2C0_MODULE: case PERIPH_I2C0_MODULE:
case PERIPH_I2C1_MODULE: case PERIPH_I2C1_MODULE:
return HP_SYS_CLKRST_HP_RST_EN1_REG; return HP_SYS_CLKRST_HP_RST_EN1_REG;
case PERIPH_RMT_MODULE:
case PERIPH_TWAI0_MODULE: case PERIPH_TWAI0_MODULE:
case PERIPH_TWAI1_MODULE: case PERIPH_TWAI1_MODULE:
case PERIPH_TWAI2_MODULE: case PERIPH_TWAI2_MODULE:

View File

@@ -0,0 +1,923 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @note TX and RX channels are index from 0 in the LL driver, i.e. tx_channel = [0,3], rx_channel = [0,3]
*/
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#include "hal/misc.h"
#include "hal/assert.h"
#include "hal/rmt_types.h"
#include "soc/rmt_struct.h"
#include "soc/hp_sys_clkrst_struct.h"
#ifdef __cplusplus
extern "C" {
#endif
#define RMT_LL_EVENT_TX_DONE(channel) (1 << (channel))
#define RMT_LL_EVENT_TX_THRES(channel) (1 << ((channel) + 8))
#define RMT_LL_EVENT_TX_LOOP_END(channel) (1 << ((channel) + 12))
#define RMT_LL_EVENT_TX_ERROR(channel) (1 << ((channel) + 4))
#define RMT_LL_EVENT_RX_DONE(channel) (1 << ((channel) + 16))
#define RMT_LL_EVENT_RX_THRES(channel) (1 << ((channel) + 24))
#define RMT_LL_EVENT_RX_ERROR(channel) (1 << ((channel) + 20))
#define RMT_LL_EVENT_TX_MASK(channel) (RMT_LL_EVENT_TX_DONE(channel) | RMT_LL_EVENT_TX_THRES(channel) | RMT_LL_EVENT_TX_LOOP_END(channel))
#define RMT_LL_EVENT_RX_MASK(channel) (RMT_LL_EVENT_RX_DONE(channel) | RMT_LL_EVENT_RX_THRES(channel))
#define RMT_LL_MAX_LOOP_COUNT_PER_BATCH 1023
#define RMT_LL_MAX_FILTER_VALUE 255
#define RMT_LL_MAX_IDLE_VALUE 32767
typedef enum {
RMT_LL_MEM_OWNER_SW = 0,
RMT_LL_MEM_OWNER_HW = 1,
} rmt_ll_mem_owner_t;
/**
* @brief Enable the bus clock for RMT module
*
* @param group_id Group ID
* @param enable true to enable, false to disable
*/
static inline void rmt_ll_enable_bus_clock(int group_id, bool enable)
{
(void)group_id;
HP_SYS_CLKRST.soc_clk_ctrl2.reg_rmt_sys_clk_en = enable;
}
/// use a macro to wrap the function, force the caller to use it in a critical section
/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance
#define rmt_ll_enable_bus_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; rmt_ll_enable_bus_clock(__VA_ARGS__)
/**
* @brief Reset the RMT module
*
* @param group_id Group ID
*/
static inline void rmt_ll_reset_register(int group_id)
{
(void)group_id;
HP_SYS_CLKRST.hp_rst_en1.reg_rst_en_rmt = 1;
HP_SYS_CLKRST.hp_rst_en1.reg_rst_en_rmt = 0;
}
/// use a macro to wrap the function, force the caller to use it in a critical section
/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance
#define rmt_ll_reset_register(...) (void)__DECLARE_RCC_ATOMIC_ENV; rmt_ll_reset_register(__VA_ARGS__)
/**
* @brief Set clock source and divider for RMT channel group
*
* @param dev Peripheral instance address
* @param channel not used as clock source is set for all channels
* @param src Clock source
* @param divider_integral Integral part of the divider
* @param divider_denominator Denominator part of the divider
* @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)
{
(void)dev;
// Formula: rmt_sclk = module_clock_src / (1 + div_num + div_a / div_b)
(void)channel; // the source clock is set for all channels
HAL_ASSERT(divider_integral >= 1);
HAL_FORCE_MODIFY_U32_REG_FIELD(HP_SYS_CLKRST.peri_clk_ctrl22, reg_rmt_clk_div_num, divider_integral - 1);
HAL_FORCE_MODIFY_U32_REG_FIELD(HP_SYS_CLKRST.peri_clk_ctrl22, reg_rmt_clk_div_numerator, divider_numerator);
HAL_FORCE_MODIFY_U32_REG_FIELD(HP_SYS_CLKRST.peri_clk_ctrl22, reg_rmt_clk_div_denominator, divider_denominator);
switch (src) {
case RMT_CLK_SRC_PLL_F80M:
HP_SYS_CLKRST.peri_clk_ctrl22.reg_rmt_clk_src_sel = 2;
break;
case RMT_CLK_SRC_RC_FAST:
HP_SYS_CLKRST.peri_clk_ctrl22.reg_rmt_clk_src_sel = 1;
break;
case RMT_CLK_SRC_XTAL:
HP_SYS_CLKRST.peri_clk_ctrl22.reg_rmt_clk_src_sel = 0;
break;
default:
HAL_ASSERT(false && "unsupported RMT clock source");
break;
}
}
/// use a macro to wrap the function, force the caller to use it in a critical section
/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance
#define rmt_ll_set_group_clock_src(...) (void)__DECLARE_RCC_ATOMIC_ENV; rmt_ll_set_group_clock_src(__VA_ARGS__)
/**
* @brief Enable RMT peripheral source clock
*
* @param dev Peripheral instance address
* @param en True to enable, False to disable
*/
static inline void rmt_ll_enable_group_clock(rmt_dev_t *dev, bool en)
{
(void)dev;
HP_SYS_CLKRST.peri_clk_ctrl22.reg_rmt_clk_en = en;
}
/// use a macro to wrap the function, force the caller to use it in a critical section
/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance
#define rmt_ll_enable_group_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; rmt_ll_enable_group_clock(__VA_ARGS__)
/**
* @brief Enable clock gate for register and memory
*
* @param dev Peripheral instance address
* @param enable True to enable, False to disable
*/
static inline void rmt_ll_enable_periph_clock(rmt_dev_t *dev, bool enable)
{
dev->sys_conf.clk_en = enable; // register clock gating
dev->sys_conf.mem_clk_force_on = enable; // memory clock gating
}
/**
* @brief Power down memory
*
* @param dev Peripheral instance address
* @param enable True to power down, False to power up
*/
static inline void rmt_ll_power_down_mem(rmt_dev_t *dev, bool enable)
{
dev->sys_conf.mem_force_pu = !enable;
dev->sys_conf.mem_force_pd = enable;
}
/**
* @brief Enable APB accessing RMT memory in nonfifo mode
*
* @param dev Peripheral instance address
* @param enable True to enable, False to disable
*/
static inline void rmt_ll_enable_mem_access_nonfifo(rmt_dev_t *dev, bool enable)
{
dev->sys_conf.apb_fifo_mask = enable;
}
////////////////////////////////////////TX Channel Specific/////////////////////////////////////////////////////////////
/**
* @brief Reset clock divider for TX channels by mask
*
* @param dev Peripheral instance address
* @param channel_mask Mask of TX channels
*/
static inline void rmt_ll_tx_reset_channels_clock_div(rmt_dev_t *dev, uint32_t channel_mask)
{
// write 1 to reset
dev->ref_cnt_rst.val |= channel_mask & 0x0F;
}
/**
* @brief Set TX channel clock divider
*
* @param dev Peripheral instance address
* @param channel RMT TX channel number
* @param div Division value
*/
static inline void rmt_ll_tx_set_channel_clock_div(rmt_dev_t *dev, uint32_t channel, uint32_t div)
{
HAL_ASSERT(div >= 1 && div <= 256 && "divider out of range");
// limit the maximum divider to 256
if (div >= 256) {
div = 0; // 0 means 256 division
}
HAL_FORCE_MODIFY_U32_REG_FIELD(dev->chnconf0[channel], div_cnt_chn, div);
}
/**
* @brief Reset RMT reading pointer for TX channel
*
* @param dev Peripheral instance address
* @param channel RMT TX channel number
*/
__attribute__((always_inline))
static inline void rmt_ll_tx_reset_pointer(rmt_dev_t *dev, uint32_t channel)
{
dev->chnconf0[channel].mem_rd_rst_chn = 1;
dev->chnconf0[channel].mem_rd_rst_chn = 0;
dev->chnconf0[channel].apb_mem_rst_chn = 1;
dev->chnconf0[channel].apb_mem_rst_chn = 0;
}
/**
* @brief Enable DMA access for TX channel
*
* @param dev Peripheral instance address
* @param channel RMT TX channel number
* @param enable True to enable, False to disable
*/
static inline void rmt_ll_tx_enable_dma(rmt_dev_t *dev, uint32_t channel, bool enable)
{
HAL_ASSERT(channel == 3 && "only TX channel 3 has DMA ability");
dev->chnconf0[channel].dma_access_en_chn = enable;
}
/**
* @brief Start transmitting for TX channel
*
* @param dev Peripheral instance address
* @param channel RMT TX channel number
*/
__attribute__((always_inline))
static inline void rmt_ll_tx_start(rmt_dev_t *dev, uint32_t channel)
{
// update other configuration registers before start transmitting
dev->chnconf0[channel].conf_update_chn = 1;
dev->chnconf0[channel].tx_start_chn = 1;
}
/**
* @brief Stop transmitting for TX channel
*
* @param dev Peripheral instance address
* @param channel RMT TX channel number
*/
__attribute__((always_inline))
static inline void rmt_ll_tx_stop(rmt_dev_t *dev, uint32_t channel)
{
dev->chnconf0[channel].tx_stop_chn = 1;
// stop won't take place until configurations updated
dev->chnconf0[channel].conf_update_chn = 1;
}
/**
* @brief Set memory block number for TX channel
*
* @param dev Peripheral instance address
* @param channel RMT TX channel number
* @param block_num memory block number
*/
static inline void rmt_ll_tx_set_mem_blocks(rmt_dev_t *dev, uint32_t channel, uint8_t block_num)
{
dev->chnconf0[channel].mem_size_chn = block_num;
}
/**
* @brief Enable TX wrap
*
* @param dev Peripheral instance address
* @param channel RMT TX channel number
* @param enable True to enable, False to disable
*/
static inline void rmt_ll_tx_enable_wrap(rmt_dev_t *dev, uint32_t channel, bool enable)
{
dev->chnconf0[channel].mem_tx_wrap_en_chn = enable;
}
/**
* @brief Enable transmitting in a loop
*
* @param dev Peripheral instance address
* @param channel RMT TX channel number
* @param enable True to enable, False to disable
*/
__attribute__((always_inline))
static inline void rmt_ll_tx_enable_loop(rmt_dev_t *dev, uint32_t channel, bool enable)
{
dev->chnconf0[channel].tx_conti_mode_chn = enable;
}
/**
* @brief Set loop count for TX channel
*
* @param dev Peripheral instance address
* @param channel RMT TX channel number
* @param count TX loop count
*/
__attribute__((always_inline))
static inline void rmt_ll_tx_set_loop_count(rmt_dev_t *dev, uint32_t channel, uint32_t count)
{
HAL_ASSERT(count <= RMT_LL_MAX_LOOP_COUNT_PER_BATCH && "loop count out of range");
dev->chn_tx_lim[channel].tx_loop_num_chn = count;
}
/**
* @brief Reset loop count for TX channel
*
* @param dev Peripheral instance address
* @param channel RMT TX channel number
*/
__attribute__((always_inline))
static inline void rmt_ll_tx_reset_loop_count(rmt_dev_t *dev, uint32_t channel)
{
dev->chn_tx_lim[channel].loop_count_reset_chn = 1;
dev->chn_tx_lim[channel].loop_count_reset_chn = 0;
}
/**
* @brief Enable loop count for TX channel
*
* @param dev Peripheral instance address
* @param channel RMT TX channel number
* @param enable True to enable, False to disable
*/
__attribute__((always_inline))
static inline void rmt_ll_tx_enable_loop_count(rmt_dev_t *dev, uint32_t channel, bool enable)
{
dev->chn_tx_lim[channel].tx_loop_cnt_en_chn = enable;
}
/**
* @brief Enable loop stop at count value automatically
*
* @param dev Peripheral instance address
* @param channel RMT TX channel number
* @param enable True to enable, False to disable
*/
__attribute__((always_inline))
static inline void rmt_ll_tx_enable_loop_autostop(rmt_dev_t *dev, uint32_t channel, bool enable)
{
dev->chn_tx_lim[channel].loop_stop_en_chn = enable;
}
/**
* @brief Enable transmit multiple channels synchronously
*
* @param dev Peripheral instance address
* @param enable True to enable, False to disable
*/
static inline void rmt_ll_tx_enable_sync(rmt_dev_t *dev, bool enable)
{
dev->tx_sim.tx_sim_en = enable;
}
/**
* @brief Clear the TX channels synchronous group
*
* @param dev Peripheral instance address
*/
static inline void rmt_ll_tx_clear_sync_group(rmt_dev_t *dev)
{
dev->tx_sim.val &= ~(0x0F);
}
/**
* @brief Add TX channels to the synchronous group
*
* @param dev Peripheral instance address
* @param channel_mask Mask of TX channels to be added to the synchronous group
*/
static inline void rmt_ll_tx_sync_group_add_channels(rmt_dev_t *dev, uint32_t channel_mask)
{
dev->tx_sim.val |= (channel_mask & 0x0F);
}
/**
* @brief Remove TX channels from the synchronous group
*
* @param dev Peripheral instance address
* @param channel_mask Mask of TX channels to be removed from the synchronous group
*/
static inline void rmt_ll_tx_sync_group_remove_channels(rmt_dev_t *dev, uint32_t channel_mask)
{
dev->tx_sim.val &= ~channel_mask;
}
/**
* @brief Fix the output level when TX channel is in IDLE state
*
* @param dev Peripheral instance address
* @param channel RMT TX channel number
* @param level IDLE level (1 => high, 0 => low)
* @param enable True to fix the IDLE level, otherwise the IDLE level is determined by EOF encoder
*/
__attribute__((always_inline))
static inline void rmt_ll_tx_fix_idle_level(rmt_dev_t *dev, uint32_t channel, uint8_t level, bool enable)
{
dev->chnconf0[channel].idle_out_en_chn = enable;
dev->chnconf0[channel].idle_out_lv_chn = level;
}
/**
* @brief Set the amount of RMT symbols that can trigger the limitation interrupt
*
* @param dev Peripheral instance address
* @param channel RMT TX channel number
* @param limit Specify the number of symbols
*/
static inline void rmt_ll_tx_set_limit(rmt_dev_t *dev, uint32_t channel, uint32_t limit)
{
dev->chn_tx_lim[channel].tx_lim_chn = limit;
}
/**
* @brief Set high and low duration of carrier signal
*
* @param dev Peripheral instance address
* @param channel RMT TX channel number
* @param high_ticks Duration of high level
* @param low_ticks Duration of low level
*/
static inline void rmt_ll_tx_set_carrier_high_low_ticks(rmt_dev_t *dev, uint32_t channel, uint32_t high_ticks, uint32_t low_ticks)
{
HAL_ASSERT(high_ticks >= 1 && high_ticks <= 65536 && low_ticks >= 1 && low_ticks <= 65536 && "out of range high/low ticks");
// ticks=0 means 65536 in hardware
if (high_ticks >= 65536) {
high_ticks = 0;
}
if (low_ticks >= 65536) {
low_ticks = 0;
}
HAL_FORCE_MODIFY_U32_REG_FIELD(dev->chncarrier_duty[channel], carrier_high_chn, high_ticks);
HAL_FORCE_MODIFY_U32_REG_FIELD(dev->chncarrier_duty[channel], carrier_low_chn, low_ticks);
}
/**
* @brief Enable modulating carrier signal to TX channel
*
* @param dev Peripheral instance address
* @param channel RMT TX channel number
* @param enable True to enable, False to disable
*/
static inline void rmt_ll_tx_enable_carrier_modulation(rmt_dev_t *dev, uint32_t channel, bool enable)
{
dev->chnconf0[channel].carrier_en_chn = enable;
}
/**
* @brief Set on high or low to modulate the carrier signal
*
* @param dev Peripheral instance address
* @param channel RMT TX channel number
* @param level Which level to modulate on (0=>low level, 1=>high level)
*/
static inline void rmt_ll_tx_set_carrier_level(rmt_dev_t *dev, uint32_t channel, uint8_t level)
{
dev->chnconf0[channel].carrier_out_lv_chn = level;
}
/**
* @brief Enable to always output carrier signal, regardless of a valid data transmission
*
* @param dev Peripheral instance address
* @param channel RMT TX channel number
* @param enable True to output carrier signal in all RMT state, False to only ouput carrier signal for effective data
*/
static inline void rmt_ll_tx_enable_carrier_always_on(rmt_dev_t *dev, uint32_t channel, bool enable)
{
dev->chnconf0[channel].carrier_eff_en_chn = !enable;
}
////////////////////////////////////////RX Channel Specific/////////////////////////////////////////////////////////////
/**
* @brief Reset clock divider for RX channels by mask
*
* @param dev Peripheral instance address
* @param channel_mask Mask of RX channels
*/
static inline void rmt_ll_rx_reset_channels_clock_div(rmt_dev_t *dev, uint32_t channel_mask)
{
dev->ref_cnt_rst.val |= ((channel_mask & 0x0F) << 4);
}
/**
* @brief Set RX channel clock divider
*
* @param dev Peripheral instance address
* @param channel RMT RX channel number
* @param div Division value
*/
static inline void rmt_ll_rx_set_channel_clock_div(rmt_dev_t *dev, uint32_t channel, uint32_t div)
{
HAL_ASSERT(div >= 1 && div <= 256 && "divider out of range");
// limit the maximum divider to 256
if (div >= 256) {
div = 0; // 0 means 256 division
}
HAL_FORCE_MODIFY_U32_REG_FIELD(dev->chmconf[channel].conf0, div_cnt_chm, div);
}
/**
* @brief Reset RMT writing pointer for RX channel
*
* @param dev Peripheral instance address
* @param channel RMT RX channel number
*/
static inline void rmt_ll_rx_reset_pointer(rmt_dev_t *dev, uint32_t channel)
{
dev->chmconf[channel].conf1.mem_wr_rst_chm = 1;
dev->chmconf[channel].conf1.mem_wr_rst_chm = 0;
dev->chmconf[channel].conf1.apb_mem_rst_chm = 1;
dev->chmconf[channel].conf1.apb_mem_rst_chm = 0;
}
/**
* @brief Enable DMA access for RX channel
*
* @param dev Peripheral instance address
* @param channel RMT RX channel number
* @param enable True to enable, False to disable
*/
static inline void rmt_ll_rx_enable_dma(rmt_dev_t *dev, uint32_t channel, bool enable)
{
HAL_ASSERT(channel == 3 && "only RX channel 3 has DMA ability");
dev->chmconf[channel].conf0.dma_access_en_chm = enable;
}
/**
* @brief Enable receiving for RX channel
*
* @param dev Peripheral instance address
* @param channel RMT RX channel number
* @param enable True to enable, False to disable
*/
__attribute__((always_inline))
static inline void rmt_ll_rx_enable(rmt_dev_t *dev, uint32_t channel, bool enable)
{
dev->chmconf[channel].conf1.rx_en_chm = enable;
// rx won't be enabled until configurations updated
dev->chmconf[channel].conf1.conf_update_chm = 1;
}
/**
* @brief Set memory block number for RX channel
*
* @param dev Peripheral instance address
* @param channel RMT RX channel number
* @param block_num memory block number
*/
static inline void rmt_ll_rx_set_mem_blocks(rmt_dev_t *dev, uint32_t channel, uint8_t block_num)
{
dev->chmconf[channel].conf0.mem_size_chm = block_num;
}
/**
* @brief Set the time length for RX channel before going into IDLE state
*
* @param dev Peripheral instance address
* @param channel RMT RX channel number
* @param thres Time length threshold
*/
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;
}
/**
* @brief Set RMT memory owner for RX channel
*
* @param dev Peripheral instance address
* @param channel RMT RX channel number
* @param owner Memory owner
*/
__attribute__((always_inline))
static inline void rmt_ll_rx_set_mem_owner(rmt_dev_t *dev, uint32_t channel, rmt_ll_mem_owner_t owner)
{
dev->chmconf[channel].conf1.mem_owner_chm = owner;
}
/**
* @brief Enable filter for RX channel
*
* @param dev Peripheral instance address
* @param channel RMT RX chanenl number
* @param enable True to enable, False to disable
*/
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;
}
/**
* @brief Set RX channel filter threshold (i.e. the maximum width of one pulse signal that would be treated as a noise)
*
* @param dev Peripheral instance address
* @param channel RMT RX channel number
* @param thres Filter threshold
*/
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);
}
/**
* @brief Get RMT memory write cursor offset
*
* @param dev Peripheral instance address
* @param channel RMT RX channel number
* @return writer offset
*/
__attribute__((always_inline))
static inline uint32_t rmt_ll_rx_get_memory_writer_offset(rmt_dev_t *dev, uint32_t channel)
{
return dev->chmstatus[channel].mem_waddr_ex_chm - (channel + 4) * 48;
}
/**
* @brief Set the amount of RMT symbols that can trigger the limitation interrupt
*
* @param dev Peripheral instance address
* @param channel RMT RX channel number
* @param limit Specify the number of symbols
*/
static inline void rmt_ll_rx_set_limit(rmt_dev_t *dev, uint32_t channel, uint32_t limit)
{
dev->chm_rx_lim[channel].rx_lim_chm = limit;
}
/**
* @brief Set high and low duration of carrier signal
*
* @param dev dev Peripheral instance address
* @param channel RMT TX channel number
* @param high_ticks Duration of high level
* @param low_ticks Duration of low level
*/
static inline void rmt_ll_rx_set_carrier_high_low_ticks(rmt_dev_t *dev, uint32_t channel, uint32_t high_ticks, uint32_t low_ticks)
{
HAL_ASSERT(high_ticks >= 1 && high_ticks <= 65536 && low_ticks >= 1 && low_ticks <= 65536 && "out of range high/low ticks");
HAL_FORCE_MODIFY_U32_REG_FIELD(dev->chm_rx_carrier_rm[channel], carrier_high_thres_chm, high_ticks - 1);
HAL_FORCE_MODIFY_U32_REG_FIELD(dev->chm_rx_carrier_rm[channel], carrier_low_thres_chm, low_ticks - 1);
}
/**
* @brief Enable demodulating the carrier on RX channel
*
* @param dev Peripheral instance address
* @param channel RMT RX channel number
* @param enable True to enable, False to disable
*/
static inline void rmt_ll_rx_enable_carrier_demodulation(rmt_dev_t *dev, uint32_t channel, bool enable)
{
dev->chmconf[channel].conf0.carrier_en_chm = enable;
}
/**
* @brief Set on high or low to demodulate the carrier signal
*
* @param dev Peripheral instance address
* @param channel RMT RX channel number
* @param level Which level to demodulate (0=>low level, 1=>high level)
*/
static inline void rmt_ll_rx_set_carrier_level(rmt_dev_t *dev, uint32_t channel, uint8_t level)
{
dev->chmconf[channel].conf0.carrier_out_lv_chm = level;
}
/**
* @brief Enable RX wrap
*
* @param dev Peripheral instance address
* @param channel RMT RX channel number
* @param enable True to enable, False to disable
*/
static inline void rmt_ll_rx_enable_wrap(rmt_dev_t *dev, uint32_t channel, bool enable)
{
dev->chmconf[channel].conf1.mem_rx_wrap_en_chm = enable;
}
//////////////////////////////////////////Interrupt Specific////////////////////////////////////////////////////////////
/**
* @brief Enable RMT interrupt for specific event mask
*
* @param dev Peripheral instance address
* @param mask Event mask
* @param enable True to enable, False to disable
*/
__attribute__((always_inline))
static inline void rmt_ll_enable_interrupt(rmt_dev_t *dev, uint32_t mask, bool enable)
{
if (enable) {
dev->int_ena.val |= mask;
} else {
dev->int_ena.val &= ~mask;
}
}
/**
* @brief Clear RMT interrupt status by mask
*
* @param dev Peripheral instance address
* @param mask Interupt status mask
*/
__attribute__((always_inline))
static inline void rmt_ll_clear_interrupt_status(rmt_dev_t *dev, uint32_t mask)
{
dev->int_clr.val = mask;
}
/**
* @brief Get interrupt status register address
*
* @param dev Peripheral instance address
* @return Register address
*/
static inline volatile void *rmt_ll_get_interrupt_status_reg(rmt_dev_t *dev)
{
return &dev->int_st;
}
/**
* @brief Get interrupt status for TX channel
*
* @param dev Peripheral instance address
* @param channel RMT TX channel number
* @return Interrupt status
*/
__attribute__((always_inline))
static inline uint32_t rmt_ll_tx_get_interrupt_status(rmt_dev_t *dev, uint32_t channel)
{
return dev->int_st.val & RMT_LL_EVENT_TX_MASK(channel);
}
/**
* @brief Get interrupt raw status for TX channel
*
* @param dev Peripheral instance address
* @param channel RMT TX channel number
* @return Interrupt raw status
*/
static inline uint32_t rmt_ll_tx_get_interrupt_status_raw(rmt_dev_t *dev, uint32_t channel)
{
return dev->int_raw.val & (RMT_LL_EVENT_TX_MASK(channel) | RMT_LL_EVENT_TX_ERROR(channel));
}
/**
* @brief Get interrupt raw status for RX channel
*
* @param dev Peripheral instance address
* @param channel RMT RX channel number
* @return Interrupt raw status
*/
static inline uint32_t rmt_ll_rx_get_interrupt_status_raw(rmt_dev_t *dev, uint32_t channel)
{
return dev->int_raw.val & (RMT_LL_EVENT_RX_MASK(channel) | RMT_LL_EVENT_RX_ERROR(channel));
}
/**
* @brief Get interrupt status for RX channel
*
* @param dev Peripheral instance address
* @param channel RMT RX channel number
* @return Interrupt status
*/
__attribute__((always_inline))
static inline uint32_t rmt_ll_rx_get_interrupt_status(rmt_dev_t *dev, uint32_t channel)
{
return dev->int_st.val & RMT_LL_EVENT_RX_MASK(channel);
}
//////////////////////////////////////////Deprecated Functions//////////////////////////////////////////////////////////
/////////////////////////////The following functions are only used by the legacy driver/////////////////////////////////
/////////////////////////////They might be removed in the next major release (ESP-IDF 6.0)//////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
__attribute__((always_inline))
static inline uint32_t rmt_ll_tx_get_status_word(rmt_dev_t *dev, uint32_t channel)
{
return dev->chnstatus[channel].val;
}
__attribute__((always_inline))
static inline uint32_t rmt_ll_rx_get_status_word(rmt_dev_t *dev, uint32_t channel)
{
return dev->chmstatus[channel].val;
}
__attribute__((always_inline))
static inline uint32_t rmt_ll_tx_get_channel_clock_div(rmt_dev_t *dev, uint32_t channel)
{
uint32_t div = HAL_FORCE_READ_U32_REG_FIELD(dev->chnconf0[channel], div_cnt_chn);
return div == 0 ? 256 : div;
}
__attribute__((always_inline))
static inline uint32_t rmt_ll_rx_get_channel_clock_div(rmt_dev_t *dev, uint32_t channel)
{
uint32_t div = HAL_FORCE_READ_U32_REG_FIELD(dev->chmconf[channel].conf0, div_cnt_chm);
return div == 0 ? 256 : div;
}
__attribute__((always_inline))
static inline uint32_t rmt_ll_rx_get_idle_thres(rmt_dev_t *dev, uint32_t channel)
{
return dev->chmconf[channel].conf0.idle_thres_chm;
}
__attribute__((always_inline))
static inline uint32_t rmt_ll_tx_get_mem_blocks(rmt_dev_t *dev, uint32_t channel)
{
return dev->chnconf0[channel].mem_size_chn;
}
__attribute__((always_inline))
static inline uint32_t rmt_ll_rx_get_mem_blocks(rmt_dev_t *dev, uint32_t channel)
{
return dev->chmconf[channel].conf0.mem_size_chm;
}
__attribute__((always_inline))
static inline bool rmt_ll_tx_is_loop_enabled(rmt_dev_t *dev, uint32_t channel)
{
return dev->chnconf0[channel].tx_conti_mode_chn;
}
__attribute__((always_inline))
static inline rmt_clock_source_t rmt_ll_get_group_clock_src(rmt_dev_t *dev, uint32_t channel)
{
rmt_clock_source_t clk_src = RMT_CLK_SRC_PLL_F80M;
switch (HP_SYS_CLKRST.peri_clk_ctrl22.reg_rmt_clk_src_sel) {
case 0:
clk_src = RMT_CLK_SRC_XTAL;
break;
case 1:
clk_src = RMT_CLK_SRC_RC_FAST;
break;
case 2:
clk_src = RMT_CLK_SRC_PLL_F80M;
break;
}
return clk_src;
}
__attribute__((always_inline))
static inline bool rmt_ll_tx_is_idle_enabled(rmt_dev_t *dev, uint32_t channel)
{
return dev->chnconf0[channel].idle_out_en_chn;
}
__attribute__((always_inline))
static inline uint32_t rmt_ll_tx_get_idle_level(rmt_dev_t *dev, uint32_t channel)
{
return dev->chnconf0[channel].idle_out_lv_chn;
}
static inline bool rmt_ll_is_mem_powered_down(rmt_dev_t *dev)
{
// the RTC domain can also power down RMT memory
// so it's probably not enough to detect whether it's powered down or not
// mem_force_pd has higher priority than mem_force_pu
return (dev->sys_conf.mem_force_pd) || !(dev->sys_conf.mem_force_pu);
}
__attribute__((always_inline))
static inline uint32_t rmt_ll_rx_get_mem_owner(rmt_dev_t *dev, uint32_t channel)
{
return dev->chmconf[channel].conf1.mem_owner_chm;
}
__attribute__((always_inline))
static inline uint32_t rmt_ll_rx_get_limit(rmt_dev_t *dev, uint32_t channel)
{
return dev->chm_rx_lim[channel].rx_lim_chm;
}
__attribute__((always_inline))
static inline uint32_t rmt_ll_get_tx_end_interrupt_status(rmt_dev_t *dev)
{
return dev->int_st.val & 0x0F;
}
__attribute__((always_inline))
static inline uint32_t rmt_ll_get_rx_end_interrupt_status(rmt_dev_t *dev)
{
return (dev->int_st.val >> 16) & 0x0F;
}
__attribute__((always_inline))
static inline uint32_t rmt_ll_get_tx_err_interrupt_status(rmt_dev_t *dev)
{
return (dev->int_st.val >> 4) & 0x0F;
}
__attribute__((always_inline))
static inline uint32_t rmt_ll_get_rx_err_interrupt_status(rmt_dev_t *dev)
{
return (dev->int_st.val >> 20) & 0x0F;
}
__attribute__((always_inline))
static inline uint32_t rmt_ll_get_tx_thres_interrupt_status(rmt_dev_t *dev)
{
return (dev->int_st.val >> 8) & 0x0F;
}
__attribute__((always_inline))
static inline uint32_t rmt_ll_get_rx_thres_interrupt_status(rmt_dev_t *dev)
{
return (dev->int_st.val >> 24) & 0x0F;
}
__attribute__((always_inline))
static inline uint32_t rmt_ll_get_tx_loop_interrupt_status(rmt_dev_t *dev)
{
return (dev->int_st.val >> 12) & 0x0F;
}
#ifdef __cplusplus
}
#endif

View File

@@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2019-2022 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2019-2023 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@@ -16,13 +16,13 @@
#include "hal/misc.h" #include "hal/misc.h"
#include "hal/assert.h" #include "hal/assert.h"
#include "soc/rmt_struct.h" #include "soc/rmt_struct.h"
#include "soc/system_reg.h"
#include "hal/rmt_types.h" #include "hal/rmt_types.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
#define RMT_LL_EVENT_TX_DONE(channel) (1 << ((channel) * 3)) #define RMT_LL_EVENT_TX_DONE(channel) (1 << ((channel) * 3))
#define RMT_LL_EVENT_TX_THRES(channel) (1 << ((channel) + 12)) #define RMT_LL_EVENT_TX_THRES(channel) (1 << ((channel) + 12))
#define RMT_LL_EVENT_TX_LOOP_END(channel) (1 << ((channel) + 16)) #define RMT_LL_EVENT_TX_LOOP_END(channel) (1 << ((channel) + 16))
@@ -42,6 +42,41 @@ typedef enum {
RMT_LL_MEM_OWNER_HW = 1, RMT_LL_MEM_OWNER_HW = 1,
} rmt_ll_mem_owner_t; } rmt_ll_mem_owner_t;
/**
* @brief Enable the bus clock for RMT module
*
* @param group_id Group ID
* @param enable true to enable, false to disable
*/
static inline void rmt_ll_enable_bus_clock(int group_id, bool enable)
{
(void)group_id;
uint32_t reg_val = READ_PERI_REG(DPORT_PERIP_CLK_EN0_REG);
reg_val &= ~DPORT_RMT_CLK_EN_M;
reg_val |= enable << DPORT_RMT_CLK_EN_S;
WRITE_PERI_REG(DPORT_PERIP_CLK_EN0_REG, reg_val);
}
/// use a macro to wrap the function, force the caller to use it in a critical section
/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance
#define rmt_ll_enable_bus_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; rmt_ll_enable_bus_clock(__VA_ARGS__)
/**
* @brief Reset the RMT module
*
* @param group_id Group ID
*/
static inline void rmt_ll_reset_register(int group_id)
{
(void)group_id;
WRITE_PERI_REG(DPORT_PERIP_RST_EN0_REG, DPORT_RMT_RST_M);
WRITE_PERI_REG(DPORT_PERIP_RST_EN0_REG, 0);
}
/// use a macro to wrap the function, force the caller to use it in a critical section
/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance
#define rmt_ll_reset_register(...) (void)__DECLARE_RCC_ATOMIC_ENV; rmt_ll_reset_register(__VA_ARGS__)
/** /**
* @brief Enable clock gate for register and memory * @brief Enable clock gate for register and memory
* *

View File

@@ -16,6 +16,7 @@
#include "hal/misc.h" #include "hal/misc.h"
#include "hal/assert.h" #include "hal/assert.h"
#include "soc/rmt_struct.h" #include "soc/rmt_struct.h"
#include "soc/system_struct.h"
#include "hal/rmt_types.h" #include "hal/rmt_types.h"
#ifdef __cplusplus #ifdef __cplusplus
@@ -41,6 +42,38 @@ typedef enum {
RMT_LL_MEM_OWNER_HW = 1, RMT_LL_MEM_OWNER_HW = 1,
} rmt_ll_mem_owner_t; } rmt_ll_mem_owner_t;
/**
* @brief Enable the bus clock for RMT module
*
* @param group_id Group ID
* @param enable true to enable, false to disable
*/
static inline void rmt_ll_enable_bus_clock(int group_id, bool enable)
{
(void)group_id;
SYSTEM.perip_clk_en0.rmt_clk_en = enable;
}
/// use a macro to wrap the function, force the caller to use it in a critical section
/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance
#define rmt_ll_enable_bus_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; rmt_ll_enable_bus_clock(__VA_ARGS__)
/**
* @brief Reset the RMT module
*
* @param group_id Group ID
*/
static inline void rmt_ll_reset_register(int group_id)
{
(void)group_id;
SYSTEM.perip_rst_en0.rmt_rst = 1;
SYSTEM.perip_rst_en0.rmt_rst = 0;
}
/// use a macro to wrap the function, force the caller to use it in a critical section
/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance
#define rmt_ll_reset_register(...) (void)__DECLARE_RCC_ATOMIC_ENV; rmt_ll_reset_register(__VA_ARGS__)
/** /**
* @brief Enable clock gate for register and memory * @brief Enable clock gate for register and memory
* *

View File

@@ -14,7 +14,6 @@ void rmt_hal_init(rmt_hal_context_t *hal)
rmt_ll_enable_mem_access_nonfifo(hal->regs, true); // APB access the RMTMEM in nonfifo mode rmt_ll_enable_mem_access_nonfifo(hal->regs, true); // APB access the RMTMEM in nonfifo mode
rmt_ll_enable_interrupt(hal->regs, UINT32_MAX, false); // disable all interupt events rmt_ll_enable_interrupt(hal->regs, UINT32_MAX, false); // disable all interupt events
rmt_ll_clear_interrupt_status(hal->regs, UINT32_MAX); // clear all pending events rmt_ll_clear_interrupt_status(hal->regs, UINT32_MAX); // clear all pending events
rmt_ll_enable_group_clock(hal->regs, true); // enable clock source
#if SOC_RMT_SUPPORT_TX_SYNCHRO #if SOC_RMT_SUPPORT_TX_SYNCHRO
rmt_ll_tx_clear_sync_group(hal->regs); rmt_ll_tx_clear_sync_group(hal->regs);
#endif // SOC_RMT_SUPPORT_TX_SYNCHRO #endif // SOC_RMT_SUPPORT_TX_SYNCHRO
@@ -25,7 +24,6 @@ void rmt_hal_deinit(rmt_hal_context_t *hal)
rmt_ll_enable_interrupt(hal->regs, UINT32_MAX, false); // disable all interupt events rmt_ll_enable_interrupt(hal->regs, UINT32_MAX, false); // disable all interupt events
rmt_ll_clear_interrupt_status(hal->regs, UINT32_MAX); // clear all pending events rmt_ll_clear_interrupt_status(hal->regs, UINT32_MAX); // clear all pending events
rmt_ll_power_down_mem(hal->regs, true); // turn off RMTMEM power domain rmt_ll_power_down_mem(hal->regs, true); // turn off RMTMEM power domain
rmt_ll_enable_group_clock(hal->regs, false); // disable clock source
hal->regs = NULL; hal->regs = NULL;
} }

View File

@@ -55,6 +55,10 @@ config SOC_RTC_MEM_SUPPORTED
bool bool
default y default y
config SOC_RMT_SUPPORTED
bool
default y
config SOC_I2C_SUPPORTED config SOC_I2C_SUPPORTED
bool bool
default y default y
@@ -489,15 +493,15 @@ config SOC_RMT_GROUPS
config SOC_RMT_TX_CANDIDATES_PER_GROUP config SOC_RMT_TX_CANDIDATES_PER_GROUP
int int
default 2 default 4
config SOC_RMT_RX_CANDIDATES_PER_GROUP config SOC_RMT_RX_CANDIDATES_PER_GROUP
int int
default 2 default 4
config SOC_RMT_CHANNELS_PER_GROUP config SOC_RMT_CHANNELS_PER_GROUP
int int
default 4 default 8
config SOC_RMT_MEM_WORDS_PER_CHANNEL config SOC_RMT_MEM_WORDS_PER_CHANNEL
int int
@@ -515,6 +519,14 @@ config SOC_RMT_SUPPORT_TX_ASYNC_STOP
bool bool
default y default y
config SOC_RMT_SUPPORT_TX_LOOP_COUNT
bool
default y
config SOC_RMT_SUPPORT_TX_LOOP_AUTO_STOP
bool
default y
config SOC_RMT_SUPPORT_TX_SYNCHRO config SOC_RMT_SUPPORT_TX_SYNCHRO
bool bool
default y default y
@@ -527,7 +539,7 @@ config SOC_RMT_SUPPORT_XTAL
bool bool
default y default y
config SOC_RMT_SUPPORT_RC_FAST config SOC_RMT_SUPPORT_DMA
bool bool
default y default y

View File

@@ -213,6 +213,42 @@ typedef enum {
//////////////////////////////////////////////////RMT/////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////RMT///////////////////////////////////////////////////////////////////
/**
* @brief Array initializer for all supported clock sources of RMT
*/
#if SOC_CLK_TREE_SUPPORTED
#define SOC_RMT_CLKS {SOC_MOD_CLK_PLL_F80M, SOC_MOD_CLK_RC_FAST, SOC_MOD_CLK_XTAL}
#else
#define SOC_RMT_CLKS {SOC_MOD_CLK_XTAL}
#endif
/**
* @brief Type of RMT clock source
*/
typedef enum {
RMT_CLK_SRC_PLL_F80M = SOC_MOD_CLK_PLL_F80M, /*!< Select PLL_F80M as the source clock */
RMT_CLK_SRC_RC_FAST = SOC_MOD_CLK_RC_FAST, /*!< Select RC_FAST as the source clock */
RMT_CLK_SRC_XTAL = SOC_MOD_CLK_XTAL, /*!< Select XTAL as the source clock */
#if SOC_CLK_TREE_SUPPORTED
RMT_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_F80M, /*!< Select PLL_F80M as the default choice */
#else
RMT_CLK_SRC_DEFAULT = SOC_MOD_CLK_XTAL, /*!< Select XTAL as the default choice */
#endif
} soc_periph_rmt_clk_src_t;
/**
* @brief Type of RMT clock source, reserved for the legacy RMT driver
*/
typedef enum {
RMT_BASECLK_PLL_F80M = SOC_MOD_CLK_PLL_F80M, /*!< RMT source clock is PLL_F80M */
RMT_BASECLK_XTAL = SOC_MOD_CLK_XTAL, /*!< RMT source clock is XTAL */
#if SOC_CLK_TREE_SUPPORTED
RMT_BASECLK_DEFAULT = SOC_MOD_CLK_PLL_F80M, /*!< RMT source clock default choice is PLL_F80M */
#else
RMT_BASECLK_DEFAULT = SOC_MOD_CLK_XTAL, /*!< RMT source clock default choice is XTAL */
#endif
} soc_periph_rmt_clk_src_legacy_t;
//////////////////////////////////////////////////Temp Sensor/////////////////////////////////////////////////////////// //////////////////////////////////////////////////Temp Sensor///////////////////////////////////////////////////////////
///////////////////////////////////////////////////UART///////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////UART/////////////////////////////////////////////////////////////////

View File

@@ -6,6 +6,7 @@
#pragma once #pragma once
#include <stdint.h> #include <stdint.h>
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
@@ -16,7 +17,7 @@ extern "C" {
*/ */
typedef union { typedef union {
struct { struct {
/** chndata : HRO; bitpos: [31:0]; default: 0; /** chndata : RO; bitpos: [31:0]; default: 0;
* Read and write data for channel n via APB FIFO. * Read and write data for channel n via APB FIFO.
*/ */
uint32_t chndata: 32; uint32_t chndata: 32;
@@ -29,7 +30,7 @@ typedef union {
*/ */
typedef union { typedef union {
struct { struct {
/** chmdata : HRO; bitpos: [31:0]; default: 0; /** chmdata : RO; bitpos: [31:0]; default: 0;
* Read and write data for channel $n via APB FIFO. * Read and write data for channel $n via APB FIFO.
*/ */
uint32_t chmdata: 32; uint32_t chmdata: 32;
@@ -37,78 +38,85 @@ typedef union {
uint32_t val; uint32_t val;
} rmt_chmdata_reg_t; } rmt_chmdata_reg_t;
/** Group: Configuration registers */ /** Group: Configuration registers */
/** Type of chnconf0 register /** Type of chnconf0 register
* Channel n configure register 0 * Channel n configure register 0
*/ */
typedef union { typedef union {
struct { struct {
/** tx_start_ch0 : WT; bitpos: [0]; default: 0; /** tx_start_chn : WT; bitpos: [0]; default: 0;
* Set this bit to start sending data on CHANNELn. * Set this bit to start sending data on CHANNELn.
*/ */
uint32_t tx_start_ch0:1; uint32_t tx_start_chn: 1;
/** mem_rd_rst_ch0 : WT; bitpos: [1]; default: 0; /** mem_rd_rst_chn : WT; bitpos: [1]; default: 0;
* Set this bit to reset read ram address for CHANNELn by accessing transmitter. * Set this bit to reset read ram address for CHANNELn by accessing transmitter.
*/ */
uint32_t mem_rd_rst_ch0:1; uint32_t mem_rd_rst_chn: 1;
/** apb_mem_rst_ch0 : WT; bitpos: [2]; default: 0; /** apb_mem_rst_chn : WT; bitpos: [2]; default: 0;
* Set this bit to reset W/R ram address for CHANNELn by accessing apb fifo. * Set this bit to reset W/R ram address for CHANNELn by accessing apb fifo.
*/ */
uint32_t apb_mem_rst_ch0:1; uint32_t apb_mem_rst_chn: 1;
/** tx_conti_mode_ch0 : R/W; bitpos: [3]; default: 0; /** tx_conti_mode_chn : R/W; bitpos: [3]; default: 0;
* Set this bit to restart transmission from the first data to the last data in * Set this bit to restart transmission from the first data to the last data in
* CHANNELn. * CHANNELn.
*/ */
uint32_t tx_conti_mode_ch0:1; uint32_t tx_conti_mode_chn: 1;
/** mem_tx_wrap_en_ch0 : R/W; bitpos: [4]; default: 0; /** mem_tx_wrap_en_chn : R/W; bitpos: [4]; default: 0;
* This is the channel n enable bit for wraparound mode: it will resume sending at the * This is the channel n enable bit for wraparound mode: it will resume sending at the
* start when the data to be sent is more than its memory size. * start when the data to be sent is more than its memory size.
*/ */
uint32_t mem_tx_wrap_en_ch0:1; uint32_t mem_tx_wrap_en_chn: 1;
/** idle_out_lv_ch0 : R/W; bitpos: [5]; default: 0; /** idle_out_lv_chn : R/W; bitpos: [5]; default: 0;
* This bit configures the level of output signal in CHANNELn when the latter is in * This bit configures the level of output signal in CHANNELn when the latter is in
* IDLE state. * IDLE state.
*/ */
uint32_t idle_out_lv_ch0:1; uint32_t idle_out_lv_chn: 1;
/** idle_out_en_ch0 : R/W; bitpos: [6]; default: 0; /** idle_out_en_chn : R/W; bitpos: [6]; default: 0;
* This is the output enable-control bit for CHANNELn in IDLE state. * This is the output enable-control bit for CHANNELn in IDLE state.
*/ */
uint32_t idle_out_en_ch0:1; uint32_t idle_out_en_chn: 1;
/** tx_stop_ch0 : R/W/SC; bitpos: [7]; default: 0; /** tx_stop_chn : R/W/SC; bitpos: [7]; default: 0;
* Set this bit to stop the transmitter of CHANNELn sending data out. * Set this bit to stop the transmitter of CHANNELn sending data out.
*/ */
uint32_t tx_stop_ch0:1; uint32_t tx_stop_chn: 1;
/** div_cnt_ch0 : R/W; bitpos: [15:8]; default: 2; /** div_cnt_chn : R/W; bitpos: [15:8]; default: 2;
* This register is used to configure the divider for clock of CHANNELn. * This register is used to configure the divider for clock of CHANNELn.
*/ */
uint32_t div_cnt_ch0:8; uint32_t div_cnt_chn: 8;
/** mem_size_ch0 : R/W; bitpos: [19:16]; default: 1; /** mem_size_chn : R/W; bitpos: [19:16]; default: 1;
* This register is used to configure the maximum size of memory allocated to CHANNELn. * This register is used to configure the maximum size of memory allocated to CHANNELn.
*/ */
uint32_t mem_size_ch0:4; uint32_t mem_size_chn: 4;
/** carrier_eff_en_ch0 : R/W; bitpos: [20]; default: 1; /** carrier_eff_en_chn : R/W; bitpos: [20]; default: 1;
* 1: Add carrier modulation on the output signal only at the send data state for * 1: Add carrier modulation on the output signal only at the send data state for
* CHANNELn. 0: Add carrier modulation on the output signal at all state for CHANNELn. * CHANNELn. 0: Add carrier modulation on the output signal at all state for CHANNELn.
* Only valid when RMT_CARRIER_EN_CHn is 1. * Only valid when RMT_CARRIER_EN_CHn is 1.
*/ */
uint32_t carrier_eff_en_ch0:1; uint32_t carrier_eff_en_chn: 1;
/** carrier_en_ch0 : R/W; bitpos: [21]; default: 1; /** carrier_en_chn : R/W; bitpos: [21]; default: 1;
* This is the carrier modulation enable-control bit for CHANNELn. 1: Add carrier * This is the carrier modulation enable-control bit for CHANNELn. 1: Add carrier
* modulation in the output signal. 0: No carrier modulation in sig_out. * modulation in the output signal. 0: No carrier modulation in sig_out.
*/ */
uint32_t carrier_en_ch0:1; uint32_t carrier_en_chn: 1;
/** carrier_out_lv_ch0 : R/W; bitpos: [22]; default: 1; /** carrier_out_lv_chn : R/W; bitpos: [22]; default: 1;
* This bit is used to configure the position of carrier wave for CHANNELn.1'h0: add * This bit is used to configure the position of carrier wave for CHANNELn.
* carrier wave on low level.1'h1: add carrier wave on high level. * 1'h0: add carrier wave on low level.
* 1'h1: add carrier wave on high level.
*/ */
uint32_t carrier_out_lv_ch0:1; uint32_t carrier_out_lv_chn: 1;
uint32_t reserved_23:1; /** afifo_rst_chn : WT; bitpos: [23]; default: 0;
/** conf_update_ch0 : WT; bitpos: [24]; default: 0; * Reserved
*/
uint32_t afifo_rst_chn: 1;
/** conf_update_chn : WT; bitpos: [24]; default: 0;
* synchronization bit for CHANNELn * synchronization bit for CHANNELn
*/ */
uint32_t conf_update_ch0:1; uint32_t conf_update_chn: 1;
uint32_t reserved_25:7; /** dma_access_en_chn : WT; bitpos: [25]; default: 0;
* DMA access control bit for CHANNELn (only CHANNEL3 has this control bit)
*/
uint32_t dma_access_en_chn: 1;
uint32_t reserved_26: 6;
}; };
uint32_t val; uint32_t val;
} rmt_chnconf0_reg_t; } rmt_chnconf0_reg_t;
@@ -118,30 +126,34 @@ typedef union {
*/ */
typedef union { typedef union {
struct { struct {
/** div_cnt_ch4 : R/W; bitpos: [7:0]; default: 2; /** div_cnt_chm : R/W; bitpos: [7:0]; default: 2;
* This register is used to configure the divider for clock of CHANNELm. * This register is used to configure the divider for clock of CHANNELm.
*/ */
uint32_t div_cnt_ch4:8; uint32_t div_cnt_chm: 8;
/** idle_thres_ch4 : R/W; bitpos: [22:8]; default: 32767; /** idle_thres_chm : R/W; bitpos: [22:8]; default: 32767;
* When no edge is detected on the input signal and continuous clock cycles is longer * When no edge is detected on the input signal and continuous clock cycles is longer
* than this register value, received process is finished. * than this register value, received process is finished.
*/ */
uint32_t idle_thres_ch4:15; uint32_t idle_thres_chm: 15;
uint32_t reserved_23:1; /** dma_access_en_m : WT; bitpos: [23]; default: 0;
/** mem_size_ch4 : R/W; bitpos: [27:24]; default: 1; * DMA access control bit for CHANNELm (only channel7 has this control bit)
*/
uint32_t dma_access_en_chm: 1;
/** mem_size_chm : R/W; bitpos: [27:24]; default: 1;
* This register is used to configure the maximum size of memory allocated to CHANNELm. * This register is used to configure the maximum size of memory allocated to CHANNELm.
*/ */
uint32_t mem_size_ch4:4; uint32_t mem_size_chm: 4;
/** carrier_en_ch4 : R/W; bitpos: [28]; default: 1; /** carrier_en_chm : R/W; bitpos: [28]; default: 1;
* This is the carrier modulation enable-control bit for CHANNELm. 1: Add carrier * This is the carrier modulation enable-control bit for CHANNELm. 1: Add carrier
* modulation in the output signal. 0: No carrier modulation in sig_out. * modulation in the output signal. 0: No carrier modulation in sig_out.
*/ */
uint32_t carrier_en_ch4:1; uint32_t carrier_en_chm: 1;
/** carrier_out_lv_ch4 : R/W; bitpos: [29]; default: 1; /** carrier_out_lv_chm : R/W; bitpos: [29]; default: 1;
* This bit is used to configure the position of carrier wave for CHANNELm.1'h0: add * This bit is used to configure the position of carrier wave for CHANNELm.
* carrier wave on low level.1'h1: add carrier wave on high level. * 1'h0: add carrier wave on low level.
* 1'h1: add carrier wave on high level.
*/ */
uint32_t carrier_out_lv_ch4:1; uint32_t carrier_out_lv_chm: 1;
uint32_t reserved_30: 2; uint32_t reserved_30: 2;
}; };
uint32_t val; uint32_t val;
@@ -152,42 +164,46 @@ typedef union {
*/ */
typedef union { typedef union {
struct { struct {
/** rx_en_ch4 : R/W; bitpos: [0]; default: 0; /** rx_en_chm : R/W; bitpos: [0]; default: 0;
* Set this bit to enable receiver to receive data on CHANNELm. * Set this bit to enable receiver to receive data on CHANNELm.
*/ */
uint32_t rx_en_ch4:1; uint32_t rx_en_chm: 1;
/** mem_wr_rst_ch4 : WT; bitpos: [1]; default: 0; /** mem_wr_rst_chm : WT; bitpos: [1]; default: 0;
* Set this bit to reset write ram address for CHANNELm by accessing receiver. * Set this bit to reset write ram address for CHANNELm by accessing receiver.
*/ */
uint32_t mem_wr_rst_ch4:1; uint32_t mem_wr_rst_chm: 1;
/** apb_mem_rst_ch4 : WT; bitpos: [2]; default: 0; /** apb_mem_rst_chm : WT; bitpos: [2]; default: 0;
* Set this bit to reset W/R ram address for CHANNELm by accessing apb fifo. * Set this bit to reset W/R ram address for CHANNELm by accessing apb fifo.
*/ */
uint32_t apb_mem_rst_ch4:1; uint32_t apb_mem_rst_chm: 1;
/** mem_owner_ch4 : R/W/SC; bitpos: [3]; default: 1; /** mem_owner_chm : R/W/SC; bitpos: [3]; default: 1;
* This register marks the ownership of CHANNELm's ram block.1'h1: Receiver is using * This register marks the ownership of CHANNELm's ram block.
* the ram. 1'h0: APB bus is using the ram. * 1'h1: Receiver is using the ram.
* 1'h0: APB bus is using the ram.
*/ */
uint32_t mem_owner_ch4:1; uint32_t mem_owner_chm: 1;
/** rx_filter_en_ch4 : R/W; bitpos: [4]; default: 0; /** rx_filter_en_chm : R/W; bitpos: [4]; default: 0;
* This is the receive filter's enable bit for CHANNELm. * This is the receive filter's enable bit for CHANNELm.
*/ */
uint32_t rx_filter_en_ch4:1; uint32_t rx_filter_en_chm: 1;
/** rx_filter_thres_ch4 : R/W; bitpos: [12:5]; default: 15; /** rx_filter_thres_chm : R/W; bitpos: [12:5]; default: 15;
* Ignores the input pulse when its width is smaller than this register value in APB * Ignores the input pulse when its width is smaller than this register value in APB
* clock periods (in receive mode). * clock periods (in receive mode).
*/ */
uint32_t rx_filter_thres_ch4:8; uint32_t rx_filter_thres_chm: 8;
/** mem_rx_wrap_en_ch4 : R/W; bitpos: [13]; default: 0; /** mem_rx_wrap_en_chm : R/W; bitpos: [13]; default: 0;
* This is the channel m enable bit for wraparound mode: it will resume receiving at * This is the channel m enable bit for wraparound mode: it will resume receiving at
* the start when the data to be received is more than its memory size. * the start when the data to be received is more than its memory size.
*/ */
uint32_t mem_rx_wrap_en_ch4:1; uint32_t mem_rx_wrap_en_chm: 1;
uint32_t reserved_14:1; /** afifo_rst_chm : WT; bitpos: [14]; default: 0;
/** conf_update_ch4 : WT; bitpos: [15]; default: 0; * Reserved
*/
uint32_t afifo_rst_chm: 1;
/** conf_update_chm : WT; bitpos: [15]; default: 0;
* synchronization bit for CHANNELm * synchronization bit for CHANNELm
*/ */
uint32_t conf_update_ch4:1; uint32_t conf_update_chm: 1;
uint32_t reserved_16: 16; uint32_t reserved_16: 16;
}; };
uint32_t val; uint32_t val;
@@ -198,16 +214,16 @@ typedef union {
*/ */
typedef union { typedef union {
struct { struct {
/** carrier_low_thres_ch4 : R/W; bitpos: [15:0]; default: 0; /** carrier_low_thres_chm : R/W; bitpos: [15:0]; default: 0;
* The low level period in a carrier modulation mode is * The low level period in a carrier modulation mode is
* (REG_RMT_REG_CARRIER_LOW_THRES_CHm + 1) for channel m. * (REG_RMT_REG_CARRIER_LOW_THRES_CHm + 1) for channel m.
*/ */
uint32_t carrier_low_thres_ch4:16; uint32_t carrier_low_thres_chm: 16;
/** carrier_high_thres_ch4 : R/W; bitpos: [31:16]; default: 0; /** carrier_high_thres_chm : R/W; bitpos: [31:16]; default: 0;
* The high level period in a carrier modulation mode is * The high level period in a carrier modulation mode is
* (REG_RMT_REG_CARRIER_HIGH_THRES_CHm + 1) for channel m. * (REG_RMT_REG_CARRIER_HIGH_THRES_CHm + 1) for channel m.
*/ */
uint32_t carrier_high_thres_ch4:16; uint32_t carrier_high_thres_chm: 16;
}; };
uint32_t val; uint32_t val;
} rmt_chm_rx_carrier_rm_reg_t; } rmt_chm_rx_carrier_rm_reg_t;
@@ -306,38 +322,37 @@ typedef union {
uint32_t val; uint32_t val;
} rmt_ref_cnt_rst_reg_t; } rmt_ref_cnt_rst_reg_t;
/** Group: Status registers */ /** Group: Status registers */
/** Type of chnstatus register /** Type of chnstatus register
* Channel n status register * Channel n status register
*/ */
typedef union { typedef union {
struct { struct {
/** mem_raddr_ex_ch0 : RO; bitpos: [9:0]; default: 0; /** mem_raddr_ex_chn : RO; bitpos: [9:0]; default: 0;
* This register records the memory address offset when transmitter of CHANNELn is * This register records the memory address offset when transmitter of CHANNELn is
* using the RAM. * using the RAM.
*/ */
uint32_t mem_raddr_ex_ch0:10; uint32_t mem_raddr_ex_chn: 10;
uint32_t reserved_10: 1; uint32_t reserved_10: 1;
/** apb_mem_waddr_ch0 : RO; bitpos: [20:11]; default: 0; /** apb_mem_waddr_chn : RO; bitpos: [20:11]; default: 0;
* This register records the memory address offset when writes RAM over APB bus. * This register records the memory address offset when writes RAM over APB bus.
*/ */
uint32_t apb_mem_waddr_ch0:10; uint32_t apb_mem_waddr_chn: 10;
uint32_t reserved_21: 1; uint32_t reserved_21: 1;
/** state_ch0 : RO; bitpos: [24:22]; default: 0; /** state_chn : RO; bitpos: [24:22]; default: 0;
* This register records the FSM status of CHANNELn. * This register records the FSM status of CHANNELn.
*/ */
uint32_t state_ch0:3; uint32_t state_chn: 3;
/** mem_empty_ch0 : RO; bitpos: [25]; default: 0; /** mem_empty_chn : RO; bitpos: [25]; default: 0;
* This status bit will be set when the data to be set is more than memory size and * This status bit will be set when the data to be set is more than memory size and
* the wraparound mode is disabled. * the wraparound mode is disabled.
*/ */
uint32_t mem_empty_ch0:1; uint32_t mem_empty_chn: 1;
/** apb_mem_wr_err_ch0 : RO; bitpos: [26]; default: 0; /** apb_mem_wr_err_chn : RO; bitpos: [26]; default: 0;
* This status bit will be set if the offset address out of memory size when writes * This status bit will be set if the offset address out of memory size when writes
* via APB bus. * via APB bus.
*/ */
uint32_t apb_mem_wr_err_ch0:1; uint32_t apb_mem_wr_err_chn: 1;
uint32_t reserved_27: 5; uint32_t reserved_27: 5;
}; };
uint32_t val; uint32_t val;
@@ -348,40 +363,39 @@ typedef union {
*/ */
typedef union { typedef union {
struct { struct {
/** mem_waddr_ex_ch4 : RO; bitpos: [9:0]; default: 192; /** mem_waddr_ex_chm : RO; bitpos: [9:0]; default: 192;
* This register records the memory address offset when receiver of CHANNELm is using * This register records the memory address offset when receiver of CHANNELm is using
* the RAM. * the RAM.
*/ */
uint32_t mem_waddr_ex_ch4:10; uint32_t mem_waddr_ex_chm: 10;
uint32_t reserved_10: 1; uint32_t reserved_10: 1;
/** apb_mem_raddr_ch4 : RO; bitpos: [20:11]; default: 192; /** apb_mem_raddr_chm : RO; bitpos: [20:11]; default: 192;
* This register records the memory address offset when reads RAM over APB bus. * This register records the memory address offset when reads RAM over APB bus.
*/ */
uint32_t apb_mem_raddr_ch4:10; uint32_t apb_mem_raddr_chm: 10;
uint32_t reserved_21: 1; uint32_t reserved_21: 1;
/** state_ch4 : RO; bitpos: [24:22]; default: 0; /** state_chm : RO; bitpos: [24:22]; default: 0;
* This register records the FSM status of CHANNELm. * This register records the FSM status of CHANNELm.
*/ */
uint32_t state_ch4:3; uint32_t state_chm: 3;
/** mem_owner_err_ch4 : RO; bitpos: [25]; default: 0; /** mem_owner_err_chm : RO; bitpos: [25]; default: 0;
* This status bit will be set when the ownership of memory block is wrong. * This status bit will be set when the ownership of memory block is wrong.
*/ */
uint32_t mem_owner_err_ch4:1; uint32_t mem_owner_err_chm: 1;
/** mem_full_ch4 : RO; bitpos: [26]; default: 0; /** mem_full_chm : RO; bitpos: [26]; default: 0;
* This status bit will be set if the receiver receives more data than the memory size. * This status bit will be set if the receiver receives more data than the memory size.
*/ */
uint32_t mem_full_ch4:1; uint32_t mem_full_chm: 1;
/** apb_mem_rd_err_ch4 : RO; bitpos: [27]; default: 0; /** apb_mem_rd_err_chm : RO; bitpos: [27]; default: 0;
* This status bit will be set if the offset address out of memory size when reads via * This status bit will be set if the offset address out of memory size when reads via
* APB bus. * APB bus.
*/ */
uint32_t apb_mem_rd_err_ch4:1; uint32_t apb_mem_rd_err_chm: 1;
uint32_t reserved_28: 4; uint32_t reserved_28: 4;
}; };
uint32_t val; uint32_t val;
} rmt_chmstatus_reg_t; } rmt_chmstatus_reg_t;
/** Group: Interrupt registers */ /** Group: Interrupt registers */
/** Type of int_raw register /** Type of int_raw register
* Raw interrupt status * Raw interrupt status
@@ -915,56 +929,54 @@ typedef union {
uint32_t val; uint32_t val;
} rmt_int_clr_reg_t; } rmt_int_clr_reg_t;
/** Group: Carrier wave duty cycle registers */ /** Group: Carrier wave duty cycle registers */
/** Type of chncarrier_duty register /** Type of chncarrier_duty register
* Channel n duty cycle configuration register * Channel n duty cycle configuration register
*/ */
typedef union { typedef union {
struct { struct {
/** carrier_low_ch0 : R/W; bitpos: [15:0]; default: 64; /** carrier_low_chn : R/W; bitpos: [15:0]; default: 64;
* This register is used to configure carrier wave 's low level clock period for * This register is used to configure carrier wave 's low level clock period for
* CHANNELn. * CHANNELn.
*/ */
uint32_t carrier_low_ch0:16; uint32_t carrier_low_chn: 16;
/** carrier_high_ch0 : R/W; bitpos: [31:16]; default: 64; /** carrier_high_chn : R/W; bitpos: [31:16]; default: 64;
* This register is used to configure carrier wave 's high level clock period for * This register is used to configure carrier wave 's high level clock period for
* CHANNELn. * CHANNELn.
*/ */
uint32_t carrier_high_ch0:16; uint32_t carrier_high_chn: 16;
}; };
uint32_t val; uint32_t val;
} rmt_chncarrier_duty_reg_t; } rmt_chncarrier_duty_reg_t;
/** Group: Tx event configuration registers */ /** Group: Tx event configuration registers */
/** Type of chn_tx_lim register /** Type of chn_tx_lim register
* Channel n Tx event configuration register * Channel n Tx event configuration register
*/ */
typedef union { typedef union {
struct { struct {
/** tx_lim_ch0 : R/W; bitpos: [8:0]; default: 128; /** tx_lim_chn : R/W; bitpos: [8:0]; default: 128;
* This register is used to configure the maximum entries that CHANNELn can send out. * This register is used to configure the maximum entries that CHANNELn can send out.
*/ */
uint32_t tx_lim_ch0:9; uint32_t tx_lim_chn: 9;
/** tx_loop_num_ch0 : R/W; bitpos: [18:9]; default: 0; /** tx_loop_num_chn : R/W; bitpos: [18:9]; default: 0;
* This register is used to configure the maximum loop count when tx_conti_mode is * This register is used to configure the maximum loop count when tx_conti_mode is
* valid. * valid.
*/ */
uint32_t tx_loop_num_ch0:10; uint32_t tx_loop_num_chn: 10;
/** tx_loop_cnt_en_ch0 : R/W; bitpos: [19]; default: 0; /** tx_loop_cnt_en_chn : R/W; bitpos: [19]; default: 0;
* This register is the enabled bit for loop count. * This register is the enabled bit for loop count.
*/ */
uint32_t tx_loop_cnt_en_ch0:1; uint32_t tx_loop_cnt_en_chn: 1;
/** loop_count_reset_ch0 : WT; bitpos: [20]; default: 0; /** loop_count_reset_chn : WT; bitpos: [20]; default: 0;
* This register is used to reset the loop count when tx_conti_mode is valid. * This register is used to reset the loop count when tx_conti_mode is valid.
*/ */
uint32_t loop_count_reset_ch0:1; uint32_t loop_count_reset_chn: 1;
/** loop_stop_en_ch0 : R/W; bitpos: [21]; default: 0; /** loop_stop_en_chn : R/W; bitpos: [21]; default: 0;
* This bit is used to enable the loop send stop function after the loop counter * This bit is used to enable the loop send stop function after the loop counter
* counts to loop number for CHANNELn. * counts to loop number for CHANNELn.
*/ */
uint32_t loop_stop_en_ch0:1; uint32_t loop_stop_en_chn: 1;
uint32_t reserved_22: 10; uint32_t reserved_22: 10;
}; };
uint32_t val; uint32_t val;
@@ -1005,23 +1017,21 @@ typedef union {
uint32_t val; uint32_t val;
} rmt_tx_sim_reg_t; } rmt_tx_sim_reg_t;
/** Group: Rx event configuration registers */ /** Group: Rx event configuration registers */
/** Type of chm_rx_lim register /** Type of chm_rx_lim register
* Channel m Rx event configuration register * Channel m Rx event configuration register
*/ */
typedef union { typedef union {
struct { struct {
/** rx_lim_ch4 : R/W; bitpos: [8:0]; default: 128; /** rx_lim_chm : R/W; bitpos: [8:0]; default: 128;
* This register is used to configure the maximum entries that CHANNELm can receive. * This register is used to configure the maximum entries that CHANNELm can receive.
*/ */
uint32_t rx_lim_ch4:9; uint32_t rx_lim_chm: 9;
uint32_t reserved_9: 23; uint32_t reserved_9: 23;
}; };
uint32_t val; uint32_t val;
} rmt_chm_rx_lim_reg_t; } rmt_chm_rx_lim_reg_t;
/** Group: Version register */ /** Group: Version register */
/** Type of date register /** Type of date register
* RMT version register * RMT version register
@@ -1037,19 +1047,14 @@ typedef union {
uint32_t val; uint32_t val;
} rmt_date_reg_t; } rmt_date_reg_t;
typedef struct rmt_dev_t {
typedef struct {
volatile rmt_chndata_reg_t chndata[4]; volatile rmt_chndata_reg_t chndata[4];
volatile rmt_chmdata_reg_t chmdata[4]; volatile rmt_chmdata_reg_t chmdata[4];
volatile rmt_chnconf0_reg_t chnconf0[4]; volatile rmt_chnconf0_reg_t chnconf0[4];
volatile rmt_chmconf0_reg_t ch4conf0; volatile struct {
volatile rmt_chmconf1_reg_t ch4conf1; rmt_chmconf0_reg_t conf0;
volatile rmt_chmconf0_reg_t ch5conf0; rmt_chmconf1_reg_t conf1;
volatile rmt_chmconf1_reg_t ch5conf1; } chmconf[4];
volatile rmt_chmconf0_reg_t ch6conf0;
volatile rmt_chmconf1_reg_t ch6conf1;
volatile rmt_chmconf0_reg_t ch7conf0;
volatile rmt_chmconf1_reg_t ch7conf1;
volatile rmt_chnstatus_reg_t chnstatus[4]; volatile rmt_chnstatus_reg_t chnstatus[4];
volatile rmt_chmstatus_reg_t chmstatus[4]; volatile rmt_chmstatus_reg_t chmstatus[4];
volatile rmt_int_raw_reg_t int_raw; volatile rmt_int_raw_reg_t int_raw;
@@ -1066,6 +1071,7 @@ typedef struct {
volatile rmt_date_reg_t date; volatile rmt_date_reg_t date;
} rmt_dev_t; } rmt_dev_t;
extern rmt_dev_t RMT;
#ifndef __cplusplus #ifndef __cplusplus
_Static_assert(sizeof(rmt_dev_t) == 0xd0, "Invalid size of rmt_dev_t structure"); _Static_assert(sizeof(rmt_dev_t) == 0xd0, "Invalid size of rmt_dev_t structure");

View File

@@ -49,7 +49,7 @@
#define SOC_RTC_FAST_MEM_SUPPORTED 1 #define SOC_RTC_FAST_MEM_SUPPORTED 1
#define SOC_RTC_MEM_SUPPORTED 1 #define SOC_RTC_MEM_SUPPORTED 1
// #define SOC_I2S_SUPPORTED 1 //TODO: IDF-6508 // #define SOC_I2S_SUPPORTED 1 //TODO: IDF-6508
// #define SOC_RMT_SUPPORTED 1 //TODO: IDF-7476 #define SOC_RMT_SUPPORTED 1
// #define SOC_SDM_SUPPORTED 1 //TODO: IDF-7551 // #define SOC_SDM_SUPPORTED 1 //TODO: IDF-7551
// #define SOC_GPSPI_SUPPORTED 1 //TODO: IDF-7502, TODO: IDF-7503 // #define SOC_GPSPI_SUPPORTED 1 //TODO: IDF-7502, TODO: IDF-7503
// #define SOC_LEDC_SUPPORTED 1 //TODO: IDF-6510 // #define SOC_LEDC_SUPPORTED 1 //TODO: IDF-6510
@@ -271,19 +271,20 @@
/*--------------------------- RMT CAPS ---------------------------------------*/ /*--------------------------- RMT CAPS ---------------------------------------*/
#define SOC_RMT_GROUPS 1U /*!< One RMT group */ #define SOC_RMT_GROUPS 1U /*!< One RMT group */
#define SOC_RMT_TX_CANDIDATES_PER_GROUP 2 /*!< Number of channels that capable of Transmit */ #define SOC_RMT_TX_CANDIDATES_PER_GROUP 4 /*!< Number of channels that capable of Transmit in each group */
#define SOC_RMT_RX_CANDIDATES_PER_GROUP 2 /*!< Number of channels that capable of Receive */ #define SOC_RMT_RX_CANDIDATES_PER_GROUP 4 /*!< Number of channels that capable of Receive in each group */
#define SOC_RMT_CHANNELS_PER_GROUP 4 /*!< Total 4 channels */ #define SOC_RMT_CHANNELS_PER_GROUP 8 /*!< Total 8 channels */
#define SOC_RMT_MEM_WORDS_PER_CHANNEL 48 /*!< Each channel owns 48 words memory (1 word = 4 Bytes) */ #define SOC_RMT_MEM_WORDS_PER_CHANNEL 48 /*!< Each channel owns 48 words memory (1 word = 4 Bytes) */
#define SOC_RMT_SUPPORT_RX_PINGPONG 1 /*!< Support Ping-Pong mode on RX path */ #define SOC_RMT_SUPPORT_RX_PINGPONG 1 /*!< Support Ping-Pong mode on RX path */
#define SOC_RMT_SUPPORT_RX_DEMODULATION 1 /*!< Support signal demodulation on RX path (i.e. remove carrier) */ #define SOC_RMT_SUPPORT_RX_DEMODULATION 1 /*!< Support signal demodulation on RX path (i.e. remove carrier) */
#define SOC_RMT_SUPPORT_TX_ASYNC_STOP 1 /*!< Support stop transmission asynchronously */ #define SOC_RMT_SUPPORT_TX_ASYNC_STOP 1 /*!< Support stop transmission asynchronously */
// #define SOC_RMT_SUPPORT_TX_LOOP_COUNT 1 /*!< Support transmit specified number of cycles in loop mode */ #define SOC_RMT_SUPPORT_TX_LOOP_COUNT 1 /*!< Support transmit specified number of cycles in loop mode */
// #define SOC_RMT_SUPPORT_TX_LOOP_AUTO_STOP 1 /*!< Hardware support of auto-stop in loop mode */ //TODO: IDF-7476 #define SOC_RMT_SUPPORT_TX_LOOP_AUTO_STOP 1 /*!< Hardware support of auto-stop in loop mode */
#define SOC_RMT_SUPPORT_TX_SYNCHRO 1 /*!< Support coordinate a group of TX channels to start simultaneously */ #define SOC_RMT_SUPPORT_TX_SYNCHRO 1 /*!< Support coordinate a group of TX channels to start simultaneously */
#define SOC_RMT_SUPPORT_TX_CARRIER_DATA_ONLY 1 /*!< TX carrier can be modulated to data phase only */ #define SOC_RMT_SUPPORT_TX_CARRIER_DATA_ONLY 1 /*!< TX carrier can be modulated to data phase only */
#define SOC_RMT_SUPPORT_XTAL 1 /*!< Support set XTAL clock as the RMT clock source */ #define SOC_RMT_SUPPORT_XTAL 1 /*!< Support set XTAL clock as the RMT clock source */
#define SOC_RMT_SUPPORT_RC_FAST 1 /*!< Support set RC_FAST as the RMT clock source */ // #define SOC_RMT_SUPPORT_RC_FAST 1 /*!< Support set RC_FAST clock as the RMT clock source */
#define SOC_RMT_SUPPORT_DMA 1 /*!< RMT peripheral can connect to DMA channel */
/*-------------------------- MCPWM CAPS --------------------------------------*/ /*-------------------------- MCPWM CAPS --------------------------------------*/
#define SOC_MCPWM_GROUPS (2U) ///< 2 MCPWM groups on the chip (i.e., the number of independent MCPWM peripherals) #define SOC_MCPWM_GROUPS (2U) ///< 2 MCPWM groups on the chip (i.e., the number of independent MCPWM peripherals)

View File

@@ -17,8 +17,8 @@ PROVIDE ( SPIMEM3 = 0x5008F000 );
PROVIDE ( I2C0 = 0x500C4000 ); PROVIDE ( I2C0 = 0x500C4000 );
PROVIDE ( I2C1 = 0x500C5000 ); PROVIDE ( I2C1 = 0x500C5000 );
PROVIDE ( UHCI0 = 0x500DF000 ); PROVIDE ( UHCI0 = 0x500DF000 );
PROVIDE ( RMT = 0x500D4000 ); PROVIDE ( RMT = 0x500A2000 );
PROVIDE ( RMTMEM = 0x500D4800 ); PROVIDE ( RMTMEM = 0x500A2800 );
PROVIDE ( LEDC = 0x500D3000 ); PROVIDE ( LEDC = 0x500D3000 );
PROVIDE ( TIMERG0 = 0x500C2000 ); PROVIDE ( TIMERG0 = 0x500C2000 );
PROVIDE ( TIMERG1 = 0x500C3000 ); PROVIDE ( TIMERG1 = 0x500C3000 );

View File

@@ -8,5 +8,44 @@
#include "soc/gpio_sig_map.h" #include "soc/gpio_sig_map.h"
const rmt_signal_conn_t rmt_periph_signals = { const rmt_signal_conn_t rmt_periph_signals = {
.groups = {
[0] = {
.module = PERIPH_RMT_MODULE,
.irq = ETS_RMT_INTR_SOURCE,
.channels = {
[0] = {
.tx_sig = RMT_SIG_PAD_OUT0_IDX,
.rx_sig = -1
},
[1] = {
.tx_sig = RMT_SIG_PAD_OUT1_IDX,
.rx_sig = -1
},
[2] = {
.tx_sig = RMT_SIG_PAD_OUT2_IDX,
.rx_sig = -1
},
[3] = {
.tx_sig = RMT_SIG_PAD_OUT3_IDX,
.rx_sig = -1
},
[4] = {
.tx_sig = -1,
.rx_sig = RMT_SIG_PAD_IN0_IDX
},
[5] = {
.tx_sig = -1,
.rx_sig = RMT_SIG_PAD_IN1_IDX
},
[6] = {
.tx_sig = -1,
.rx_sig = RMT_SIG_PAD_IN2_IDX
},
[7] = {
.tx_sig = -1,
.rx_sig = RMT_SIG_PAD_IN3_IDX
}
}
}
}
}; };

View File

@@ -141,7 +141,6 @@ api-reference/peripherals/spi_master.rst
api-reference/peripherals/index.rst api-reference/peripherals/index.rst
api-reference/peripherals/sdmmc_host.rst api-reference/peripherals/sdmmc_host.rst
api-reference/peripherals/uart.rst api-reference/peripherals/uart.rst
api-reference/peripherals/rmt.rst
api-reference/kconfig.rst api-reference/kconfig.rst
api-reference/network/esp_openthread.rst api-reference/network/esp_openthread.rst
api-reference/network/esp_eth.rst api-reference/network/esp_eth.rst

View File

@@ -1,5 +1,5 @@
| Supported Targets | ESP32 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S2 | ESP32-S3 | | Supported Targets | ESP32 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | | ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- |
# RMT Infinite Loop Transmit Example -- Dshot ESC (Electronic Speed Controller) # RMT Infinite Loop Transmit Example -- Dshot ESC (Electronic Speed Controller)
(See the README.md file in the upper level 'examples' directory for more information about examples.) (See the README.md file in the upper level 'examples' directory for more information about examples.)

View File

@@ -1,5 +1,5 @@
| Supported Targets | ESP32 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S2 | ESP32-S3 | | Supported Targets | ESP32 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | | ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- |
# IR NEC Encoding and Decoding Example # IR NEC Encoding and Decoding Example
(See the README.md file in the upper level 'examples' directory for more information about examples.) (See the README.md file in the upper level 'examples' directory for more information about examples.)

View File

@@ -1,5 +1,5 @@
| Supported Targets | ESP32 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S2 | ESP32-S3 | | Supported Targets | ESP32 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | | ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- |
# RMT Transmit Example -- LED Strip # RMT Transmit Example -- LED Strip
(See the README.md file in the upper level 'examples' directory for more information about examples.) (See the README.md file in the upper level 'examples' directory for more information about examples.)

View File

@@ -1,5 +1,5 @@
| Supported Targets | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S2 | ESP32-S3 | | Supported Targets | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 |
| ----------------- | -------- | -------- | -------- | -------- | -------- | | ----------------- | -------- | -------- | -------- | -------- | -------- | -------- |
# RMT Transmit Loop Count Example -- Musical Buzzer # RMT Transmit Loop Count Example -- Musical Buzzer

View File

@@ -1,5 +1,5 @@
| Supported Targets | ESP32 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S2 | ESP32-S3 | | Supported Targets | ESP32 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | | ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- |
# Advanced RMT Transmit & Receive Example -- Simulate 1-Wire Bus # Advanced RMT Transmit & Receive Example -- Simulate 1-Wire Bus

View File

@@ -1,5 +1,5 @@
| Supported Targets | ESP32-C6 | ESP32-H2 | ESP32-S3 | | Supported Targets | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S3 |
| ----------------- | -------- | -------- | -------- | | ----------------- | -------- | -------- | -------- | -------- |
# RMT Based Stepper Motor Smooth Controller # RMT Based Stepper Motor Smooth Controller