diff --git a/components/bootloader_support/src/esp32s31/flash_encryption_secure_features.c b/components/bootloader_support/src/esp32s31/flash_encryption_secure_features.c index 4b57850cc4..9e43e3e236 100644 --- a/components/bootloader_support/src/esp32s31/flash_encryption_secure_features.c +++ b/components/bootloader_support/src/esp32s31/flash_encryption_secure_features.c @@ -4,66 +4,66 @@ * SPDX-License-Identifier: Apache-2.0 */ - #include - #include "esp_secure_boot.h" - #include "esp_efuse.h" - #include "esp_efuse_table.h" - #include "esp_log.h" - #include "sdkconfig.h" +#include +#include "esp_secure_boot.h" +#include "esp_efuse.h" +#include "esp_efuse_table.h" +#include "esp_log.h" +#include "sdkconfig.h" - ESP_LOG_ATTR_TAG(TAG, "secure_boot"); +ESP_LOG_ATTR_TAG(TAG, "flash_encrypt"); - esp_err_t esp_secure_boot_enable_secure_features(void) - { - esp_efuse_write_field_bit(ESP_EFUSE_DIS_DIRECT_BOOT); +esp_err_t esp_flash_encryption_enable_secure_features(void) +{ + esp_efuse_write_field_bit(ESP_EFUSE_DIS_DIRECT_BOOT); - #ifdef CONFIG_SECURE_ENABLE_SECURE_ROM_DL_MODE - ESP_LOGI(TAG, "Enabling Security download mode..."); - esp_err_t err = esp_efuse_enable_rom_secure_download_mode(); - if (err != ESP_OK) { - ESP_LOGE(TAG, "Could not enable Security download mode..."); - return err; - } - #elif CONFIG_SECURE_DISABLE_ROM_DL_MODE - ESP_LOGI(TAG, "Disable ROM Download mode..."); - esp_err_t err = esp_efuse_disable_rom_download_mode(); - if (err != ESP_OK) { - ESP_LOGE(TAG, "Could not disable ROM Download mode..."); - return err; - } - #else - ESP_LOGW(TAG, "UART ROM Download mode kept enabled - SECURITY COMPROMISED"); - #endif +#ifdef CONFIG_SECURE_ENABLE_SECURE_ROM_DL_MODE + ESP_LOGI(TAG, "Enabling Security download mode..."); + esp_err_t err = esp_efuse_enable_rom_secure_download_mode(); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Could not enable Security download mode..."); + return err; + } +#elif CONFIG_SECURE_DISABLE_ROM_DL_MODE + ESP_LOGI(TAG, "Disable ROM Download mode..."); + esp_err_t err = esp_efuse_disable_rom_download_mode(); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Could not disable ROM Download mode..."); + return err; + } +#else + ESP_LOGW(TAG, "UART ROM Download mode kept enabled - SECURITY COMPROMISED"); +#endif - #ifndef CONFIG_SECURE_BOOT_ALLOW_JTAG - ESP_LOGI(TAG, "Disable hardware & software JTAG..."); - esp_efuse_write_field_bit(ESP_EFUSE_DIS_PAD_JTAG); - esp_efuse_write_field_bit(ESP_EFUSE_DIS_USB_JTAG); - esp_efuse_write_field_cnt(ESP_EFUSE_SOFT_DIS_JTAG, ESP_EFUSE_SOFT_DIS_JTAG[0]->bit_count); - #else - ESP_LOGW(TAG, "Not disabling JTAG - SECURITY COMPROMISED"); - #endif +#ifndef CONFIG_SECURE_BOOT_ALLOW_JTAG + ESP_LOGI(TAG, "Disable hardware & software JTAG..."); + esp_efuse_write_field_bit(ESP_EFUSE_DIS_PAD_JTAG); + esp_efuse_write_field_bit(ESP_EFUSE_DIS_USB_JTAG); + esp_efuse_write_field_cnt(ESP_EFUSE_SOFT_DIS_JTAG, ESP_EFUSE_SOFT_DIS_JTAG[0]->bit_count); +#else + ESP_LOGW(TAG, "Not disabling JTAG - SECURITY COMPROMISED"); +#endif - #ifdef CONFIG_SECURE_BOOT_ENABLE_AGGRESSIVE_KEY_REVOKE - esp_efuse_write_field_bit(ESP_EFUSE_SECURE_BOOT_AGGRESSIVE_REVOKE); - #endif +#ifdef CONFIG_SECURE_BOOT_ENABLE_AGGRESSIVE_KEY_REVOKE + esp_efuse_write_field_bit(ESP_EFUSE_SECURE_BOOT_AGGRESSIVE_REVOKE); +#endif - esp_efuse_write_field_bit(ESP_EFUSE_SECURE_BOOT_EN); + esp_efuse_write_field_bit(ESP_EFUSE_SECURE_BOOT_EN); - #ifndef CONFIG_SECURE_BOOT_V2_ALLOW_EFUSE_RD_DIS - bool rd_dis_now = true; - #ifdef CONFIG_SECURE_FLASH_ENC_ENABLED - /* If flash encryption is not enabled yet then don't read-disable efuses yet, do it later in the boot - when Flash Encryption is being enabled */ - rd_dis_now = esp_efuse_is_flash_encryption_enabled(); - #endif - if (rd_dis_now) { - ESP_LOGI(TAG, "Prevent read disabling of additional efuses..."); - esp_efuse_write_field_bit(ESP_EFUSE_WR_DIS_RD_DIS); - } - #else - ESP_LOGW(TAG, "Allowing read disabling of additional efuses - SECURITY COMPROMISED"); - #endif +#ifndef CONFIG_SECURE_BOOT_V2_ALLOW_EFUSE_RD_DIS + bool rd_dis_now = true; +#ifdef CONFIG_SECURE_FLASH_ENC_ENABLED + /* If flash encryption is not enabled yet then don't read-disable efuses yet, do it later in the boot + when Flash Encryption is being enabled */ + rd_dis_now = esp_efuse_is_flash_encryption_enabled(); +#endif + if (rd_dis_now) { + ESP_LOGI(TAG, "Prevent read disabling of additional efuses..."); + esp_efuse_write_field_bit(ESP_EFUSE_WR_DIS_RD_DIS); + } +#else + ESP_LOGW(TAG, "Allowing read disabling of additional efuses - SECURITY COMPROMISED"); +#endif - return ESP_OK; - } + return ESP_OK; +} diff --git a/components/esp_driver_rmt/test_apps/rmt/README.md b/components/esp_driver_rmt/test_apps/rmt/README.md index c3221d0779..2ce6f477ac 100644 --- a/components/esp_driver_rmt/test_apps/rmt/README.md +++ b/components/esp_driver_rmt/test_apps/rmt/README.md @@ -1,2 +1,2 @@ -| Supported Targets | ESP32 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S2 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | -------- | +| Supported Targets | ESP32 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S2 | ESP32-S3 | ESP32-S31 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | -------- | --------- | diff --git a/components/esp_driver_rmt/test_apps/rmt/pytest_rmt.py b/components/esp_driver_rmt/test_apps/rmt/pytest_rmt.py index 1f058a0763..fa360b9cd2 100644 --- a/components/esp_driver_rmt/test_apps/rmt/pytest_rmt.py +++ b/components/esp_driver_rmt/test_apps/rmt/pytest_rmt.py @@ -14,7 +14,9 @@ from pytest_embedded_idf.utils import idf_parametrize ], indirect=True, ) -@idf_parametrize('target', ['esp32', 'esp32s2', 'esp32c3', 'esp32c6', 'esp32h2', 'esp32p4'], indirect=['target']) +@idf_parametrize( + 'target', ['esp32', 'esp32s2', 'esp32c3', 'esp32c6', 'esp32h2', 'esp32p4', 'esp32s31'], indirect=['target'] +) def test_rmt(dut: Dut) -> None: dut.run_all_single_board_cases() diff --git a/components/esp_driver_rmt/test_apps/rmt/sdkconfig.defaults.esp32s31 b/components/esp_driver_rmt/test_apps/rmt/sdkconfig.defaults.esp32s31 new file mode 100644 index 0000000000..db575808cf --- /dev/null +++ b/components/esp_driver_rmt/test_apps/rmt/sdkconfig.defaults.esp32s31 @@ -0,0 +1,2 @@ +CONFIG_SPIRAM=y +CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL=0 diff --git a/components/esp_hal_rmt/esp32c3/include/hal/rmt_ll.h b/components/esp_hal_rmt/esp32c3/include/hal/rmt_ll.h index a5c5a4be7f..97f80d7e0f 100644 --- a/components/esp_hal_rmt/esp32c3/include/hal/rmt_ll.h +++ b/components/esp_hal_rmt/esp32c3/include/hal/rmt_ll.h @@ -54,7 +54,6 @@ extern "C" { // Maximum values due to limited register bit width #define RMT_LL_CHANNEL_CLOCK_MAX_PRESCALE 256 #define RMT_LL_GROUP_CLOCK_MAX_INTEGER_PRESCALE 256 -#define RMT_LL_GROUP_CLOCK_MAX_FRACTAL_PRESCALE 64 typedef enum { RMT_LL_MEM_OWNER_SW = 0, diff --git a/components/esp_hal_rmt/esp32c5/include/hal/rmt_ll.h b/components/esp_hal_rmt/esp32c5/include/hal/rmt_ll.h index aea8f6b360..0e75bb46df 100644 --- a/components/esp_hal_rmt/esp32c5/include/hal/rmt_ll.h +++ b/components/esp_hal_rmt/esp32c5/include/hal/rmt_ll.h @@ -55,7 +55,6 @@ extern "C" { // Maximum values due to limited register bit width #define RMT_LL_CHANNEL_CLOCK_MAX_PRESCALE 256 #define RMT_LL_GROUP_CLOCK_MAX_INTEGER_PRESCALE 256 -#define RMT_LL_GROUP_CLOCK_MAX_FRACTAL_PRESCALE 64 typedef enum { RMT_LL_MEM_OWNER_SW = 0, diff --git a/components/esp_hal_rmt/esp32c6/include/hal/rmt_ll.h b/components/esp_hal_rmt/esp32c6/include/hal/rmt_ll.h index aed0fdc156..484d5b1778 100644 --- a/components/esp_hal_rmt/esp32c6/include/hal/rmt_ll.h +++ b/components/esp_hal_rmt/esp32c6/include/hal/rmt_ll.h @@ -55,7 +55,6 @@ extern "C" { // Maximum values due to limited register bit width #define RMT_LL_CHANNEL_CLOCK_MAX_PRESCALE 256 #define RMT_LL_GROUP_CLOCK_MAX_INTEGER_PRESCALE 256 -#define RMT_LL_GROUP_CLOCK_MAX_FRACTAL_PRESCALE 64 typedef enum { RMT_LL_MEM_OWNER_SW = 0, diff --git a/components/esp_hal_rmt/esp32h2/include/hal/rmt_ll.h b/components/esp_hal_rmt/esp32h2/include/hal/rmt_ll.h index 1a23a24f28..fc3bd21682 100644 --- a/components/esp_hal_rmt/esp32h2/include/hal/rmt_ll.h +++ b/components/esp_hal_rmt/esp32h2/include/hal/rmt_ll.h @@ -55,7 +55,6 @@ extern "C" { // Maximum values due to limited register bit width #define RMT_LL_CHANNEL_CLOCK_MAX_PRESCALE 256 #define RMT_LL_GROUP_CLOCK_MAX_INTEGER_PRESCALE 256 -#define RMT_LL_GROUP_CLOCK_MAX_FRACTAL_PRESCALE 64 typedef enum { RMT_LL_MEM_OWNER_SW = 0, diff --git a/components/esp_hal_rmt/esp32h21/include/hal/rmt_ll.h b/components/esp_hal_rmt/esp32h21/include/hal/rmt_ll.h index ae1023502a..f51639cf97 100644 --- a/components/esp_hal_rmt/esp32h21/include/hal/rmt_ll.h +++ b/components/esp_hal_rmt/esp32h21/include/hal/rmt_ll.h @@ -55,7 +55,6 @@ extern "C" { // Maximum values due to limited register bit width #define RMT_LL_CHANNEL_CLOCK_MAX_PRESCALE 256 #define RMT_LL_GROUP_CLOCK_MAX_INTEGER_PRESCALE 256 -#define RMT_LL_GROUP_CLOCK_MAX_FRACTAL_PRESCALE 64 typedef enum { RMT_LL_MEM_OWNER_SW = 0, diff --git a/components/esp_hal_rmt/esp32h4/include/hal/rmt_ll.h b/components/esp_hal_rmt/esp32h4/include/hal/rmt_ll.h index f369f4fc4a..d0ad6f65e7 100644 --- a/components/esp_hal_rmt/esp32h4/include/hal/rmt_ll.h +++ b/components/esp_hal_rmt/esp32h4/include/hal/rmt_ll.h @@ -55,7 +55,6 @@ extern "C" { // Maximum values due to limited register bit width #define RMT_LL_CHANNEL_CLOCK_MAX_PRESCALE 256 #define RMT_LL_GROUP_CLOCK_MAX_INTEGER_PRESCALE 256 -#define RMT_LL_GROUP_CLOCK_MAX_FRACTAL_PRESCALE 64 typedef enum { RMT_LL_MEM_OWNER_SW = 0, diff --git a/components/esp_hal_rmt/esp32p4/include/hal/rmt_ll.h b/components/esp_hal_rmt/esp32p4/include/hal/rmt_ll.h index 2aac81c3f5..0f122b896f 100644 --- a/components/esp_hal_rmt/esp32p4/include/hal/rmt_ll.h +++ b/components/esp_hal_rmt/esp32p4/include/hal/rmt_ll.h @@ -54,7 +54,6 @@ extern "C" { // Maximum values due to limited register bit width #define RMT_LL_CHANNEL_CLOCK_MAX_PRESCALE 256 #define RMT_LL_GROUP_CLOCK_MAX_INTEGER_PRESCALE 256 -#define RMT_LL_GROUP_CLOCK_MAX_FRACTAL_PRESCALE 64 typedef enum { RMT_LL_MEM_OWNER_SW = 0, diff --git a/components/esp_hal_rmt/esp32s3/include/hal/rmt_ll.h b/components/esp_hal_rmt/esp32s3/include/hal/rmt_ll.h index bb98824a7f..295d3e9c38 100644 --- a/components/esp_hal_rmt/esp32s3/include/hal/rmt_ll.h +++ b/components/esp_hal_rmt/esp32s3/include/hal/rmt_ll.h @@ -54,7 +54,6 @@ extern "C" { // Maximum values due to limited register bit width #define RMT_LL_CHANNEL_CLOCK_MAX_PRESCALE 256 #define RMT_LL_GROUP_CLOCK_MAX_INTEGER_PRESCALE 256 -#define RMT_LL_GROUP_CLOCK_MAX_FRACTAL_PRESCALE 64 typedef enum { RMT_LL_MEM_OWNER_SW = 0, diff --git a/components/esp_hal_rmt/esp32s31/include/hal/rmt_ll.h b/components/esp_hal_rmt/esp32s31/include/hal/rmt_ll.h new file mode 100644 index 0000000000..49b1d2fa94 --- /dev/null +++ b/components/esp_hal_rmt/esp32s31/include/hal/rmt_ll.h @@ -0,0 +1,816 @@ +/* + * SPDX-FileCopyrightText: 2026 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 +#include +#include +#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" +#include "soc/hp_system_struct.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// Get RMT attribute +#define RMT_LL_GET(_attr) (RMT_LL_ ## _attr) +#define RMT_LL_SUPPORT(_feat) (RMT_LL_SUPPORT_ ## _feat) + +// SoC-based capabilities +#define RMT_LL_INST_NUM (1) /*!< Number of RMT group */ +#define RMT_LL_TX_CANDIDATES_PER_INST (4) /*!< Number of channels that capable of Transmit in each group */ +#define RMT_LL_RX_CANDIDATES_PER_INST (4) /*!< Number of channels that capable of Receive in each group */ +#define RMT_LL_CHANS_PER_INST (8) /*!< Total 8 channels */ +#define RMT_LL_SUPPORT_RX_DEMODULATION (1) /*!< Support signal demodulation on RX path (i.e. remove carrier) */ +#define RMT_LL_SUPPORT_ASYNC_STOP (1) /*!< Support stop transmission asynchronously */ +#define RMT_LL_SUPPORT_TX_SYNCHRO (1) /*!< Support coordinate a group of TX channels to start simultaneously */ +#define RMT_LL_SUPPORT_RC_FAST (1) /*!< Support set RC_FAST clock as the RMT clock source */ + +#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 + +// Maximum values due to limited register bit width +#define RMT_LL_CHANNEL_CLOCK_MAX_PRESCALE 256 +#define RMT_LL_GROUP_CLOCK_MAX_INTEGER_PRESCALE 256 + +typedef enum { + RMT_LL_MEM_OWNER_SW = 0, + RMT_LL_MEM_OWNER_HW = 1, +} rmt_ll_mem_owner_t; + +typedef enum { + RMT_LL_MEM_LP_MODE_DEEP_SLEEP, // memory will enter deep sleep during low power stage, keep memory data + RMT_LL_MEM_LP_MODE_LIGHT_SLEEP, // memory will enter light sleep during low power stage, keep memory data + RMT_LL_MEM_LP_MODE_SHUT_DOWN, // memory will be powered down during low power stage + RMT_LL_MEM_LP_MODE_DISABLE, // disable the low power stage +} rmt_ll_mem_lp_mode_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.rmt_ctrl0.reg_rmt_sys_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; + HP_SYS_CLKRST.rmt_ctrl0.reg_rmt_rst_en = 1; + HP_SYS_CLKRST.rmt_ctrl0.reg_rmt_rst_en = 0; +} + +/** + * @brief Force power on the RMT memory block, regardless of the outside PMU logic + * + * @param dev Peripheral instance address + */ +static inline void rmt_ll_mem_force_power_on(rmt_dev_t *dev) +{ + (void)dev; + HP_SYSTEM.sys_rmt_mem_lp_ctrl.sys_rmt_mem_lp_force_ctrl = 1; + HP_SYSTEM.sys_rmt_mem_lp_ctrl.sys_rmt_mem_lp_en = 0; +} + +/** + * @brief Force the RMT memory block into low power mode, regardless of the outside PMU logic + * + * @param dev Peripheral instance address + */ +static inline void rmt_ll_mem_force_low_power(rmt_dev_t *dev) +{ + (void)dev; + HP_SYSTEM.sys_rmt_mem_lp_ctrl.sys_rmt_mem_lp_force_ctrl = 1; + HP_SYSTEM.sys_rmt_mem_lp_ctrl.sys_rmt_mem_lp_en = 1; +} + +/** + * @brief Power control the RMT memory block by the outside PMU logic + * + * @param dev Peripheral instance address + * @param mode RMT memory low power mode in low power stage + */ +static inline void rmt_ll_mem_power_by_pmu(rmt_dev_t *dev) +{ + (void)dev; + HP_SYSTEM.sys_rmt_mem_lp_ctrl.sys_rmt_mem_lp_en = 0; + HP_SYSTEM.sys_rmt_mem_lp_ctrl.sys_rmt_mem_lp_force_ctrl = 0; +} + +/** + * @brief Set low power mode for RMT memory block + * + * @param dev Peripheral instance address + * @param mode RMT memory low power mode in low power stage + */ +static inline void rmt_ll_mem_set_low_power_mode(rmt_dev_t *dev, rmt_ll_mem_lp_mode_t mode) +{ + (void)dev; + HP_SYSTEM.sys_rmt_mem_lp_ctrl.sys_rmt_mem_lp_mode = mode; +} + +/** + * @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; +} + +/** + * @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.rmt_ctrl0, reg_rmt_clk_div_num, divider_integral - 1); + HAL_FORCE_MODIFY_U32_REG_FIELD(HP_SYS_CLKRST.rmt_ctrl0, reg_rmt_clk_div_numerator, divider_numerator); + HAL_FORCE_MODIFY_U32_REG_FIELD(HP_SYS_CLKRST.rmt_ctrl0, reg_rmt_clk_div_denominator, divider_denominator); + switch (src) { + case RMT_CLK_SRC_PLL_F80M: + HP_SYS_CLKRST.rmt_ctrl0.reg_rmt_clk_src_sel = 2; + break; + case RMT_CLK_SRC_RC_FAST: + HP_SYS_CLKRST.rmt_ctrl0.reg_rmt_clk_src_sel = 1; + break; + case RMT_CLK_SRC_XTAL: + HP_SYS_CLKRST.rmt_ctrl0.reg_rmt_clk_src_sel = 0; + break; + default: + HAL_ASSERT(false); + break; + } +} + +/** + * @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.rmt_ctrl0.reg_rmt_clk_en = en; +} + +////////////////////////////////////////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 output 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) +{ + // write 1 to reset + 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 + */ +__attribute__((always_inline)) +static inline void rmt_ll_rx_reset_pointer(rmt_dev_t *dev, uint32_t channel) +{ + dev->chmconf[channel].conf1.mem_wr_rst_chm = 1; + 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 + */ +__attribute__((always_inline)) +static inline void rmt_ll_rx_set_idle_thres(rmt_dev_t *dev, uint32_t channel, uint32_t thres) +{ + dev->chmconf[channel].conf0.idle_thres_chm = thres; +} + +/** + * @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 + */ +__attribute__((always_inline)) +static inline void rmt_ll_rx_enable_filter(rmt_dev_t *dev, uint32_t channel, bool enable) +{ + dev->chmconf[channel].conf1.rx_filter_en_chm = enable; +} + +/** + * @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 + */ +__attribute__((always_inline)) +static inline void rmt_ll_rx_set_filter_thres(rmt_dev_t *dev, uint32_t channel, uint32_t thres) +{ + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->chmconf[channel].conf1, rx_filter_thres_chm, thres); +} + +/** + * @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 Interrupt 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); +} + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_hal_rmt/esp32s31/rmt_periph.c b/components/esp_hal_rmt/esp32s31/rmt_periph.c new file mode 100644 index 0000000000..bf6bb99b0b --- /dev/null +++ b/components/esp_hal_rmt/esp32s31/rmt_periph.c @@ -0,0 +1,80 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "hal/rmt_periph.h" +#include "soc/gpio_sig_map.h" +#include "soc/rmt_reg.h" + +const soc_rmt_signal_desc_t soc_rmt_signals[1] = { + [0] = { + .irq = ETS_RMT_INTR_SOURCE, + .module_name = "rmt0", + .channels = { + [0] = { + .tx_sig = RMT_SIG_OUT0_IDX, + .rx_sig = -1 + }, + [1] = { + .tx_sig = RMT_SIG_OUT1_IDX, + .rx_sig = -1 + }, + [2] = { + .tx_sig = RMT_SIG_OUT2_IDX, + .rx_sig = -1 + }, + [3] = { + .tx_sig = RMT_SIG_OUT3_IDX, + .rx_sig = -1 + }, + [4] = { + .tx_sig = -1, + .rx_sig = RMT_SIG_IN0_IDX + }, + [5] = { + .tx_sig = -1, + .rx_sig = RMT_SIG_IN1_IDX + }, + [6] = { + .tx_sig = -1, + .rx_sig = RMT_SIG_IN2_IDX + }, + [7] = { + .tx_sig = -1, + .rx_sig = RMT_SIG_IN3_IDX + }, + } + } +}; + +/** + * RMT Registers to be saved during sleep retention + * - Channel configuration registers, e.g.: RMT_CH0CONF0_REG, RMT_CH3CONF0_REG, RMT_CH3CONF1_REG, RMT_CH0_TX_LIM_REG, RMT_CH3_RX_LIM_REG + * - TX synchronization registers, e.g.: RMT_TX_SIM_REG + * - Interrupt enable registers, e.g.: RMT_INT_ENA_REG + * - Carrier duty registers, e.g.: RMT_CH0CARRIER_DUTY_REG, RMT_CH3_RX_CARRIER_RM_REG + * - Global configuration registers, e.g.: RMT_SYS_CONF_REG + */ +#define RMT_RETENTION_REGS_CNT 31 +#define RMT_RETENTION_REGS_BASE (DR_REG_RMT_BASE + 0x20) +static const uint32_t rmt_regs_map[4] = {0xff400fff, 0x3ff, 0x0, 0x0}; +static const regdma_entries_config_t rmt_regdma_entries[] = { + [0] = { + .config = REGDMA_LINK_ADDR_MAP_INIT(REGDMA_RMT_LINK(0x00), + RMT_RETENTION_REGS_BASE, RMT_RETENTION_REGS_BASE, + RMT_RETENTION_REGS_CNT, 0, 0, + rmt_regs_map[0], rmt_regs_map[1], + rmt_regs_map[2], rmt_regs_map[3]), + .owner = ENTRY(0), + }, +}; + +const rmt_reg_retention_info_t rmt_reg_retention_info[1] = { + [0] = { + .module = SLEEP_RETENTION_MODULE_RMT0, + .regdma_entry_array = rmt_regdma_entries, + .array_size = ARRAY_SIZE(rmt_regdma_entries), + }, +}; diff --git a/components/soc/esp32s31/include/soc/Kconfig.soc_caps.in b/components/soc/esp32s31/include/soc/Kconfig.soc_caps.in index 4170e280cd..c6dda3dd63 100644 --- a/components/soc/esp32s31/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32s31/include/soc/Kconfig.soc_caps.in @@ -59,6 +59,10 @@ config SOC_RTC_MEM_SUPPORTED bool default y +config SOC_RMT_SUPPORTED + bool + default y + config SOC_SDM_SUPPORTED bool default y @@ -323,6 +327,30 @@ config SOC_LEDC_CHANNEL_NUM int default 6 +config SOC_RMT_MEM_WORDS_PER_CHANNEL + int + default 48 + +config SOC_RMT_SUPPORT_RX_PINGPONG + bool + 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_DMA + bool + default y + +config SOC_RMT_SUPPORT_SLEEP_RETENTION + bool + default y + config SOC_MMU_PERIPH_NUM int default 2 diff --git a/components/soc/esp32s31/include/soc/clk_tree_defs.h b/components/soc/esp32s31/include/soc/clk_tree_defs.h index fd187b18ca..57a6de9c79 100644 --- a/components/soc/esp32s31/include/soc/clk_tree_defs.h +++ b/components/soc/esp32s31/include/soc/clk_tree_defs.h @@ -209,6 +209,21 @@ typedef enum { //////////////////////////////////////////////////RMT/////////////////////////////////////////////////////////////////// +/** + * @brief Array initializer for all supported clock sources of RMT + */ +#define SOC_RMT_CLKS {SOC_MOD_CLK_PLL_F80M, SOC_MOD_CLK_RC_FAST, SOC_MOD_CLK_XTAL} + +/** + * @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 */ + RMT_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_F80M, /*!< Select PLL_F80M as the default choice */ +} soc_periph_rmt_clk_src_t; + ///////////////////////////////////////////////////UART///////////////////////////////////////////////////////////////// /** diff --git a/components/soc/esp32s31/include/soc/soc_caps.h b/components/soc/esp32s31/include/soc/soc_caps.h index 42d450710f..1f641a41b5 100644 --- a/components/soc/esp32s31/include/soc/soc_caps.h +++ b/components/soc/esp32s31/include/soc/soc_caps.h @@ -54,7 +54,7 @@ #define SOC_EFUSE_SUPPORTED 1 // TODO: [ESP32S31] IDF-14688 #define SOC_RTC_FAST_MEM_SUPPORTED 1 #define SOC_RTC_MEM_SUPPORTED 1 // TODO: [ESP32S31] IDF-14645 -// #define SOC_RMT_SUPPORTED 1 // TODO: [ESP32S31] IDF-14794 +#define SOC_RMT_SUPPORTED 1 // #define SOC_I2S_SUPPORTED 1 // TODO: [ESP32S31] IDF-14771 #define SOC_SDM_SUPPORTED 1 // #define SOC_GPSPI_SUPPORTED 1 // TODO: [ESP32S31] IDF-14734 @@ -208,6 +208,14 @@ // TODO: [ESP32S31] IDF-14709 #define SOC_LEDC_CHANNEL_NUM (6) +/*--------------------------- RMT CAPS ---------------------------------------*/ +#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_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 */ +#define SOC_RMT_SUPPORT_DMA 1 /*!< RMT peripheral can connect to DMA channel */ +#define SOC_RMT_SUPPORT_SLEEP_RETENTION 1 /*!< The sleep retention feature can help back up RMT registers before sleep */ + /*-------------------------- MMU CAPS ----------------------------------------*/ #define SOC_MMU_PERIPH_NUM (2U) #define SOC_MMU_LINEAR_ADDRESS_REGION_NUM (2U) diff --git a/components/soc/esp32s31/ld/esp32s31.peripherals.ld b/components/soc/esp32s31/ld/esp32s31.peripherals.ld index c97ee08b38..698f517a87 100644 --- a/components/soc/esp32s31/ld/esp32s31.peripherals.ld +++ b/components/soc/esp32s31/ld/esp32s31.peripherals.ld @@ -15,6 +15,7 @@ PROVIDE ( AXI_DMA = 0x20348000 ); PROVIDE ( GMAC = 0x20350000 ); PROVIDE ( PVT = 0x20354000 ); PROVIDE ( RMT = 0x20355000 ); +PROVIDE ( RMTMEM = 0x20355800 ); PROVIDE ( BITSCRAMBLER = 0x20356000 ); PROVIDE ( ASRC = 0x20357000 ); PROVIDE ( CNNT_SYS_REG = 0x20359000 ); diff --git a/components/soc/esp32s31/register/soc/rmt_struct.h b/components/soc/esp32s31/register/soc/rmt_struct.h index 97c7b8c515..fbab99c30e 100644 --- a/components/soc/esp32s31/register/soc/rmt_struct.h +++ b/components/soc/esp32s31/register/soc/rmt_struct.h @@ -108,7 +108,11 @@ typedef union { * synchronization bit for CHANNELn */ 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; } rmt_chnconf0_reg_t; @@ -127,7 +131,10 @@ typedef union { * than this register value, received process is finished. */ uint32_t idle_thres_chm:15; - uint32_t reserved_23:1; + /** dma_access_en_m : WT; bitpos: [23]; default: 0; + * 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. */ @@ -1038,18 +1045,14 @@ typedef union { } rmt_date_reg_t; -typedef struct { +typedef struct rmt_dev_t { volatile rmt_chndata_reg_t chndata[4]; volatile rmt_chmdata_reg_t chmdata[4]; volatile rmt_chnconf0_reg_t chnconf0[4]; - volatile rmt_chmconf0_reg_t ch4conf0; - volatile rmt_chmconf1_reg_t ch4conf1; - volatile rmt_chmconf0_reg_t ch5conf0; - volatile rmt_chmconf1_reg_t ch5conf1; - 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 struct { + rmt_chmconf0_reg_t conf0; + rmt_chmconf1_reg_t conf1; + } chmconf[4]; volatile rmt_chnstatus_reg_t chnstatus[4]; volatile rmt_chmstatus_reg_t chmstatus[4]; volatile rmt_int_raw_reg_t int_raw; @@ -1066,6 +1069,8 @@ typedef struct { volatile rmt_date_reg_t date; } rmt_dev_t; +extern rmt_dev_t RMT; + #ifndef __cplusplus _Static_assert(sizeof(rmt_dev_t) == 0xd0, "Invalid size of rmt_dev_t structure"); diff --git a/examples/get-started/blink/README.md b/examples/get-started/blink/README.md index 29f9e68a75..7bf3b250d5 100644 --- a/examples/get-started/blink/README.md +++ b/examples/get-started/blink/README.md @@ -1,5 +1,5 @@ -| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S2 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | --------- | -------- | -------- | -------- | -------- | +| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S2 | ESP32-S3 | ESP32-S31 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | --------- | -------- | -------- | -------- | -------- | --------- | # Blink Example diff --git a/examples/get-started/blink/pytest_blink.py b/examples/get-started/blink/pytest_blink.py index 78bb71a0e2..6412ae72ca 100644 --- a/examples/get-started/blink/pytest_blink.py +++ b/examples/get-started/blink/pytest_blink.py @@ -10,7 +10,6 @@ from pytest_embedded_idf.utils import idf_parametrize @pytest.mark.generic @idf_parametrize('target', ['supported_targets'], indirect=['target']) -@pytest.mark.temp_skip_ci(targets=['esp32s31'], reason='s31 bringup on this module is not done') def test_blink(dut: IdfDut) -> None: # check and log bin size binary_file = os.path.join(dut.app.binary_path, 'blink.bin') diff --git a/examples/peripherals/rmt/dshot_esc/README.md b/examples/peripherals/rmt/dshot_esc/README.md index 90dd901d54..f291ae3ab3 100644 --- a/examples/peripherals/rmt/dshot_esc/README.md +++ b/examples/peripherals/rmt/dshot_esc/README.md @@ -1,5 +1,5 @@ -| Supported Targets | ESP32 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S2 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | -------- | +| Supported Targets | ESP32 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S2 | ESP32-S3 | ESP32-S31 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | -------- | --------- | # 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.) diff --git a/examples/peripherals/rmt/dshot_esc/pytest_dshot_esc.py b/examples/peripherals/rmt/dshot_esc/pytest_dshot_esc.py index 4356000120..88766f15f9 100644 --- a/examples/peripherals/rmt/dshot_esc/pytest_dshot_esc.py +++ b/examples/peripherals/rmt/dshot_esc/pytest_dshot_esc.py @@ -3,14 +3,11 @@ import pytest from pytest_embedded import Dut from pytest_embedded_idf.utils import idf_parametrize +from pytest_embedded_idf.utils import soc_filtered_targets @pytest.mark.generic -@idf_parametrize( - 'target', - ['esp32', 'esp32s2', 'esp32s3', 'esp32c3', 'esp32c5', 'esp32c6', 'esp32h2', 'esp32p4'], - indirect=['target'], -) +@idf_parametrize('target', soc_filtered_targets('SOC_RMT_SUPPORTED == 1'), indirect=['target']) def test_dshot_esc_example(dut: Dut) -> None: dut.expect_exact('example: Create RMT TX channel') dut.expect_exact('example: Install Dshot ESC encoder') diff --git a/examples/peripherals/rmt/ir_nec_transceiver/README.md b/examples/peripherals/rmt/ir_nec_transceiver/README.md index c908d35e2b..2e30fd13cb 100644 --- a/examples/peripherals/rmt/ir_nec_transceiver/README.md +++ b/examples/peripherals/rmt/ir_nec_transceiver/README.md @@ -1,5 +1,5 @@ -| Supported Targets | ESP32 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S2 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | -------- | +| Supported Targets | ESP32 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S2 | ESP32-S3 | ESP32-S31 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | -------- | --------- | # IR NEC Encoding and Decoding Example (See the README.md file in the upper level 'examples' directory for more information about examples.) diff --git a/examples/peripherals/rmt/led_strip/README.md b/examples/peripherals/rmt/led_strip/README.md index d295661786..9918f701be 100644 --- a/examples/peripherals/rmt/led_strip/README.md +++ b/examples/peripherals/rmt/led_strip/README.md @@ -1,5 +1,5 @@ -| Supported Targets | ESP32 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S2 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | -------- | +| Supported Targets | ESP32 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S2 | ESP32-S3 | ESP32-S31 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | -------- | --------- | # RMT Transmit Example -- LED Strip (See the README.md file in the upper level 'examples' directory for more information about examples.) diff --git a/examples/peripherals/rmt/led_strip/pytest_led_strip.py b/examples/peripherals/rmt/led_strip/pytest_led_strip.py index d38b0f60cc..dd26d2cde4 100644 --- a/examples/peripherals/rmt/led_strip/pytest_led_strip.py +++ b/examples/peripherals/rmt/led_strip/pytest_led_strip.py @@ -3,14 +3,11 @@ import pytest from pytest_embedded import Dut from pytest_embedded_idf.utils import idf_parametrize +from pytest_embedded_idf.utils import soc_filtered_targets @pytest.mark.generic -@idf_parametrize( - 'target', - ['esp32', 'esp32s2', 'esp32s3', 'esp32c3', 'esp32c5', 'esp32c6', 'esp32h2', 'esp32p4'], - indirect=['target'], -) +@idf_parametrize('target', soc_filtered_targets('SOC_RMT_SUPPORTED == 1'), indirect=['target']) def test_led_strip_example(dut: Dut) -> None: dut.expect_exact('example: Create RMT TX channel') dut.expect_exact('example: Install led strip encoder') diff --git a/examples/peripherals/rmt/led_strip_simple_encoder/README.md b/examples/peripherals/rmt/led_strip_simple_encoder/README.md index 4d147c438a..2879d95f32 100644 --- a/examples/peripherals/rmt/led_strip_simple_encoder/README.md +++ b/examples/peripherals/rmt/led_strip_simple_encoder/README.md @@ -1,5 +1,5 @@ -| Supported Targets | ESP32 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S2 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | -------- | +| Supported Targets | ESP32 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S2 | ESP32-S3 | ESP32-S31 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | -------- | --------- | # RMT Transmit Example -- LED Strip (See the README.md file in the upper level 'examples' directory for more information about examples.) diff --git a/examples/peripherals/rmt/led_strip_simple_encoder/main/led_strip_example_main.c b/examples/peripherals/rmt/led_strip_simple_encoder/main/led_strip_example_main.c index 1e7352b352..bea5ce2a79 100644 --- a/examples/peripherals/rmt/led_strip_simple_encoder/main/led_strip_example_main.c +++ b/examples/peripherals/rmt/led_strip_simple_encoder/main/led_strip_example_main.c @@ -11,7 +11,7 @@ #include "driver/rmt_tx.h" #define RMT_LED_STRIP_RESOLUTION_HZ 10000000 // 10MHz resolution, 1 tick = 0.1us (led strip needs a high resolution) -#define RMT_LED_STRIP_GPIO_NUM 8 +#define RMT_LED_STRIP_GPIO_NUM 0 #define EXAMPLE_LED_NUMBERS 24 diff --git a/examples/peripherals/rmt/led_strip_simple_encoder/pytest_led_strip_simple_encoder.py b/examples/peripherals/rmt/led_strip_simple_encoder/pytest_led_strip_simple_encoder.py new file mode 100644 index 0000000000..97da232396 --- /dev/null +++ b/examples/peripherals/rmt/led_strip_simple_encoder/pytest_led_strip_simple_encoder.py @@ -0,0 +1,15 @@ +# SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: CC0-1.0 +import pytest +from pytest_embedded import Dut +from pytest_embedded_idf.utils import idf_parametrize +from pytest_embedded_idf.utils import soc_filtered_targets + + +@pytest.mark.generic +@idf_parametrize('target', soc_filtered_targets('SOC_RMT_SUPPORTED == 1'), indirect=['target']) +def test_led_strip_simple_encoder_example(dut: Dut) -> None: + dut.expect_exact('example: Create RMT TX channel') + dut.expect_exact('example: Create simple callback-based encoder') + dut.expect_exact('example: Enable RMT TX channel') + dut.expect_exact('example: Start LED rainbow chase') diff --git a/examples/peripherals/rmt/musical_buzzer/README.md b/examples/peripherals/rmt/musical_buzzer/README.md index 4454ca92fd..d9ccceecf2 100644 --- a/examples/peripherals/rmt/musical_buzzer/README.md +++ b/examples/peripherals/rmt/musical_buzzer/README.md @@ -1,5 +1,5 @@ -| Supported Targets | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S2 | ESP32-S3 | -| ----------------- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | -------- | +| Supported Targets | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S2 | ESP32-S3 | ESP32-S31 | +| ----------------- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | -------- | --------- | # RMT Transmit Loop Count Example -- Musical Buzzer diff --git a/examples/peripherals/rmt/musical_buzzer/pytest_musical_buzzer.py b/examples/peripherals/rmt/musical_buzzer/pytest_musical_buzzer.py index bfbfb04a6d..0037f83530 100644 --- a/examples/peripherals/rmt/musical_buzzer/pytest_musical_buzzer.py +++ b/examples/peripherals/rmt/musical_buzzer/pytest_musical_buzzer.py @@ -3,12 +3,11 @@ import pytest from pytest_embedded import Dut from pytest_embedded_idf.utils import idf_parametrize +from pytest_embedded_idf.utils import soc_filtered_targets @pytest.mark.generic -@idf_parametrize( - 'target', ['esp32s2', 'esp32s3', 'esp32c3', 'esp32c5', 'esp32c6', 'esp32h2', 'esp32p4'], indirect=['target'] -) +@idf_parametrize('target', soc_filtered_targets('SOC_RMT_SUPPORT_TX_LOOP_COUNT == 1'), indirect=['target']) def test_musical_buzzer_example(dut: Dut) -> None: dut.expect_exact('example: Create RMT TX channel') dut.expect_exact('example: Install musical score encoder') diff --git a/examples/peripherals/rmt/onewire/README.md b/examples/peripherals/rmt/onewire/README.md index 821e4f03f0..380d7294a4 100644 --- a/examples/peripherals/rmt/onewire/README.md +++ b/examples/peripherals/rmt/onewire/README.md @@ -1,5 +1,5 @@ -| Supported Targets | ESP32 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S2 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | -------- | +| Supported Targets | ESP32 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S2 | ESP32-S3 | ESP32-S31 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | -------- | --------- | # Advanced RMT Transmit & Receive Example -- Simulate 1-Wire Bus diff --git a/examples/peripherals/rmt/onewire/pytest_onewire.py b/examples/peripherals/rmt/onewire/pytest_onewire.py index 3571b45cbc..f6d3dd223a 100644 --- a/examples/peripherals/rmt/onewire/pytest_onewire.py +++ b/examples/peripherals/rmt/onewire/pytest_onewire.py @@ -3,14 +3,11 @@ import pytest from pytest_embedded import Dut from pytest_embedded_idf.utils import idf_parametrize +from pytest_embedded_idf.utils import soc_filtered_targets @pytest.mark.generic -@idf_parametrize( - 'target', - ['esp32', 'esp32s2', 'esp32s3', 'esp32c3', 'esp32c5', 'esp32c6', 'esp32h2', 'esp32p4'], - indirect=['target'], -) +@idf_parametrize('target', soc_filtered_targets('SOC_RMT_SUPPORTED == 1'), indirect=['target']) def test_onewire_example(dut: Dut) -> None: dut.expect_exact('example: 1-Wire bus installed on GPIO') dut.expect_exact('example: Device iterator created, start searching') diff --git a/examples/peripherals/rmt/stepper_motor/README.md b/examples/peripherals/rmt/stepper_motor/README.md index e7e7ab90ff..9900923679 100644 --- a/examples/peripherals/rmt/stepper_motor/README.md +++ b/examples/peripherals/rmt/stepper_motor/README.md @@ -1,5 +1,5 @@ -| Supported Targets | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S3 | -| ----------------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | +| Supported Targets | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S3 | ESP32-S31 | +| ----------------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | --------- | # RMT Based Stepper Motor Smooth Controller diff --git a/examples/peripherals/rmt/stepper_motor/pytest_stepper_motor.py b/examples/peripherals/rmt/stepper_motor/pytest_stepper_motor.py index aa538f42aa..f5985cf573 100644 --- a/examples/peripherals/rmt/stepper_motor/pytest_stepper_motor.py +++ b/examples/peripherals/rmt/stepper_motor/pytest_stepper_motor.py @@ -3,10 +3,11 @@ import pytest from pytest_embedded import Dut from pytest_embedded_idf.utils import idf_parametrize +from pytest_embedded_idf.utils import soc_filtered_targets @pytest.mark.generic -@idf_parametrize('target', ['esp32s3', 'esp32c5', 'esp32c6', 'esp32h2', 'esp32p4'], indirect=['target']) +@idf_parametrize('target', soc_filtered_targets('SOC_RMT_SUPPORT_TX_LOOP_AUTO_STOP == 1'), indirect=['target']) def test_stepper_motor_example(dut: Dut) -> None: dut.expect_exact('example: Initialize EN + DIR GPIO') dut.expect_exact('example: Create RMT TX channel')