From 83512e3e7cae40ab9d93b8b21e978b116407ff09 Mon Sep 17 00:00:00 2001 From: morris Date: Thu, 7 Aug 2025 10:55:52 +0800 Subject: [PATCH 1/3] feat(sdm): enhance the thread safety --- components/esp_driver_sdm/CMakeLists.txt | 11 +- components/esp_driver_sdm/Kconfig | 23 +- .../esp_driver_sdm/include/driver/sdm.h | 5 +- components/esp_driver_sdm/src/sdm.c | 231 +++++++++++------- .../test_apps/sigma_delta/main/CMakeLists.txt | 2 +- .../main/{test_sdm.c => test_sdm.cpp} | 25 +- .../sigma_delta/pytest_sigma_delta.py | 3 +- components/hal/esp32/include/hal/sdm_ll.h | 8 +- components/hal/esp32c3/include/hal/sdm_ll.h | 8 +- components/hal/esp32c5/include/hal/sdm_ll.h | 5 +- components/hal/esp32c6/include/hal/sdm_ll.h | 5 +- components/hal/esp32h2/include/hal/sdm_ll.h | 5 +- components/hal/esp32p4/include/hal/sdm_ll.h | 5 +- components/hal/esp32s2/include/hal/sdm_ll.h | 8 +- components/hal/esp32s3/include/hal/sdm_ll.h | 8 +- components/hal/include/hal/sdm_hal.h | 26 +- components/hal/sdm_hal.c | 21 +- .../soc/esp32/include/soc/Kconfig.soc_caps.in | 12 - .../soc/esp32/include/soc/clk_tree_defs.h | 8 - components/soc/esp32/include/soc/soc_caps.h | 5 - .../soc/esp32/include/soc/soc_caps_full.h | 4 + components/soc/esp32/sdm_periph.c | 55 +++-- .../soc/esp32c2/include/soc/clk_tree_defs.h | 9 - .../esp32c3/include/soc/Kconfig.soc_caps.in | 12 - .../soc/esp32c3/include/soc/clk_tree_defs.h | 9 - components/soc/esp32c3/include/soc/soc_caps.h | 7 +- .../soc/esp32c3/include/soc/soc_caps_full.h | 4 + components/soc/esp32c3/sdm_periph.c | 31 +-- .../esp32c5/include/soc/Kconfig.soc_caps.in | 16 -- .../soc/esp32c5/include/soc/clk_tree_defs.h | 9 - components/soc/esp32c5/include/soc/soc_caps.h | 6 - .../soc/esp32c5/include/soc/soc_caps_full.h | 4 + components/soc/esp32c5/sdm_periph.c | 31 +-- .../esp32c6/include/soc/Kconfig.soc_caps.in | 16 -- .../soc/esp32c6/include/soc/clk_tree_defs.h | 9 - components/soc/esp32c6/include/soc/soc_caps.h | 6 - .../soc/esp32c6/include/soc/soc_caps_full.h | 4 + components/soc/esp32c6/sdm_periph.c | 31 +-- .../soc/esp32c61/include/soc/clk_tree_defs.h | 9 - .../esp32h2/include/soc/Kconfig.soc_caps.in | 16 -- .../soc/esp32h2/include/soc/clk_tree_defs.h | 9 - components/soc/esp32h2/include/soc/soc_caps.h | 6 - .../soc/esp32h2/include/soc/soc_caps_full.h | 4 + components/soc/esp32h2/sdm_periph.c | 31 +-- .../soc/esp32h21/include/soc/clk_tree_defs.h | 13 - .../esp32p4/include/soc/Kconfig.soc_caps.in | 16 -- .../soc/esp32p4/include/soc/clk_tree_defs.h | 13 - components/soc/esp32p4/include/soc/soc_caps.h | 6 - .../soc/esp32p4/include/soc/soc_caps_full.h | 4 + components/soc/esp32p4/sdm_periph.c | 55 +++-- .../esp32s2/include/soc/Kconfig.soc_caps.in | 12 - .../soc/esp32s2/include/soc/clk_tree_defs.h | 9 - components/soc/esp32s2/include/soc/soc_caps.h | 5 - .../soc/esp32s2/include/soc/soc_caps_full.h | 4 + components/soc/esp32s2/sdm_periph.c | 55 +++-- .../esp32s3/include/soc/Kconfig.soc_caps.in | 12 - .../soc/esp32s3/include/soc/clk_tree_defs.h | 9 - components/soc/esp32s3/include/soc/soc_caps.h | 5 - .../soc/esp32s3/include/soc/soc_caps_full.h | 4 + components/soc/esp32s3/sdm_periph.c | 55 +++-- components/soc/include/soc/sdm_periph.h | 28 ++- docs/en/api-reference/peripherals/sdm.rst | 8 +- docs/zh_CN/api-reference/peripherals/sdm.rst | 8 +- 63 files changed, 504 insertions(+), 579 deletions(-) rename components/esp_driver_sdm/test_apps/sigma_delta/main/{test_sdm.c => test_sdm.cpp} (71%) diff --git a/components/esp_driver_sdm/CMakeLists.txt b/components/esp_driver_sdm/CMakeLists.txt index bf83629963..4656678a22 100644 --- a/components/esp_driver_sdm/CMakeLists.txt +++ b/components/esp_driver_sdm/CMakeLists.txt @@ -1,17 +1,16 @@ idf_build_get_property(target IDF_TARGET) +if(${target} STREQUAL "linux") + return() # This component is not supported by the POSIX/Linux simulator +endif() + set(srcs) set(public_include "include") +set(priv_requires esp_pm esp_driver_gpio) if(CONFIG_SOC_SDM_SUPPORTED) list(APPEND srcs "src/sdm.c") endif() -if(${target} STREQUAL "linux") - set(priv_requires "") -else() - set(priv_requires esp_pm esp_driver_gpio) -endif() - idf_component_register(SRCS ${srcs} INCLUDE_DIRS ${public_include} PRIV_REQUIRES "${priv_requires}" diff --git a/components/esp_driver_sdm/Kconfig b/components/esp_driver_sdm/Kconfig index ba89cac125..d5726c70d1 100644 --- a/components/esp_driver_sdm/Kconfig +++ b/components/esp_driver_sdm/Kconfig @@ -1,17 +1,30 @@ menu "ESP-Driver:Sigma Delta Modulator Configurations" depends on SOC_SDM_SUPPORTED + config SDM_CTRL_FUNC_IN_IRAM bool "Place SDM control functions into IRAM" default n + select SDM_OBJ_CACHE_SAFE help - Place SDM control functions (like set_duty) into IRAM, + Place SDM control functions (like set_pulse_density) into IRAM, so that these functions can be IRAM-safe and able to be called in the other IRAM interrupt context. Enabling this option can improve driver performance as well. - config SDM_ENABLE_DEBUG_LOG - bool "Enable debug log" + config SDM_OBJ_CACHE_SAFE + bool default n help - whether to enable the debug log message for SDM driver. - Note that, this option only controls the SDM driver log, won't affect other drivers. + This will ensure the SDM object will not be allocated from a memory region + where its cache can be disabled. + + config SDM_ENABLE_DEBUG_LOG + bool "Force enable debug log" + default n + help + If enabled, SDM driver will: + 1. ignore the global logging settings + 2. compile all log messages into the binary + 3. set the runtime log level to VERBOSE + Please enable this option by caution, as it will increase the binary size. + endmenu # Sigma Delta Modulator Configurations diff --git a/components/esp_driver_sdm/include/driver/sdm.h b/components/esp_driver_sdm/include/driver/sdm.h index 3da5f04121..b4f66b578f 100644 --- a/components/esp_driver_sdm/include/driver/sdm.h +++ b/components/esp_driver_sdm/include/driver/sdm.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -8,6 +8,7 @@ #include #include "hal/sdm_types.h" +#include "hal/gpio_types.h" #include "esp_err.h" #ifdef __cplusplus @@ -23,7 +24,7 @@ typedef struct sdm_channel_t *sdm_channel_handle_t; * @brief Sigma Delta channel configuration */ typedef struct { - int gpio_num; /*!< GPIO number */ + gpio_num_t gpio_num; /*!< GPIO number */ sdm_clock_source_t clk_src; /*!< Clock source */ uint32_t sample_rate_hz; /*!< Over sample rate in Hz, it determines the frequency of the carrier pulses */ struct { diff --git a/components/esp_driver_sdm/src/sdm.c b/components/esp_driver_sdm/src/sdm.c index 57c36a89e0..e4ce80a0ef 100644 --- a/components/esp_driver_sdm/src/sdm.c +++ b/components/esp_driver_sdm/src/sdm.c @@ -5,12 +5,13 @@ */ #include +#include #include #include "sdkconfig.h" #if CONFIG_SDM_ENABLE_DEBUG_LOG // The local log level must be defined before including esp_log.h // Set the maximum log level for this source file -#define LOG_LOCAL_LEVEL ESP_LOG_DEBUG +#define LOG_LOCAL_LEVEL ESP_LOG_VERBOSE #endif #include "freertos/FreeRTOS.h" #include "esp_attr.h" @@ -22,64 +23,65 @@ #include "esp_clk_tree.h" #include "driver/gpio.h" #include "driver/sdm.h" +#include "soc/sdm_periph.h" #include "hal/sdm_hal.h" #include "hal/sdm_ll.h" #include "hal/hal_utils.h" -#include "soc/sdm_periph.h" #include "esp_private/esp_clk.h" #include "esp_private/io_mux.h" #include "esp_private/gpio.h" +#include "esp_private/sleep_retention.h" +#include "esp_private/esp_gpio_reserve.h" -#if CONFIG_SDM_CTRL_FUNC_IN_IRAM +#if CONFIG_SDM_OBJ_CACHE_SAFE #define SDM_MEM_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT) #else #define SDM_MEM_ALLOC_CAPS MALLOC_CAP_DEFAULT #endif -#define SDM_PM_LOCK_NAME_LEN_MAX 16 - -static const char *TAG = "sdm"; +///!< Logging settings +#define TAG "sdm" typedef struct sdm_platform_t sdm_platform_t; typedef struct sdm_group_t sdm_group_t; typedef struct sdm_channel_t sdm_channel_t; struct sdm_platform_t { - _lock_t mutex; // platform level mutex lock - sdm_group_t *groups[SOC_SDM_GROUPS]; // sdm group pool - int group_ref_counts[SOC_SDM_GROUPS]; // reference count used to protect group install/uninstall + _lock_t mutex; // platform level mutex lock + sdm_group_t *groups[SOC_SDM_ATTR(INST_NUM)]; // sdm group pool + int group_ref_counts[SOC_SDM_ATTR(INST_NUM)];// reference count used to protect group install/uninstall }; struct sdm_group_t { - int group_id; // Group ID, index from 0 - portMUX_TYPE spinlock; // to protect per-group register level concurrent access + int group_id; // Group ID, index from 0 + portMUX_TYPE spinlock; // to protect per-group register level concurrent access sdm_hal_context_t hal; // hal context - sdm_channel_t *channels[SOC_SDM_CHANNELS_PER_GROUP]; // array of sdm channels + sdm_channel_t *channels[SOC_SDM_ATTR(CHANS_PER_INST)]; // array of sdm channels sdm_clock_source_t clk_src; // Clock source +#if CONFIG_PM_ENABLE + esp_pm_lock_handle_t pm_lock; // PM lock, to prevent the system going into light sleep when SDM is running +#endif }; typedef enum { SDM_FSM_INIT, SDM_FSM_ENABLE, + SDM_FSM_WAIT, } sdm_fsm_t; struct sdm_channel_t { - sdm_group_t *group; // which group the sdm channel belongs to - uint32_t chan_id; // allocated channel numerical ID - int gpio_num; // GPIO number - uint32_t sample_rate_hz; // Sample rate, in Hz - portMUX_TYPE spinlock; // to protect per-channels resources concurrently accessed by task and ISR handler - sdm_fsm_t fsm; // FSM state -#if CONFIG_PM_ENABLE - esp_pm_lock_handle_t pm_lock; // PM lock, for glitch filter, as that module can only be functional under APB - char pm_lock_name[SDM_PM_LOCK_NAME_LEN_MAX]; // pm lock name -#endif + sdm_group_t *group; // which group the sdm channel belongs to + uint32_t chan_id; // allocated channel numerical ID + gpio_num_t gpio_num; // GPIO number + uint32_t sample_rate_hz; // Sample rate, in Hz + portMUX_TYPE spinlock; // to protect per-channels resources concurrently accessed by tasks + _Atomic sdm_fsm_t fsm; // state machine, to control the API is called in the correct order }; // sdm driver platform, it's always a singleton static sdm_platform_t s_platform; -static sdm_group_t *sdm_acquire_group_handle(int group_id) +static sdm_group_t *sdm_acquire_group_handle(int group_id, sdm_clock_source_t clk_src) { bool new_group = false; sdm_group_t *group = NULL; @@ -94,12 +96,12 @@ static sdm_group_t *sdm_acquire_group_handle(int group_id) // initialize sdm group members group->group_id = group_id; group->spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED; - group->clk_src = 0; + group->clk_src = clk_src; // initialize HAL context - sdm_hal_init(&group->hal, group_id); - // enable clock - // note that, this will enables all the channels' output, and channel can't be disable/enable separately - sdm_ll_enable_clock(group->hal.dev, true); + sdm_hal_init_config_t hal_config = { + .group_id = group_id, + }; + sdm_hal_init(&group->hal, &hal_config); } } else { group = s_platform.groups[group_id]; @@ -112,6 +114,17 @@ static sdm_group_t *sdm_acquire_group_handle(int group_id) if (new_group) { ESP_LOGD(TAG, "new group (%d) at %p", group_id, group); +#if CONFIG_PM_ENABLE + esp_pm_lock_type_t pm_type = ESP_PM_NO_LIGHT_SLEEP; +#if TIMER_LL_FUNC_CLOCK_SUPPORT_APB + if (clk_src == SDM_CLK_SRC_APB) { + pm_type = ESP_PM_APB_FREQ_MAX; + } +#endif // TIMER_LL_FUNC_CLOCK_SUPPORT_APB + if (esp_pm_lock_create(pm_type, 0, soc_sdm_signals[group_id].module_name, &group->pm_lock) != ESP_OK) { + ESP_LOGE(TAG, "fail to create PM lock for group %d", group_id); + } +#endif // CONFIG_PM_ENABLE } return group; @@ -128,29 +141,36 @@ static void sdm_release_group_handle(sdm_group_t *group) assert(s_platform.groups[group_id]); do_deinitialize = true; s_platform.groups[group_id] = NULL; // deregister from platform - sdm_ll_enable_clock(group->hal.dev, false); + sdm_hal_deinit(&group->hal); } _lock_release(&s_platform.mutex); if (do_deinitialize) { +#if CONFIG_PM_ENABLE + if (group->pm_lock) { + esp_pm_lock_delete(group->pm_lock); + } +#endif free(group); ESP_LOGD(TAG, "del group (%d)", group_id); } } -static esp_err_t sdm_register_to_group(sdm_channel_t *chan) +static esp_err_t sdm_register_to_group(sdm_channel_t *chan, sdm_clock_source_t clk_src) { sdm_group_t *group = NULL; int chan_id = -1; - for (int i = 0; i < SOC_SDM_GROUPS; i++) { - group = sdm_acquire_group_handle(i); + for (int i = 0; i < SOC_SDM_ATTR(INST_NUM); i++) { + group = sdm_acquire_group_handle(i, clk_src); ESP_RETURN_ON_FALSE(group, ESP_ERR_NO_MEM, TAG, "no mem for group (%d)", i); // loop to search free unit in the group portENTER_CRITICAL(&group->spinlock); - for (int j = 0; j < SOC_SDM_CHANNELS_PER_GROUP; j++) { + for (int j = 0; j < SOC_SDM_ATTR(CHANS_PER_INST); j++) { if (!group->channels[j]) { chan_id = j; group->channels[j] = chan; + chan->group = group; + chan->chan_id = chan_id; break; } } @@ -158,8 +178,6 @@ static esp_err_t sdm_register_to_group(sdm_channel_t *chan) if (chan_id < 0) { sdm_release_group_handle(group); } else { - chan->group = group; - chan->chan_id = chan_id; break; } } @@ -180,60 +198,53 @@ static void sdm_unregister_from_group(sdm_channel_t *chan) static esp_err_t sdm_destroy(sdm_channel_t *chan) { -#if CONFIG_PM_ENABLE - if (chan->pm_lock) { - ESP_RETURN_ON_ERROR(esp_pm_lock_delete(chan->pm_lock), TAG, "delete pm lock failed"); - } -#endif if (chan->group) { sdm_unregister_from_group(chan); } + if (chan->gpio_num >= 0) { + gpio_output_disable(chan->gpio_num); + esp_gpio_revoke(BIT64(chan->gpio_num)); + } free(chan); return ESP_OK; } esp_err_t sdm_new_channel(const sdm_config_t *config, sdm_channel_handle_t *ret_chan) { -#if CONFIG_SDM_ENABLE_DEBUG_LOG - esp_log_level_set(TAG, ESP_LOG_DEBUG); -#endif esp_err_t ret = ESP_OK; sdm_channel_t *chan = NULL; - ESP_GOTO_ON_FALSE(config && ret_chan, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument"); - ESP_GOTO_ON_FALSE(GPIO_IS_VALID_OUTPUT_GPIO(config->gpio_num), ESP_ERR_INVALID_ARG, err, TAG, "invalid GPIO number"); + ESP_RETURN_ON_FALSE(config && ret_chan, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); + ESP_RETURN_ON_FALSE(GPIO_IS_VALID_OUTPUT_GPIO(config->gpio_num), ESP_ERR_INVALID_ARG, TAG, "invalid GPIO number"); - chan = heap_caps_calloc(1, sizeof(sdm_channel_t), SDM_MEM_ALLOC_CAPS); - ESP_GOTO_ON_FALSE(chan, ESP_ERR_NO_MEM, err, TAG, "no mem for channel"); + + // allocate channel memory from internal memory because it contains atomic variable + chan = heap_caps_calloc(1, sizeof(sdm_channel_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); + ESP_RETURN_ON_FALSE(chan, ESP_ERR_NO_MEM, TAG, "no mem for channel"); + chan->gpio_num = GPIO_NUM_NC; // default to NC, will be set later + + sdm_clock_source_t clk_src = config->clk_src ? config->clk_src : SDM_CLK_SRC_DEFAULT; // register channel to the group - ESP_GOTO_ON_ERROR(sdm_register_to_group(chan), err, TAG, "register to group failed"); + ESP_GOTO_ON_ERROR(sdm_register_to_group(chan, clk_src), err, TAG, "register to group failed"); sdm_group_t *group = chan->group; int group_id = group->group_id; int chan_id = chan->chan_id; - ESP_GOTO_ON_FALSE(group->clk_src == 0 || group->clk_src == config->clk_src, ESP_ERR_INVALID_ARG, err, TAG, "clock source conflict"); - uint32_t src_clk_hz = 0; - ESP_GOTO_ON_ERROR(esp_clk_tree_src_get_freq_hz((soc_module_clk_t)config->clk_src, - ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, &src_clk_hz), err, TAG, "get source clock frequency failed"); - -#if CONFIG_PM_ENABLE - esp_pm_lock_type_t pm_type = ESP_PM_NO_LIGHT_SLEEP; -#if SOC_SDM_CLK_SUPPORT_APB - if (config->clk_src == SDM_CLK_SRC_APB) { - pm_type = ESP_PM_APB_FREQ_MAX; - } -#endif // SOC_SDM_CLK_SUPPORT_APB - sprintf(chan->pm_lock_name, "sdm_%d_%d", group->group_id, chan_id); // e.g. sdm_0_0 - ret = esp_pm_lock_create(pm_type, 0, chan->pm_lock_name, &chan->pm_lock); - ESP_GOTO_ON_ERROR(ret, err, TAG, "create %s lock failed", chan->pm_lock_name); -#endif // CONFIG_PM_ENABLE - group->clk_src = config->clk_src; + ESP_GOTO_ON_FALSE(group->clk_src == clk_src, ESP_ERR_INVALID_ARG, err, TAG, "clock source conflict"); // SDM clock comes from IO MUX, but IO MUX clock might be shared with other submodules as well - ESP_GOTO_ON_ERROR(io_mux_set_clock_source((soc_module_clk_t)(group->clk_src)), err, TAG, "set IO MUX clock source failed"); + ESP_GOTO_ON_ERROR(io_mux_set_clock_source((soc_module_clk_t)clk_src), err, TAG, "set IO MUX clock source failed"); - gpio_func_sel(config->gpio_num, PIN_FUNC_GPIO); - // connect the signal to the GPIO by matrix, it will also enable the output path properly - esp_rom_gpio_connect_out_signal(config->gpio_num, sigma_delta_periph_signals.channels[chan_id].sd_sig, config->flags.invert_out, false); + uint32_t src_clk_hz = 0; + ESP_GOTO_ON_ERROR(esp_clk_tree_src_get_freq_hz((soc_module_clk_t)clk_src, + ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, &src_clk_hz), err, TAG, "get source clock frequency failed"); + + // Reserve the new GPIO + uint64_t old_gpio_rsv_mask = esp_gpio_reserve(BIT64(config->gpio_num)); + if (old_gpio_rsv_mask & BIT64(config->gpio_num)) { + ESP_LOGW(TAG, "GPIO %d is not usable, maybe conflict with others", config->gpio_num); + } + // connect the signal to the GPIO by matrix + gpio_matrix_output(config->gpio_num, soc_sdm_signals[group_id].channels[chan_id].sig_id_matrix, config->flags.invert_out, false); chan->gpio_num = config->gpio_num; // set prescale based on sample rate @@ -258,7 +269,7 @@ esp_err_t sdm_new_channel(const sdm_config_t *config, sdm_channel_handle_t *ret_ // initialize other members of timer chan->spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED; - chan->fsm = SDM_FSM_INIT; // put the channel into init state + atomic_init(&chan->fsm, SDM_FSM_INIT); // set the initial state to INIT ESP_LOGD(TAG, "new sdm channel (%d,%d) at %p, gpio=%d, sample rate=%"PRIu32"Hz", group_id, chan_id, chan, chan->gpio_num, chan->sample_rate_hz); *ret_chan = chan; @@ -273,12 +284,10 @@ err: esp_err_t sdm_del_channel(sdm_channel_handle_t chan) { ESP_RETURN_ON_FALSE(chan, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); - ESP_RETURN_ON_FALSE(chan->fsm == SDM_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "channel not in init state"); - sdm_group_t *group = chan->group; - int group_id = group->group_id; - int chan_id = chan->chan_id; - gpio_output_disable(chan->gpio_num); - ESP_LOGD(TAG, "del channel (%d,%d)", group_id, chan_id); + sdm_fsm_t expected_fsm = SDM_FSM_INIT; + ESP_RETURN_ON_FALSE(atomic_compare_exchange_strong(&chan->fsm, &expected_fsm, SDM_FSM_WAIT), + ESP_ERR_INVALID_STATE, TAG, "channel not in init state"); + ESP_LOGD(TAG, "del channel (%d,%d)", chan->group->group_id, chan->chan_id); // recycle memory resource ESP_RETURN_ON_ERROR(sdm_destroy(chan), TAG, "destroy channel failed"); return ESP_OK; @@ -287,36 +296,66 @@ esp_err_t sdm_del_channel(sdm_channel_handle_t chan) esp_err_t sdm_channel_enable(sdm_channel_handle_t chan) { ESP_RETURN_ON_FALSE(chan, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); - ESP_RETURN_ON_FALSE(chan->fsm == SDM_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "channel not in init state"); - + sdm_fsm_t expected_fsm = SDM_FSM_INIT; + if (atomic_compare_exchange_strong(&chan->fsm, &expected_fsm, SDM_FSM_WAIT)) { #if CONFIG_PM_ENABLE - // acquire power manager lock - if (chan->pm_lock) { - ESP_RETURN_ON_ERROR(esp_pm_lock_acquire(chan->pm_lock), TAG, "acquire pm_lock failed"); - } + // acquire power manager lock + if (chan->group->pm_lock) { + esp_pm_lock_acquire(chan->group->pm_lock); + } #endif - chan->fsm = SDM_FSM_ENABLE; + // enable the channel + atomic_store(&chan->fsm, SDM_FSM_ENABLE); // change state to ENABLE + ESP_LOGD(TAG, "channel (%d,%d) enabled", chan->group->group_id, chan->chan_id); + } else { + ESP_RETURN_ON_ERROR(ESP_ERR_INVALID_STATE, TAG, "channel not in init state"); + } + return ESP_OK; } esp_err_t sdm_channel_disable(sdm_channel_handle_t chan) { ESP_RETURN_ON_FALSE(chan, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); - ESP_RETURN_ON_FALSE(chan->fsm == SDM_FSM_ENABLE, ESP_ERR_INVALID_STATE, TAG, "channel not in enable state"); - + sdm_fsm_t expected_fsm = SDM_FSM_ENABLE; + if (atomic_compare_exchange_strong(&chan->fsm, &expected_fsm, SDM_FSM_WAIT)) { #if CONFIG_PM_ENABLE - // release power manager lock - if (chan->pm_lock) { - ESP_RETURN_ON_ERROR(esp_pm_lock_release(chan->pm_lock), TAG, "release pm_lock failed"); - } + // release power manager lock + if (chan->group->pm_lock) { + esp_pm_lock_release(chan->group->pm_lock); + } #endif - chan->fsm = SDM_FSM_INIT; + atomic_store(&chan->fsm, SDM_FSM_INIT); // change state to INIT + ESP_LOGD(TAG, "channel (%d,%d) disabled", chan->group->group_id, chan->chan_id); + } else { + ESP_RETURN_ON_ERROR(ESP_ERR_INVALID_STATE, TAG, "channel not in enable state"); + } + return ESP_OK; } esp_err_t sdm_channel_set_pulse_density(sdm_channel_handle_t chan, int8_t density) { - ESP_RETURN_ON_FALSE_ISR(chan, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); + if (!chan) { + return ESP_ERR_INVALID_ARG; + } + bool valid_state = false; + sdm_fsm_t expected_fsm = SDM_FSM_INIT; + sdm_fsm_t restore_fsm = SDM_FSM_INIT; + // check if the channel is in INIT state, if so, change it to WAIT state + if (atomic_compare_exchange_strong(&chan->fsm, &expected_fsm, SDM_FSM_WAIT)) { + valid_state = true; + restore_fsm = SDM_FSM_INIT; + } else { + expected_fsm = SDM_FSM_ENABLE; + if (atomic_compare_exchange_strong(&chan->fsm, &expected_fsm, SDM_FSM_WAIT)) { + valid_state = true; + restore_fsm = SDM_FSM_ENABLE; + } + } + if (!valid_state) { + return ESP_ERR_INVALID_STATE; + } sdm_group_t *group = chan->group; int chan_id = chan->chan_id; @@ -325,8 +364,18 @@ esp_err_t sdm_channel_set_pulse_density(sdm_channel_handle_t chan, int8_t densit sdm_ll_set_pulse_density(group->hal.dev, chan_id, density); portEXIT_CRITICAL_SAFE(&chan->spinlock); + atomic_store(&chan->fsm, restore_fsm); // restore the state + return ESP_OK; } esp_err_t sdm_channel_set_duty(sdm_channel_handle_t chan, int8_t duty) __attribute__((alias("sdm_channel_set_pulse_density"))); + +#if CONFIG_SDM_ENABLE_DEBUG_LOG +__attribute__((constructor)) +static void sdm_override_default_log_level(void) +{ + esp_log_level_set(TAG, ESP_LOG_VERBOSE); +} +#endif diff --git a/components/esp_driver_sdm/test_apps/sigma_delta/main/CMakeLists.txt b/components/esp_driver_sdm/test_apps/sigma_delta/main/CMakeLists.txt index 5484720431..b416b209f1 100644 --- a/components/esp_driver_sdm/test_apps/sigma_delta/main/CMakeLists.txt +++ b/components/esp_driver_sdm/test_apps/sigma_delta/main/CMakeLists.txt @@ -1,7 +1,7 @@ set(srcs "test_app_main.c") if(CONFIG_SOC_SDM_SUPPORTED) - list(APPEND srcs "test_sdm.c") + list(APPEND srcs "test_sdm.cpp") endif() # In order for the cases defined by `TEST_CASE` to be linked into the final elf, diff --git a/components/esp_driver_sdm/test_apps/sigma_delta/main/test_sdm.c b/components/esp_driver_sdm/test_apps/sigma_delta/main/test_sdm.cpp similarity index 71% rename from components/esp_driver_sdm/test_apps/sigma_delta/main/test_sdm.c rename to components/esp_driver_sdm/test_apps/sigma_delta/main/test_sdm.cpp index b3fedaa4f4..75f4626e9d 100644 --- a/components/esp_driver_sdm/test_apps/sigma_delta/main/test_sdm.c +++ b/components/esp_driver_sdm/test_apps/sigma_delta/main/test_sdm.cpp @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -10,28 +10,31 @@ #include "freertos/task.h" #include "unity.h" #include "driver/sdm.h" -#include "soc/soc_caps.h" +#include "soc/sdm_periph.h" #include "esp_attr.h" TEST_CASE("sdm_channel_install_uninstall", "[sdm]") { printf("install sdm channels exhaustively\r\n"); sdm_config_t config = { + .gpio_num = GPIO_NUM_0, .clk_src = SDM_CLK_SRC_DEFAULT, .sample_rate_hz = 1000000, - .gpio_num = 0, + .flags = { + .invert_out = false, + }, }; - sdm_channel_handle_t chans[SOC_SDM_GROUPS][SOC_SDM_CHANNELS_PER_GROUP] = {}; - for (int i = 0; i < SOC_SDM_GROUPS; i++) { - for (int j = 0; j < SOC_SDM_CHANNELS_PER_GROUP; j++) { + sdm_channel_handle_t chans[SOC_SDM_ATTR(INST_NUM)][SOC_SDM_ATTR(CHANS_PER_INST)] = {}; + for (int i = 0; i < SOC_SDM_ATTR(INST_NUM); i++) { + for (int j = 0; j < SOC_SDM_ATTR(CHANS_PER_INST); j++) { TEST_ESP_OK(sdm_new_channel(&config, &chans[i][j])); } TEST_ESP_ERR(ESP_ERR_NOT_FOUND, sdm_new_channel(&config, &chans[0][0])); } printf("delete sdm channels\r\n"); - for (int i = 0; i < SOC_SDM_GROUPS; i++) { - for (int j = 0; j < SOC_SDM_CHANNELS_PER_GROUP; j++) { + for (int i = 0; i < SOC_SDM_ATTR(INST_NUM); i++) { + for (int j = 0; j < SOC_SDM_ATTR(CHANS_PER_INST); j++) { TEST_ESP_OK(sdm_del_channel(chans[i][j])); } } @@ -39,10 +42,14 @@ TEST_CASE("sdm_channel_install_uninstall", "[sdm]") TEST_CASE("sdm_channel_set_pulse_density", "[sdm]") { - const int sdm_chan_gpios[2] = {0, 2}; + const gpio_num_t sdm_chan_gpios[2] = {GPIO_NUM_0, GPIO_NUM_2}; sdm_config_t config = { + .gpio_num = GPIO_NUM_NC, // will be set later .clk_src = SDM_CLK_SRC_DEFAULT, .sample_rate_hz = 1000000, + .flags = { + .invert_out = false, + }, }; sdm_channel_handle_t chans[2] = {}; for (size_t i = 0; i < 2; i++) { diff --git a/components/esp_driver_sdm/test_apps/sigma_delta/pytest_sigma_delta.py b/components/esp_driver_sdm/test_apps/sigma_delta/pytest_sigma_delta.py index 7f614064ab..14e4328015 100644 --- a/components/esp_driver_sdm/test_apps/sigma_delta/pytest_sigma_delta.py +++ b/components/esp_driver_sdm/test_apps/sigma_delta/pytest_sigma_delta.py @@ -3,6 +3,7 @@ import pytest from pytest_embedded_idf import IdfDut from pytest_embedded_idf.utils import idf_parametrize +from pytest_embedded_idf.utils import soc_filtered_targets CONFIGS = [ 'iram_safe', @@ -14,7 +15,7 @@ CONFIGS = [ @pytest.mark.parametrize('config', CONFIGS, indirect=True) @idf_parametrize( 'target', - ['esp32', 'esp32c3', 'esp32c5', 'esp32c6', 'esp32h2', 'esp32s2', 'esp32s3', 'esp32h2', 'esp32p4'], + soc_filtered_targets('SOC_SDM_SUPPORTED == 1'), indirect=['target'], ) def test_sdm(dut: IdfDut) -> None: diff --git a/components/hal/esp32/include/hal/sdm_ll.h b/components/hal/esp32/include/hal/sdm_ll.h index 45bd8a4067..1f76b3a40b 100644 --- a/components/hal/esp32/include/hal/sdm_ll.h +++ b/components/hal/esp32/include/hal/sdm_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -16,8 +16,14 @@ extern "C" { #endif +// Get SDM register base address with giving group number +#define SDM_LL_GET_HW(group_id) ((group_id == 0) ? (&SDM) : NULL) + #define SDM_LL_PRESCALE_MAX (GPIO_SD0_PRESCALE_V + 1) +// Support APB as function clock +#define SDM_LL_FUNC_CLOCK_SUPPORT_APB 1 + /** * @brief Set Sigma-delta enable * diff --git a/components/hal/esp32c3/include/hal/sdm_ll.h b/components/hal/esp32c3/include/hal/sdm_ll.h index 70071812a3..8b981c134b 100644 --- a/components/hal/esp32c3/include/hal/sdm_ll.h +++ b/components/hal/esp32c3/include/hal/sdm_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2020-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -16,8 +16,14 @@ extern "C" { #endif +// Get SDM register base address with giving group number +#define SDM_LL_GET_HW(group_id) ((group_id == 0) ? (&SDM) : NULL) + #define SDM_LL_PRESCALE_MAX (GPIO_SD0_PRESCALE_V + 1) +// Support APB as function clock +#define SDM_LL_FUNC_CLOCK_SUPPORT_APB 1 + /** * @brief Set Sigma-delta enable * diff --git a/components/hal/esp32c5/include/hal/sdm_ll.h b/components/hal/esp32c5/include/hal/sdm_ll.h index c73e06cb92..828c3207ba 100644 --- a/components/hal/esp32c5/include/hal/sdm_ll.h +++ b/components/hal/esp32c5/include/hal/sdm_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -16,6 +16,9 @@ extern "C" { #endif +// Get SDM register base address with giving group number +#define SDM_LL_GET_HW(group_id) ((group_id == 0) ? (&SDM) : NULL) + #define SDM_LL_PRESCALE_MAX (GPIO_EXT_SD0_PRESCALE_V + 1) /** diff --git a/components/hal/esp32c6/include/hal/sdm_ll.h b/components/hal/esp32c6/include/hal/sdm_ll.h index e2da68b485..089cdc7f92 100644 --- a/components/hal/esp32c6/include/hal/sdm_ll.h +++ b/components/hal/esp32c6/include/hal/sdm_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -16,6 +16,9 @@ extern "C" { #endif +// Get SDM register base address with giving group number +#define SDM_LL_GET_HW(group_id) ((group_id == 0) ? (&SDM) : NULL) + #define SDM_LL_PRESCALE_MAX (GPIO_EXT_SD0_PRESCALE_V + 1) /** diff --git a/components/hal/esp32h2/include/hal/sdm_ll.h b/components/hal/esp32h2/include/hal/sdm_ll.h index e2da68b485..089cdc7f92 100644 --- a/components/hal/esp32h2/include/hal/sdm_ll.h +++ b/components/hal/esp32h2/include/hal/sdm_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -16,6 +16,9 @@ extern "C" { #endif +// Get SDM register base address with giving group number +#define SDM_LL_GET_HW(group_id) ((group_id == 0) ? (&SDM) : NULL) + #define SDM_LL_PRESCALE_MAX (GPIO_EXT_SD0_PRESCALE_V + 1) /** diff --git a/components/hal/esp32p4/include/hal/sdm_ll.h b/components/hal/esp32p4/include/hal/sdm_ll.h index e2da68b485..089cdc7f92 100644 --- a/components/hal/esp32p4/include/hal/sdm_ll.h +++ b/components/hal/esp32p4/include/hal/sdm_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -16,6 +16,9 @@ extern "C" { #endif +// Get SDM register base address with giving group number +#define SDM_LL_GET_HW(group_id) ((group_id == 0) ? (&SDM) : NULL) + #define SDM_LL_PRESCALE_MAX (GPIO_EXT_SD0_PRESCALE_V + 1) /** diff --git a/components/hal/esp32s2/include/hal/sdm_ll.h b/components/hal/esp32s2/include/hal/sdm_ll.h index 009e7e94af..0f3e354d3a 100644 --- a/components/hal/esp32s2/include/hal/sdm_ll.h +++ b/components/hal/esp32s2/include/hal/sdm_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -16,8 +16,14 @@ extern "C" { #endif +// Get SDM register base address with giving group number +#define SDM_LL_GET_HW(group_id) ((group_id == 0) ? (&SDM) : NULL) + #define SDM_LL_PRESCALE_MAX (GPIO_SD0_PRESCALE_V + 1) +// Support APB as function clock +#define SDM_LL_FUNC_CLOCK_SUPPORT_APB 1 + /** * @brief Set Sigma-delta enable * diff --git a/components/hal/esp32s3/include/hal/sdm_ll.h b/components/hal/esp32s3/include/hal/sdm_ll.h index 58ec1eb469..d83aaf2ba5 100644 --- a/components/hal/esp32s3/include/hal/sdm_ll.h +++ b/components/hal/esp32s3/include/hal/sdm_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -16,8 +16,14 @@ extern "C" { #endif +// Get SDM register base address with giving group number +#define SDM_LL_GET_HW(group_id) ((group_id == 0) ? (&SDM) : NULL) + #define SDM_LL_PRESCALE_MAX (GPIO_SD0_PRESCALE_V + 1) +// Support APB as function clock +#define SDM_LL_FUNC_CLOCK_SUPPORT_APB 1 + /** * @brief Set Sigma-delta enable * diff --git a/components/hal/include/hal/sdm_hal.h b/components/hal/include/hal/sdm_hal.h index cddf240367..e28dedbb81 100644 --- a/components/hal/include/hal/sdm_hal.h +++ b/components/hal/include/hal/sdm_hal.h @@ -1,15 +1,9 @@ /* - * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ -/******************************************************************************* - * NOTICE - * The hal is not public api, don't use in application code. - * See readme.md in hal/include/hal/readme.md - ******************************************************************************/ - // The HAL layer for sigma delta modulator. // There is no parameter check in the hal layer, so the caller must ensure the correctness of the parameters. @@ -28,13 +22,27 @@ typedef struct { sdm_soc_handle_t dev; } sdm_hal_context_t; +/** + * @brief Configuration for the Sigma-Delta HAL layer initialization + */ +typedef struct { + int group_id; // Group ID, index from 0 +} sdm_hal_init_config_t; + /** * @brief Initialize Sigma-Delta hal driver * * @param hal Context of the HAL layer - * @param group_id Sigma-Delta group number + * @param config Configuration for the HAL layer initialization */ -void sdm_hal_init(sdm_hal_context_t *hal, int group_id); +void sdm_hal_init(sdm_hal_context_t *hal, const sdm_hal_init_config_t *config); + +/** + * @brief Deinitialize Sigma-Delta hal driver + * + * @param hal Context of the HAL layer + */ +void sdm_hal_deinit(sdm_hal_context_t *hal); #ifdef __cplusplus } diff --git a/components/hal/sdm_hal.c b/components/hal/sdm_hal.c index 261bd51d03..8510e84051 100644 --- a/components/hal/sdm_hal.c +++ b/components/hal/sdm_hal.c @@ -1,16 +1,25 @@ /* - * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ -// The HAL layer for sigma delta modulator (common part) - #include "hal/sdm_ll.h" #include "hal/sdm_hal.h" -void sdm_hal_init(sdm_hal_context_t *hal, int group_id) +void sdm_hal_init(sdm_hal_context_t *hal, const sdm_hal_init_config_t *config) { - (void) group_id; - hal->dev = &SDM; + hal->dev = SDM_LL_GET_HW(config->group_id); + // enable clock + // note that, this will enables all the channels' output, and channel can't be disable/enable separately + sdm_ll_enable_clock(hal->dev, true); +} + +void sdm_hal_deinit(sdm_hal_context_t *hal) +{ + if (hal && hal->dev) { + // disable clock + sdm_ll_enable_clock(hal->dev, false); + hal->dev = NULL; + } } diff --git a/components/soc/esp32/include/soc/Kconfig.soc_caps.in b/components/soc/esp32/include/soc/Kconfig.soc_caps.in index 716a0d8009..095b85a197 100644 --- a/components/soc/esp32/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32/include/soc/Kconfig.soc_caps.in @@ -623,18 +623,6 @@ config SOC_RTCIO_WAKE_SUPPORTED bool default y -config SOC_SDM_GROUPS - int - default 1 - -config SOC_SDM_CHANNELS_PER_GROUP - int - default 8 - -config SOC_SDM_CLK_SUPPORT_APB - bool - default y - config SOC_SPI_HD_BOTH_INOUT_SUPPORTED bool default y diff --git a/components/soc/esp32/include/soc/clk_tree_defs.h b/components/soc/esp32/include/soc/clk_tree_defs.h index 52abdd632f..8e1f0ecc52 100644 --- a/components/soc/esp32/include/soc/clk_tree_defs.h +++ b/components/soc/esp32/include/soc/clk_tree_defs.h @@ -178,14 +178,6 @@ typedef enum { GPTIMER_CLK_SRC_DEFAULT = SOC_MOD_CLK_APB, /*!< Select APB as the default choice */ } soc_periph_gptimer_clk_src_t; -/** - * @brief Type of Timer Group clock source, reserved for the legacy timer group driver - */ -typedef enum { - TIMER_SRC_CLK_APB = SOC_MOD_CLK_APB, /*!< Timer group source clock is APB */ - TIMER_SRC_CLK_DEFAULT = SOC_MOD_CLK_APB, /*!< Timer group source clock default choice is APB */ -} soc_periph_tg_clk_src_legacy_t; - //////////////////////////////////////////////////LCD/////////////////////////////////////////////////////////////////// /** diff --git a/components/soc/esp32/include/soc/soc_caps.h b/components/soc/esp32/include/soc/soc_caps.h index e2d5f83384..e88c4c984f 100644 --- a/components/soc/esp32/include/soc/soc_caps.h +++ b/components/soc/esp32/include/soc/soc_caps.h @@ -297,11 +297,6 @@ #define SOC_RTCIO_HOLD_SUPPORTED 1 #define SOC_RTCIO_WAKE_SUPPORTED 1 -/*-------------------------- Sigma Delta Modulator CAPS -----------------*/ -#define SOC_SDM_GROUPS 1U -#define SOC_SDM_CHANNELS_PER_GROUP 8 -#define SOC_SDM_CLK_SUPPORT_APB 1 - /*-------------------------- SPI CAPS ----------------------------------------*/ #define SOC_SPI_HD_BOTH_INOUT_SUPPORTED 1 //Support enabling MOSI and MISO phases together under Halfduplex mode #define SOC_SPI_AS_CS_SUPPORTED 1 //Support to toggle the CS while the clock toggles diff --git a/components/soc/esp32/include/soc/soc_caps_full.h b/components/soc/esp32/include/soc/soc_caps_full.h index ddee8e204d..acf38bfcb4 100644 --- a/components/soc/esp32/include/soc/soc_caps_full.h +++ b/components/soc/esp32/include/soc/soc_caps_full.h @@ -19,3 +19,7 @@ /*--------------------------- Watch Dog ------------------------------------------*/ #define _SOC_CAPS_WDT_MWDTS_PER_TIMG 1 // Number of main watchdog timers in each Timer Group + +/*--------------------------- SDM (Sigma-Delta Modulator) ------------------------*/ +#define _SOC_CAPS_SDM_INST_NUM 1 // Number of SDM instances +#define _SOC_CAPS_SDM_CHANS_PER_INST 8 // Number of channels in each SDM instance diff --git a/components/soc/esp32/sdm_periph.c b/components/soc/esp32/sdm_periph.c index 2445620be9..4107208205 100644 --- a/components/soc/esp32/sdm_periph.c +++ b/components/soc/esp32/sdm_periph.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2020-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -7,31 +7,34 @@ #include "soc/sdm_periph.h" #include "soc/gpio_sig_map.h" -const sigma_delta_signal_conn_t sigma_delta_periph_signals = { - .channels = { - [0] = { - GPIO_SD0_OUT_IDX - }, - [1] = { - GPIO_SD1_OUT_IDX - }, - [2] = { - GPIO_SD2_OUT_IDX - }, - [3] = { - GPIO_SD3_OUT_IDX - }, - [4] = { - GPIO_SD4_OUT_IDX - }, - [5] = { - GPIO_SD5_OUT_IDX - }, - [6] = { - GPIO_SD6_OUT_IDX - }, - [7] = { - GPIO_SD7_OUT_IDX +const soc_sdm_signal_desc_t soc_sdm_signals[1] = { + [0] = { + .module_name = "SDM0", + .channels = { + [0] = { + .sig_id_matrix = GPIO_SD0_OUT_IDX + }, + [1] = { + .sig_id_matrix = GPIO_SD1_OUT_IDX + }, + [2] = { + .sig_id_matrix = GPIO_SD2_OUT_IDX + }, + [3] = { + .sig_id_matrix = GPIO_SD3_OUT_IDX + }, + [4] = { + .sig_id_matrix = GPIO_SD4_OUT_IDX + }, + [5] = { + .sig_id_matrix = GPIO_SD5_OUT_IDX + }, + [6] = { + .sig_id_matrix = GPIO_SD6_OUT_IDX + }, + [7] = { + .sig_id_matrix = GPIO_SD7_OUT_IDX + } } } }; diff --git a/components/soc/esp32c2/include/soc/clk_tree_defs.h b/components/soc/esp32c2/include/soc/clk_tree_defs.h index e88e484f99..98e7febe0d 100644 --- a/components/soc/esp32c2/include/soc/clk_tree_defs.h +++ b/components/soc/esp32c2/include/soc/clk_tree_defs.h @@ -175,15 +175,6 @@ typedef enum { GPTIMER_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_F40M, /*!< Select PLL_F40M as the default choice */ } soc_periph_gptimer_clk_src_t; -/** - * @brief Type of Timer Group clock source, reserved for the legacy timer group driver - */ -typedef enum { - TIMER_SRC_CLK_PLL_F40M = SOC_MOD_CLK_PLL_F40M, /*!< Timer group clock source is PLL_F40M */ - TIMER_SRC_CLK_XTAL = SOC_MOD_CLK_XTAL, /*!< Timer group clock source is XTAL */ - TIMER_SRC_CLK_DEFAULT = SOC_MOD_CLK_PLL_F40M, /*!< Timer group clock source default choice is PLL_F40M */ -} soc_periph_tg_clk_src_legacy_t; - //////////////////////////////////////////////////Temp Sensor/////////////////////////////////////////////////////////// /** diff --git a/components/soc/esp32c3/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c3/include/soc/Kconfig.soc_caps.in index 1d5fbd4d16..db79f2f60d 100644 --- a/components/soc/esp32c3/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c3/include/soc/Kconfig.soc_caps.in @@ -707,18 +707,6 @@ config SOC_SHA_SUPPORT_SHA256 bool default y -config SOC_SDM_GROUPS - int - default 1 - -config SOC_SDM_CHANNELS_PER_GROUP - int - default 4 - -config SOC_SDM_CLK_SUPPORT_APB - bool - default y - config SOC_SPI_PERIPH_NUM int default 2 diff --git a/components/soc/esp32c3/include/soc/clk_tree_defs.h b/components/soc/esp32c3/include/soc/clk_tree_defs.h index 4b3076897e..01a8abc728 100644 --- a/components/soc/esp32c3/include/soc/clk_tree_defs.h +++ b/components/soc/esp32c3/include/soc/clk_tree_defs.h @@ -171,15 +171,6 @@ typedef enum { GPTIMER_CLK_SRC_DEFAULT = SOC_MOD_CLK_APB, /*!< Select APB as the default choice */ } soc_periph_gptimer_clk_src_t; -/** - * @brief Type of Timer Group clock source, reserved for the legacy timer group driver - */ -typedef enum { - TIMER_SRC_CLK_APB = SOC_MOD_CLK_APB, /*!< Timer group clock source is APB */ - TIMER_SRC_CLK_XTAL = SOC_MOD_CLK_XTAL, /*!< Timer group clock source is XTAL */ - TIMER_SRC_CLK_DEFAULT = SOC_MOD_CLK_APB, /*!< Timer group clock source default choice is APB */ -} soc_periph_tg_clk_src_legacy_t; - //////////////////////////////////////////////////RMT/////////////////////////////////////////////////////////////////// /** diff --git a/components/soc/esp32c3/include/soc/soc_caps.h b/components/soc/esp32c3/include/soc/soc_caps.h index 5f56f39f7c..6db023c42c 100644 --- a/components/soc/esp32c3/include/soc/soc_caps.h +++ b/components/soc/esp32c3/include/soc/soc_caps.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -309,11 +309,6 @@ #define SOC_SHA_SUPPORT_SHA224 (1) #define SOC_SHA_SUPPORT_SHA256 (1) -/*-------------------------- Sigma Delta Modulator CAPS -----------------*/ -#define SOC_SDM_GROUPS 1U -#define SOC_SDM_CHANNELS_PER_GROUP 4 -#define SOC_SDM_CLK_SUPPORT_APB 1 - /*-------------------------- SPI CAPS ----------------------------------------*/ #define SOC_SPI_PERIPH_NUM 2 #define SOC_SPI_PERIPH_CS_NUM(i) 6 diff --git a/components/soc/esp32c3/include/soc/soc_caps_full.h b/components/soc/esp32c3/include/soc/soc_caps_full.h index 6ccb00bd76..63d2d2eec5 100644 --- a/components/soc/esp32c3/include/soc/soc_caps_full.h +++ b/components/soc/esp32c3/include/soc/soc_caps_full.h @@ -19,3 +19,7 @@ /*--------------------------- Watch Dog ------------------------------------------*/ #define _SOC_CAPS_WDT_MWDTS_PER_TIMG 1 // Number of main watchdog timers in each Timer Group + +/*--------------------------- SDM (Sigma-Delta Modulator) ------------------------*/ +#define _SOC_CAPS_SDM_INST_NUM 1 // Number of SDM instances +#define _SOC_CAPS_SDM_CHANS_PER_INST 4 // Number of channels in each SDM instance diff --git a/components/soc/esp32c3/sdm_periph.c b/components/soc/esp32c3/sdm_periph.c index f52b1758a8..50051ba117 100644 --- a/components/soc/esp32c3/sdm_periph.c +++ b/components/soc/esp32c3/sdm_periph.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2020-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -7,19 +7,22 @@ #include "soc/sdm_periph.h" #include "soc/gpio_sig_map.h" -const sigma_delta_signal_conn_t sigma_delta_periph_signals = { - .channels = { - [0] = { - GPIO_SD0_OUT_IDX - }, - [1] = { - GPIO_SD1_OUT_IDX - }, - [2] = { - GPIO_SD2_OUT_IDX - }, - [3] = { - GPIO_SD3_OUT_IDX +const soc_sdm_signal_desc_t soc_sdm_signals[1] = { + [0] = { + .module_name = "SDM0", + .channels = { + [0] = { + .sig_id_matrix = GPIO_SD0_OUT_IDX + }, + [1] = { + .sig_id_matrix = GPIO_SD1_OUT_IDX + }, + [2] = { + .sig_id_matrix = GPIO_SD2_OUT_IDX + }, + [3] = { + .sig_id_matrix = GPIO_SD3_OUT_IDX + } } } }; diff --git a/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in index ccd3b55333..7440849224 100644 --- a/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in @@ -1127,22 +1127,6 @@ config SOC_ECDSA_SUPPORT_CURVE_P384 bool default y -config SOC_SDM_GROUPS - int - default 1 - -config SOC_SDM_CHANNELS_PER_GROUP - int - default 4 - -config SOC_SDM_CLK_SUPPORT_PLL_F80M - bool - default y - -config SOC_SDM_CLK_SUPPORT_XTAL - bool - default y - config SOC_SPI_PERIPH_NUM int default 2 diff --git a/components/soc/esp32c5/include/soc/clk_tree_defs.h b/components/soc/esp32c5/include/soc/clk_tree_defs.h index 52e126865c..8509e890da 100644 --- a/components/soc/esp32c5/include/soc/clk_tree_defs.h +++ b/components/soc/esp32c5/include/soc/clk_tree_defs.h @@ -192,15 +192,6 @@ typedef enum { GPTIMER_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_F80M, /*!< Select PLL_F80M as the default choice */ } soc_periph_gptimer_clk_src_t; -/** - * @brief Type of Timer Group clock source, reserved for the legacy timer group driver - */ -typedef enum { - TIMER_SRC_CLK_PLL_F80M = SOC_MOD_CLK_PLL_F80M, /*!< Timer group clock source is PLL_F80M */ - TIMER_SRC_CLK_XTAL = SOC_MOD_CLK_XTAL, /*!< Timer group clock source is XTAL */ - TIMER_SRC_CLK_DEFAULT = SOC_MOD_CLK_PLL_F80M, /*!< Timer group clock source default choice is PLL_F80M */ -} soc_periph_tg_clk_src_legacy_t; - //////////////////////////////////////////////////RMT/////////////////////////////////////////////////////////////////// /** diff --git a/components/soc/esp32c5/include/soc/soc_caps.h b/components/soc/esp32c5/include/soc/soc_caps.h index e42a62ab5a..34b3944b87 100644 --- a/components/soc/esp32c5/include/soc/soc_caps.h +++ b/components/soc/esp32c5/include/soc/soc_caps.h @@ -444,12 +444,6 @@ #define SOC_ECDSA_SUPPORT_HW_DETERMINISTIC_LOOP (1) #define SOC_ECDSA_SUPPORT_CURVE_P384 (1) -/*-------------------------- Sigma Delta Modulator CAPS -----------------*/ -#define SOC_SDM_GROUPS 1U -#define SOC_SDM_CHANNELS_PER_GROUP 4 -#define SOC_SDM_CLK_SUPPORT_PLL_F80M 1 -#define SOC_SDM_CLK_SUPPORT_XTAL 1 - /*-------------------------- SPI CAPS ----------------------------------------*/ #define SOC_SPI_PERIPH_NUM 2 #define SOC_SPI_PERIPH_CS_NUM(i) 6 diff --git a/components/soc/esp32c5/include/soc/soc_caps_full.h b/components/soc/esp32c5/include/soc/soc_caps_full.h index 6ccb00bd76..63d2d2eec5 100644 --- a/components/soc/esp32c5/include/soc/soc_caps_full.h +++ b/components/soc/esp32c5/include/soc/soc_caps_full.h @@ -19,3 +19,7 @@ /*--------------------------- Watch Dog ------------------------------------------*/ #define _SOC_CAPS_WDT_MWDTS_PER_TIMG 1 // Number of main watchdog timers in each Timer Group + +/*--------------------------- SDM (Sigma-Delta Modulator) ------------------------*/ +#define _SOC_CAPS_SDM_INST_NUM 1 // Number of SDM instances +#define _SOC_CAPS_SDM_CHANS_PER_INST 4 // Number of channels in each SDM instance diff --git a/components/soc/esp32c5/sdm_periph.c b/components/soc/esp32c5/sdm_periph.c index db4505de0e..b92e215fb5 100644 --- a/components/soc/esp32c5/sdm_periph.c +++ b/components/soc/esp32c5/sdm_periph.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -7,19 +7,22 @@ #include "soc/sdm_periph.h" #include "soc/gpio_sig_map.h" -const sigma_delta_signal_conn_t sigma_delta_periph_signals = { - .channels = { - [0] = { - GPIO_SD0_OUT_IDX - }, - [1] = { - GPIO_SD1_OUT_IDX - }, - [2] = { - GPIO_SD2_OUT_IDX - }, - [3] = { - GPIO_SD3_OUT_IDX +const soc_sdm_signal_desc_t soc_sdm_signals[1] = { + [0] = { + .module_name = "SDM0", + .channels = { + [0] = { + .sig_id_matrix = GPIO_SD0_OUT_IDX + }, + [1] = { + .sig_id_matrix = GPIO_SD1_OUT_IDX + }, + [2] = { + .sig_id_matrix = GPIO_SD2_OUT_IDX + }, + [3] = { + .sig_id_matrix = GPIO_SD3_OUT_IDX + } } } }; diff --git a/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in index ebd805c524..eb3ba8d31a 100644 --- a/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in @@ -987,22 +987,6 @@ config SOC_SHA_SUPPORT_SHA256 bool default y -config SOC_SDM_GROUPS - int - default 1 - -config SOC_SDM_CHANNELS_PER_GROUP - int - default 4 - -config SOC_SDM_CLK_SUPPORT_PLL_F80M - bool - default y - -config SOC_SDM_CLK_SUPPORT_XTAL - bool - default y - config SOC_SPI_PERIPH_NUM int default 2 diff --git a/components/soc/esp32c6/include/soc/clk_tree_defs.h b/components/soc/esp32c6/include/soc/clk_tree_defs.h index 23e1a5adbf..c67068f35e 100644 --- a/components/soc/esp32c6/include/soc/clk_tree_defs.h +++ b/components/soc/esp32c6/include/soc/clk_tree_defs.h @@ -189,15 +189,6 @@ typedef enum { GPTIMER_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_F80M, /*!< Select PLL_F80M as the default choice */ } soc_periph_gptimer_clk_src_t; -/** - * @brief Type of Timer Group clock source, reserved for the legacy timer group driver - */ -typedef enum { - TIMER_SRC_CLK_PLL_F80M = SOC_MOD_CLK_PLL_F80M, /*!< Timer group clock source is PLL_F80M */ - TIMER_SRC_CLK_XTAL = SOC_MOD_CLK_XTAL, /*!< Timer group clock source is XTAL */ - TIMER_SRC_CLK_DEFAULT = SOC_MOD_CLK_PLL_F80M, /*!< Timer group clock source default choice is PLL_F80M */ -} soc_periph_tg_clk_src_legacy_t; - //////////////////////////////////////////////////RMT/////////////////////////////////////////////////////////////////// /** diff --git a/components/soc/esp32c6/include/soc/soc_caps.h b/components/soc/esp32c6/include/soc/soc_caps.h index be26d94f1f..46580ed16e 100644 --- a/components/soc/esp32c6/include/soc/soc_caps.h +++ b/components/soc/esp32c6/include/soc/soc_caps.h @@ -394,12 +394,6 @@ #define SOC_SHA_SUPPORT_SHA224 (1) #define SOC_SHA_SUPPORT_SHA256 (1) -/*-------------------------- Sigma Delta Modulator CAPS -----------------*/ -#define SOC_SDM_GROUPS 1U -#define SOC_SDM_CHANNELS_PER_GROUP 4 -#define SOC_SDM_CLK_SUPPORT_PLL_F80M 1 -#define SOC_SDM_CLK_SUPPORT_XTAL 1 - /*-------------------------- SPI CAPS ----------------------------------------*/ #define SOC_SPI_PERIPH_NUM 2 #define SOC_SPI_PERIPH_CS_NUM(i) 6 diff --git a/components/soc/esp32c6/include/soc/soc_caps_full.h b/components/soc/esp32c6/include/soc/soc_caps_full.h index 6ccb00bd76..63d2d2eec5 100644 --- a/components/soc/esp32c6/include/soc/soc_caps_full.h +++ b/components/soc/esp32c6/include/soc/soc_caps_full.h @@ -19,3 +19,7 @@ /*--------------------------- Watch Dog ------------------------------------------*/ #define _SOC_CAPS_WDT_MWDTS_PER_TIMG 1 // Number of main watchdog timers in each Timer Group + +/*--------------------------- SDM (Sigma-Delta Modulator) ------------------------*/ +#define _SOC_CAPS_SDM_INST_NUM 1 // Number of SDM instances +#define _SOC_CAPS_SDM_CHANS_PER_INST 4 // Number of channels in each SDM instance diff --git a/components/soc/esp32c6/sdm_periph.c b/components/soc/esp32c6/sdm_periph.c index 6d41dc98f1..b92e215fb5 100644 --- a/components/soc/esp32c6/sdm_periph.c +++ b/components/soc/esp32c6/sdm_periph.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -7,19 +7,22 @@ #include "soc/sdm_periph.h" #include "soc/gpio_sig_map.h" -const sigma_delta_signal_conn_t sigma_delta_periph_signals = { - .channels = { - [0] = { - GPIO_SD0_OUT_IDX - }, - [1] = { - GPIO_SD1_OUT_IDX - }, - [2] = { - GPIO_SD2_OUT_IDX - }, - [3] = { - GPIO_SD3_OUT_IDX +const soc_sdm_signal_desc_t soc_sdm_signals[1] = { + [0] = { + .module_name = "SDM0", + .channels = { + [0] = { + .sig_id_matrix = GPIO_SD0_OUT_IDX + }, + [1] = { + .sig_id_matrix = GPIO_SD1_OUT_IDX + }, + [2] = { + .sig_id_matrix = GPIO_SD2_OUT_IDX + }, + [3] = { + .sig_id_matrix = GPIO_SD3_OUT_IDX + } } } }; diff --git a/components/soc/esp32c61/include/soc/clk_tree_defs.h b/components/soc/esp32c61/include/soc/clk_tree_defs.h index 76ffae3b14..fb26c2550c 100644 --- a/components/soc/esp32c61/include/soc/clk_tree_defs.h +++ b/components/soc/esp32c61/include/soc/clk_tree_defs.h @@ -180,15 +180,6 @@ typedef enum { GPTIMER_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_F80M, /*!< Select PLL_F80M as the default choice */ } soc_periph_gptimer_clk_src_t; -/** - * @brief Type of Timer Group clock source, reserved for the legacy timer group driver - */ -typedef enum { - TIMER_SRC_CLK_PLL_F80M = SOC_MOD_CLK_PLL_F80M, /*!< Timer group clock source is PLL_F80M */ - TIMER_SRC_CLK_XTAL = SOC_MOD_CLK_XTAL, /*!< Timer group clock source is XTAL */ - TIMER_SRC_CLK_DEFAULT = SOC_MOD_CLK_PLL_F80M, /*!< Timer group clock source default choice is PLL_F80M */ -} soc_periph_tg_clk_src_legacy_t; - //////////////////////////////////////////////////Temp Sensor/////////////////////////////////////////////////////////// /** diff --git a/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in b/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in index 1c58c53324..dc57925b10 100644 --- a/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in @@ -1003,22 +1003,6 @@ config SOC_SHA_SUPPORT_SHA256 bool default y -config SOC_SDM_GROUPS - int - default 1 - -config SOC_SDM_CHANNELS_PER_GROUP - int - default 4 - -config SOC_SDM_CLK_SUPPORT_PLL_F48M - bool - default y - -config SOC_SDM_CLK_SUPPORT_XTAL - bool - default y - config SOC_SPI_PERIPH_NUM int default 2 diff --git a/components/soc/esp32h2/include/soc/clk_tree_defs.h b/components/soc/esp32h2/include/soc/clk_tree_defs.h index 4d1959bad2..f39072a9bc 100644 --- a/components/soc/esp32h2/include/soc/clk_tree_defs.h +++ b/components/soc/esp32h2/include/soc/clk_tree_defs.h @@ -198,15 +198,6 @@ typedef enum { GPTIMER_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_F48M, /*!< Select PLL_F48M as the default choice */ } soc_periph_gptimer_clk_src_t; -/** - * @brief Type of Timer Group clock source, reserved for the legacy timer group driver - */ -typedef enum { - TIMER_SRC_CLK_PLL_F48M = SOC_MOD_CLK_PLL_F48M, /*!< Timer group clock source is PLL_F48M */ - TIMER_SRC_CLK_XTAL = SOC_MOD_CLK_XTAL, /*!< Timer group clock source is XTAL */ - TIMER_SRC_CLK_DEFAULT = SOC_MOD_CLK_PLL_F48M, /*!< Timer group clock source default choice is PLL_F48M */ -} soc_periph_tg_clk_src_legacy_t; - //////////////////////////////////////////////////RMT/////////////////////////////////////////////////////////////////// /** diff --git a/components/soc/esp32h2/include/soc/soc_caps.h b/components/soc/esp32h2/include/soc/soc_caps.h index 203f450bf1..b64fb789d4 100644 --- a/components/soc/esp32h2/include/soc/soc_caps.h +++ b/components/soc/esp32h2/include/soc/soc_caps.h @@ -412,12 +412,6 @@ #define SOC_SHA_SUPPORT_SHA224 (1) #define SOC_SHA_SUPPORT_SHA256 (1) -/*-------------------------- Sigma Delta Modulator CAPS -----------------*/ -#define SOC_SDM_GROUPS 1U -#define SOC_SDM_CHANNELS_PER_GROUP 4 -#define SOC_SDM_CLK_SUPPORT_PLL_F48M 1 -#define SOC_SDM_CLK_SUPPORT_XTAL 1 - /*-------------------------- SPI CAPS ----------------------------------------*/ #define SOC_SPI_PERIPH_NUM 2 #define SOC_SPI_PERIPH_CS_NUM(i) 6 diff --git a/components/soc/esp32h2/include/soc/soc_caps_full.h b/components/soc/esp32h2/include/soc/soc_caps_full.h index 6ccb00bd76..63d2d2eec5 100644 --- a/components/soc/esp32h2/include/soc/soc_caps_full.h +++ b/components/soc/esp32h2/include/soc/soc_caps_full.h @@ -19,3 +19,7 @@ /*--------------------------- Watch Dog ------------------------------------------*/ #define _SOC_CAPS_WDT_MWDTS_PER_TIMG 1 // Number of main watchdog timers in each Timer Group + +/*--------------------------- SDM (Sigma-Delta Modulator) ------------------------*/ +#define _SOC_CAPS_SDM_INST_NUM 1 // Number of SDM instances +#define _SOC_CAPS_SDM_CHANS_PER_INST 4 // Number of channels in each SDM instance diff --git a/components/soc/esp32h2/sdm_periph.c b/components/soc/esp32h2/sdm_periph.c index 6d41dc98f1..b92e215fb5 100644 --- a/components/soc/esp32h2/sdm_periph.c +++ b/components/soc/esp32h2/sdm_periph.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -7,19 +7,22 @@ #include "soc/sdm_periph.h" #include "soc/gpio_sig_map.h" -const sigma_delta_signal_conn_t sigma_delta_periph_signals = { - .channels = { - [0] = { - GPIO_SD0_OUT_IDX - }, - [1] = { - GPIO_SD1_OUT_IDX - }, - [2] = { - GPIO_SD2_OUT_IDX - }, - [3] = { - GPIO_SD3_OUT_IDX +const soc_sdm_signal_desc_t soc_sdm_signals[1] = { + [0] = { + .module_name = "SDM0", + .channels = { + [0] = { + .sig_id_matrix = GPIO_SD0_OUT_IDX + }, + [1] = { + .sig_id_matrix = GPIO_SD1_OUT_IDX + }, + [2] = { + .sig_id_matrix = GPIO_SD2_OUT_IDX + }, + [3] = { + .sig_id_matrix = GPIO_SD3_OUT_IDX + } } } }; diff --git a/components/soc/esp32h21/include/soc/clk_tree_defs.h b/components/soc/esp32h21/include/soc/clk_tree_defs.h index 8718583e19..594bb068d3 100644 --- a/components/soc/esp32h21/include/soc/clk_tree_defs.h +++ b/components/soc/esp32h21/include/soc/clk_tree_defs.h @@ -187,19 +187,6 @@ typedef enum { #endif } soc_periph_gptimer_clk_src_t; -/** - * @brief Type of Timer Group clock source, reserved for the legacy timer group driver - */ -typedef enum { - TIMER_SRC_CLK_PLL_F48M = SOC_MOD_CLK_PLL_F48M, /*!< Timer group clock source is PLL_F48M */ - TIMER_SRC_CLK_XTAL = SOC_MOD_CLK_XTAL, /*!< Timer group clock source is XTAL */ -#if SOC_CLK_TREE_SUPPORTED - TIMER_SRC_CLK_DEFAULT = SOC_MOD_CLK_PLL_F48M, /*!< Select PLL_F48M as the default choice */ -#else - TIMER_SRC_CLK_DEFAULT = SOC_MOD_CLK_XTAL, /*!< Select XTAL as the default choice if no clk_tree */ -#endif -} soc_periph_tg_clk_src_legacy_t; - //////////////////////////////////////////////////RMT/////////////////////////////////////////////////////////////////// /** diff --git a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in index 07b508925f..812dfafa3f 100644 --- a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in @@ -1499,22 +1499,6 @@ config SOC_ECDSA_USES_MPI bool default y -config SOC_SDM_GROUPS - int - default 1 - -config SOC_SDM_CHANNELS_PER_GROUP - int - default 8 - -config SOC_SDM_CLK_SUPPORT_PLL_F80M - bool - default y - -config SOC_SDM_CLK_SUPPORT_XTAL - bool - default y - config SOC_SPI_PERIPH_NUM int default 3 diff --git a/components/soc/esp32p4/include/soc/clk_tree_defs.h b/components/soc/esp32p4/include/soc/clk_tree_defs.h index 165942b874..2ee46af944 100644 --- a/components/soc/esp32p4/include/soc/clk_tree_defs.h +++ b/components/soc/esp32p4/include/soc/clk_tree_defs.h @@ -230,19 +230,6 @@ typedef enum { #endif // SOC_CLK_TREE_SUPPORTED } soc_periph_gptimer_clk_src_t; -/** - * @brief Type of Timer Group clock source, reserved for the legacy timer group driver - */ -typedef enum { - TIMER_SRC_CLK_PLL_F80M = SOC_MOD_CLK_PLL_F80M, /*!< Timer group clock source is PLL_F80M */ - TIMER_SRC_CLK_XTAL = SOC_MOD_CLK_XTAL, /*!< Timer group clock source is XTAL */ -#if SOC_CLK_TREE_SUPPORTED - TIMER_SRC_CLK_DEFAULT = SOC_MOD_CLK_PLL_F80M, /*!< Timer group clock source default choice is PLL_F80M */ -#else - TIMER_SRC_CLK_DEFAULT = SOC_MOD_CLK_XTAL, /*!< Timer group clock source default choice is XTAL */ -#endif // SOC_CLK_TREE_SUPPORTED -} soc_periph_tg_clk_src_legacy_t; - //////////////////////////////////////////////////RMT/////////////////////////////////////////////////////////////////// /** diff --git a/components/soc/esp32p4/include/soc/soc_caps.h b/components/soc/esp32p4/include/soc/soc_caps.h index a49e4ae9d2..e6491e1463 100644 --- a/components/soc/esp32p4/include/soc/soc_caps.h +++ b/components/soc/esp32p4/include/soc/soc_caps.h @@ -555,12 +555,6 @@ #define SOC_ECDSA_SUPPORT_DETERMINISTIC_MODE (1) #define SOC_ECDSA_USES_MPI (1) -/*-------------------------- Sigma Delta Modulator CAPS -----------------*/ -#define SOC_SDM_GROUPS 1U -#define SOC_SDM_CHANNELS_PER_GROUP 8 -#define SOC_SDM_CLK_SUPPORT_PLL_F80M 1 -#define SOC_SDM_CLK_SUPPORT_XTAL 1 - /*-------------------------- SPI CAPS ----------------------------------------*/ #define SOC_SPI_PERIPH_NUM 3 #define SOC_SPI_PERIPH_CS_NUM(i) (((i)==0)? 2: (((i)==1)? 6: 3)) diff --git a/components/soc/esp32p4/include/soc/soc_caps_full.h b/components/soc/esp32p4/include/soc/soc_caps_full.h index c444468053..c1cdc3b38c 100644 --- a/components/soc/esp32p4/include/soc/soc_caps_full.h +++ b/components/soc/esp32p4/include/soc/soc_caps_full.h @@ -19,3 +19,7 @@ /*--------------------------- Watch Dog ------------------------------------------*/ #define _SOC_CAPS_WDT_MWDTS_PER_TIMG 1 // Number of main watchdog timers in each Timer Group + +/*--------------------------- SDM (Sigma-Delta Modulator) ------------------------*/ +#define _SOC_CAPS_SDM_INST_NUM 1 // Number of SDM instances +#define _SOC_CAPS_SDM_CHANS_PER_INST 8 // Number of channels in each SDM instance diff --git a/components/soc/esp32p4/sdm_periph.c b/components/soc/esp32p4/sdm_periph.c index 42e2b60d7c..d013c5a45c 100644 --- a/components/soc/esp32p4/sdm_periph.c +++ b/components/soc/esp32p4/sdm_periph.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -7,31 +7,34 @@ #include "soc/sdm_periph.h" #include "soc/gpio_sig_map.h" -const sigma_delta_signal_conn_t sigma_delta_periph_signals = { - .channels = { - [0] = { - GPIO_SD0_OUT_IDX - }, - [1] = { - GPIO_SD1_OUT_IDX - }, - [2] = { - GPIO_SD2_OUT_IDX - }, - [3] = { - GPIO_SD3_OUT_IDX - }, - [4] = { - GPIO_SD4_OUT_IDX - }, - [5] = { - GPIO_SD5_OUT_IDX - }, - [6] = { - GPIO_SD6_OUT_IDX - }, - [7] = { - GPIO_SD7_OUT_IDX +const soc_sdm_signal_desc_t soc_sdm_signals[1] = { + [0] = { + .module_name = "SDM0", + .channels = { + [0] = { + .sig_id_matrix = GPIO_SD0_OUT_IDX + }, + [1] = { + .sig_id_matrix = GPIO_SD1_OUT_IDX + }, + [2] = { + .sig_id_matrix = GPIO_SD2_OUT_IDX + }, + [3] = { + .sig_id_matrix = GPIO_SD3_OUT_IDX + }, + [4] = { + .sig_id_matrix = GPIO_SD4_OUT_IDX + }, + [5] = { + .sig_id_matrix = GPIO_SD5_OUT_IDX + }, + [6] = { + .sig_id_matrix = GPIO_SD6_OUT_IDX + }, + [7] = { + .sig_id_matrix = GPIO_SD7_OUT_IDX + } } } }; diff --git a/components/soc/esp32s2/include/soc/Kconfig.soc_caps.in b/components/soc/esp32s2/include/soc/Kconfig.soc_caps.in index fdf69ab06d..2ffdc81389 100644 --- a/components/soc/esp32s2/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32s2/include/soc/Kconfig.soc_caps.in @@ -671,18 +671,6 @@ config SOC_LP_IO_CLOCK_IS_INDEPENDENT bool default y -config SOC_SDM_GROUPS - int - default 1 - -config SOC_SDM_CHANNELS_PER_GROUP - int - default 8 - -config SOC_SDM_CLK_SUPPORT_APB - bool - default y - config SOC_SPI_HD_BOTH_INOUT_SUPPORTED bool default y diff --git a/components/soc/esp32s2/include/soc/clk_tree_defs.h b/components/soc/esp32s2/include/soc/clk_tree_defs.h index b8862cecb3..235eb5dfe6 100644 --- a/components/soc/esp32s2/include/soc/clk_tree_defs.h +++ b/components/soc/esp32s2/include/soc/clk_tree_defs.h @@ -174,15 +174,6 @@ typedef enum { GPTIMER_CLK_SRC_DEFAULT = SOC_MOD_CLK_APB, /*!< Select APB as the default choice */ } soc_periph_gptimer_clk_src_t; -/** - * @brief Type of Timer Group clock source, reserved for the legacy timer group driver - */ -typedef enum { - TIMER_SRC_CLK_APB = SOC_MOD_CLK_APB, /*!< Timer group source clock is APB */ - TIMER_SRC_CLK_XTAL = SOC_MOD_CLK_XTAL, /*!< Timer group source clock is XTAL */ - TIMER_SRC_CLK_DEFAULT = SOC_MOD_CLK_APB, /*!< Timer group source clock default choice is APB */ -} soc_periph_tg_clk_src_legacy_t; - //////////////////////////////////////////////////LCD/////////////////////////////////////////////////////////////////// /** diff --git a/components/soc/esp32s2/include/soc/soc_caps.h b/components/soc/esp32s2/include/soc/soc_caps.h index 8ccc41b362..96f16dc61f 100644 --- a/components/soc/esp32s2/include/soc/soc_caps.h +++ b/components/soc/esp32s2/include/soc/soc_caps.h @@ -289,11 +289,6 @@ // LP IO peripherals have independent clock gating to manage #define SOC_LP_IO_CLOCK_IS_INDEPENDENT 1 -/*-------------------------- Sigma Delta Modulator CAPS -----------------*/ -#define SOC_SDM_GROUPS 1U -#define SOC_SDM_CHANNELS_PER_GROUP 8 -#define SOC_SDM_CLK_SUPPORT_APB 1 - /*-------------------------- SPI CAPS ----------------------------------------*/ #define SOC_SPI_HD_BOTH_INOUT_SUPPORTED 1 //Support enabling MOSI and MISO phases together under Halfduplex mode #define SOC_SPI_PERIPH_NUM 3 diff --git a/components/soc/esp32s2/include/soc/soc_caps_full.h b/components/soc/esp32s2/include/soc/soc_caps_full.h index ddee8e204d..acf38bfcb4 100644 --- a/components/soc/esp32s2/include/soc/soc_caps_full.h +++ b/components/soc/esp32s2/include/soc/soc_caps_full.h @@ -19,3 +19,7 @@ /*--------------------------- Watch Dog ------------------------------------------*/ #define _SOC_CAPS_WDT_MWDTS_PER_TIMG 1 // Number of main watchdog timers in each Timer Group + +/*--------------------------- SDM (Sigma-Delta Modulator) ------------------------*/ +#define _SOC_CAPS_SDM_INST_NUM 1 // Number of SDM instances +#define _SOC_CAPS_SDM_CHANS_PER_INST 8 // Number of channels in each SDM instance diff --git a/components/soc/esp32s2/sdm_periph.c b/components/soc/esp32s2/sdm_periph.c index 2445620be9..4107208205 100644 --- a/components/soc/esp32s2/sdm_periph.c +++ b/components/soc/esp32s2/sdm_periph.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2020-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -7,31 +7,34 @@ #include "soc/sdm_periph.h" #include "soc/gpio_sig_map.h" -const sigma_delta_signal_conn_t sigma_delta_periph_signals = { - .channels = { - [0] = { - GPIO_SD0_OUT_IDX - }, - [1] = { - GPIO_SD1_OUT_IDX - }, - [2] = { - GPIO_SD2_OUT_IDX - }, - [3] = { - GPIO_SD3_OUT_IDX - }, - [4] = { - GPIO_SD4_OUT_IDX - }, - [5] = { - GPIO_SD5_OUT_IDX - }, - [6] = { - GPIO_SD6_OUT_IDX - }, - [7] = { - GPIO_SD7_OUT_IDX +const soc_sdm_signal_desc_t soc_sdm_signals[1] = { + [0] = { + .module_name = "SDM0", + .channels = { + [0] = { + .sig_id_matrix = GPIO_SD0_OUT_IDX + }, + [1] = { + .sig_id_matrix = GPIO_SD1_OUT_IDX + }, + [2] = { + .sig_id_matrix = GPIO_SD2_OUT_IDX + }, + [3] = { + .sig_id_matrix = GPIO_SD3_OUT_IDX + }, + [4] = { + .sig_id_matrix = GPIO_SD4_OUT_IDX + }, + [5] = { + .sig_id_matrix = GPIO_SD5_OUT_IDX + }, + [6] = { + .sig_id_matrix = GPIO_SD6_OUT_IDX + }, + [7] = { + .sig_id_matrix = GPIO_SD7_OUT_IDX + } } } }; diff --git a/components/soc/esp32s3/include/soc/Kconfig.soc_caps.in b/components/soc/esp32s3/include/soc/Kconfig.soc_caps.in index 735104e4ff..f5c2981d27 100644 --- a/components/soc/esp32s3/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32s3/include/soc/Kconfig.soc_caps.in @@ -859,18 +859,6 @@ config SOC_LP_IO_CLOCK_IS_INDEPENDENT bool default y -config SOC_SDM_GROUPS - int - default 1 - -config SOC_SDM_CHANNELS_PER_GROUP - int - default 8 - -config SOC_SDM_CLK_SUPPORT_APB - bool - default y - config SOC_SPI_PERIPH_NUM int default 3 diff --git a/components/soc/esp32s3/include/soc/clk_tree_defs.h b/components/soc/esp32s3/include/soc/clk_tree_defs.h index 61cc1c73ba..62a3be165b 100644 --- a/components/soc/esp32s3/include/soc/clk_tree_defs.h +++ b/components/soc/esp32s3/include/soc/clk_tree_defs.h @@ -173,15 +173,6 @@ typedef enum { GPTIMER_CLK_SRC_DEFAULT = SOC_MOD_CLK_APB, /*!< Select APB as the default choice */ } soc_periph_gptimer_clk_src_t; -/** - * @brief Type of Timer Group clock source, reserved for the legacy timer group driver - */ -typedef enum { - TIMER_SRC_CLK_APB = SOC_MOD_CLK_APB, /*!< Timer group source clock is APB */ - TIMER_SRC_CLK_XTAL = SOC_MOD_CLK_XTAL, /*!< Timer group source clock is XTAL */ - TIMER_SRC_CLK_DEFAULT = SOC_MOD_CLK_APB, /*!< Timer group source clock default choice is APB */ -} soc_periph_tg_clk_src_legacy_t; - //////////////////////////////////////////////////LCD/////////////////////////////////////////////////////////////////// /** diff --git a/components/soc/esp32s3/include/soc/soc_caps.h b/components/soc/esp32s3/include/soc/soc_caps.h index b455d19e3f..6d1c808ff0 100644 --- a/components/soc/esp32s3/include/soc/soc_caps.h +++ b/components/soc/esp32s3/include/soc/soc_caps.h @@ -341,11 +341,6 @@ // LP IO peripherals have independent clock gating to manage #define SOC_LP_IO_CLOCK_IS_INDEPENDENT 1 -/*-------------------------- Sigma Delta Modulator CAPS -----------------*/ -#define SOC_SDM_GROUPS (1U) -#define SOC_SDM_CHANNELS_PER_GROUP 8 -#define SOC_SDM_CLK_SUPPORT_APB 1 - /*-------------------------- SPI CAPS ----------------------------------------*/ #define SOC_SPI_PERIPH_NUM 3 #define SOC_SPI_PERIPH_CS_NUM(i) (((i)==0)? 2: (((i)==1)? 6: 3)) diff --git a/components/soc/esp32s3/include/soc/soc_caps_full.h b/components/soc/esp32s3/include/soc/soc_caps_full.h index c444468053..c1cdc3b38c 100644 --- a/components/soc/esp32s3/include/soc/soc_caps_full.h +++ b/components/soc/esp32s3/include/soc/soc_caps_full.h @@ -19,3 +19,7 @@ /*--------------------------- Watch Dog ------------------------------------------*/ #define _SOC_CAPS_WDT_MWDTS_PER_TIMG 1 // Number of main watchdog timers in each Timer Group + +/*--------------------------- SDM (Sigma-Delta Modulator) ------------------------*/ +#define _SOC_CAPS_SDM_INST_NUM 1 // Number of SDM instances +#define _SOC_CAPS_SDM_CHANS_PER_INST 8 // Number of channels in each SDM instance diff --git a/components/soc/esp32s3/sdm_periph.c b/components/soc/esp32s3/sdm_periph.c index 2445620be9..4107208205 100644 --- a/components/soc/esp32s3/sdm_periph.c +++ b/components/soc/esp32s3/sdm_periph.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2020-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -7,31 +7,34 @@ #include "soc/sdm_periph.h" #include "soc/gpio_sig_map.h" -const sigma_delta_signal_conn_t sigma_delta_periph_signals = { - .channels = { - [0] = { - GPIO_SD0_OUT_IDX - }, - [1] = { - GPIO_SD1_OUT_IDX - }, - [2] = { - GPIO_SD2_OUT_IDX - }, - [3] = { - GPIO_SD3_OUT_IDX - }, - [4] = { - GPIO_SD4_OUT_IDX - }, - [5] = { - GPIO_SD5_OUT_IDX - }, - [6] = { - GPIO_SD6_OUT_IDX - }, - [7] = { - GPIO_SD7_OUT_IDX +const soc_sdm_signal_desc_t soc_sdm_signals[1] = { + [0] = { + .module_name = "SDM0", + .channels = { + [0] = { + .sig_id_matrix = GPIO_SD0_OUT_IDX + }, + [1] = { + .sig_id_matrix = GPIO_SD1_OUT_IDX + }, + [2] = { + .sig_id_matrix = GPIO_SD2_OUT_IDX + }, + [3] = { + .sig_id_matrix = GPIO_SD3_OUT_IDX + }, + [4] = { + .sig_id_matrix = GPIO_SD4_OUT_IDX + }, + [5] = { + .sig_id_matrix = GPIO_SD5_OUT_IDX + }, + [6] = { + .sig_id_matrix = GPIO_SD6_OUT_IDX + }, + [7] = { + .sig_id_matrix = GPIO_SD7_OUT_IDX + } } } }; diff --git a/components/soc/include/soc/sdm_periph.h b/components/soc/include/soc/sdm_periph.h index 2e9cd75efe..c304196fd1 100644 --- a/components/soc/include/soc/sdm_periph.h +++ b/components/soc/include/soc/sdm_periph.h @@ -1,28 +1,36 @@ /* - * SPDX-FileCopyrightText: 2019-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2019-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ #pragma once -#include "soc/soc_caps.h" +#include +#include +#include "soc/soc_caps_full.h" +#include "soc/periph_defs.h" +#include "soc/regdma.h" + +#if SOC_HAS(PAU) +#include "soc/retention_periph_defs.h" +#endif // SOC_HAS(PAU) + +// helper macros to access module attributes +#define SOC_SDM_ATTR(_attr) SOC_MODULE_ATTR(SDM, _attr) #ifdef __cplusplus extern "C" { #endif -#if SOC_SDM_SUPPORTED - typedef struct { + const char *module_name; // Module name struct { - const int sd_sig; - } channels[SOC_SDM_CHANNELS_PER_GROUP]; -} sigma_delta_signal_conn_t; + const int sig_id_matrix; // signal ID in the GPIO matrix + } channels[SOC_SDM_ATTR(CHANS_PER_INST)]; +} soc_sdm_signal_desc_t; -extern const sigma_delta_signal_conn_t sigma_delta_periph_signals; - -#endif // SOC_SDM_SUPPORTED +extern const soc_sdm_signal_desc_t soc_sdm_signals[SOC_SDM_ATTR(INST_NUM)]; #ifdef __cplusplus } diff --git a/docs/en/api-reference/peripherals/sdm.rst b/docs/en/api-reference/peripherals/sdm.rst index 32dc851fe6..8f2d8beb7b 100644 --- a/docs/en/api-reference/peripherals/sdm.rst +++ b/docs/en/api-reference/peripherals/sdm.rst @@ -102,13 +102,13 @@ There is a Kconfig option :ref:`CONFIG_SDM_CTRL_FUNC_IN_IRAM` that can put commo Thread Safety ^^^^^^^^^^^^^ -The factory function :cpp:func:`sdm_new_channel` is guaranteed to be thread-safe by the driver, which means, the user can call it from different RTOS tasks without protection by extra locks. +The driver uses critical sections to ensure atomic operations on registers. Key members in the driver handle are also protected by critical sections. The driver's internal state machine uses atomic instructions to ensure thread safety, with state checks preventing certain invalid concurrent operations (e.g., conflicts between `enable` and `delete`). Therefore, SDM driver APIs can be used in a multi-threaded environment without extra locking. -The following functions are allowed to run under ISR context, the driver uses a critical section to prevent them being called concurrently in both task and ISR. +The following functions can also be used in an interrupt context: -- :cpp:func:`sdm_channel_set_pulse_density` +.. list:: -Other functions that take the :cpp:type:`sdm_channel_handle_t` as the first positional parameter, are not treated as thread-safe. This means the user should avoid calling them from multiple tasks. + - :cpp:func:`sdm_channel_set_pulse_density` .. _sdm-kconfig-options: diff --git a/docs/zh_CN/api-reference/peripherals/sdm.rst b/docs/zh_CN/api-reference/peripherals/sdm.rst index 5230e67e1a..f140db8cef 100644 --- a/docs/zh_CN/api-reference/peripherals/sdm.rst +++ b/docs/zh_CN/api-reference/peripherals/sdm.rst @@ -102,13 +102,13 @@ Kconfig 选项 :ref:`CONFIG_SDM_CTRL_FUNC_IN_IRAM` 支持将常用的 IO 控制 线程安全 ^^^^^^^^ -驱动程序会确保工厂函数 :cpp:func:`sdm_new_channel` 的线程安全,使用时,可以直接从不同的 RTOS 任务中调用此类函数,无需额外锁保护。 +驱动使用了临界区保证了对寄存器的原子操作。句柄内部的关键成员也受临界区保护。驱动内部的状态机使用了原子指令保证了线程安全,通过状态检查还能进一步防止一些不合法的并发操作(例如 `enable` 和 `delete` 冲突)。因此, SDM 驱动的 API 可以在多线程环境下使用,无需自行加锁。 -驱动程序设置了临界区,以防函数同时在任务和 ISR 中调用。因此,以下函数支持在 ISR 上下文运行: +同时,以下这些函数还允许在中断上下文中使用: -- :cpp:func:`sdm_channel_set_pulse_density` +.. list:: -其他以 :cpp:type:`sdm_channel_handle_t` 作为第一个位置参数的函数均非线程安全,因此应避免从多个任务中调用这类函数。 + - :cpp:func:`sdm_channel_set_pulse_density` .. _sdm-kconfig-options: From f808fb9eafe20d90841f8fb5ec9fba6309ebd975 Mon Sep 17 00:00:00 2001 From: morris Date: Thu, 7 Aug 2025 16:44:52 +0800 Subject: [PATCH 2/3] feat(sdm): add sleep retention support --- .../esp_driver_sdm/include/driver/sdm.h | 2 + components/esp_driver_sdm/src/sdm.c | 66 +++++++++++++ .../test_apps/sigma_delta/main/CMakeLists.txt | 6 +- .../test_apps/sigma_delta/main/test_sdm.cpp | 2 + .../sigma_delta/main/test_sdm_sleep.cpp | 92 +++++++++++++++++++ .../sigma_delta/sdkconfig.ci.release | 2 + .../test_apps/sigma_delta/sdkconfig.defaults | 3 + .../esp_hw_support/sleep_system_peripheral.c | 4 + components/hal/esp32p4/include/hal/pmu_ll.h | 4 +- .../esp32c5/include/soc/Kconfig.soc_caps.in | 4 + .../include/soc/retention_periph_defs.h | 2 + components/soc/esp32c5/include/soc/soc_caps.h | 2 + components/soc/esp32c5/sdm_periph.c | 30 ++++++ .../esp32c6/include/soc/Kconfig.soc_caps.in | 4 + .../include/soc/retention_periph_defs.h | 2 + components/soc/esp32c6/include/soc/soc_caps.h | 2 + components/soc/esp32c6/sdm_periph.c | 30 ++++++ .../esp32h2/include/soc/Kconfig.soc_caps.in | 4 + .../include/soc/retention_periph_defs.h | 2 + components/soc/esp32h2/include/soc/soc_caps.h | 2 + components/soc/esp32h2/sdm_periph.c | 30 ++++++ .../esp32p4/include/soc/Kconfig.soc_caps.in | 4 + .../include/soc/retention_periph_defs.h | 2 + components/soc/esp32p4/include/soc/soc_caps.h | 2 + components/soc/esp32p4/sdm_periph.c | 30 ++++++ components/soc/include/soc/regdma.h | 2 + components/soc/include/soc/sdm_periph.h | 16 ++++ 27 files changed, 346 insertions(+), 5 deletions(-) create mode 100644 components/esp_driver_sdm/test_apps/sigma_delta/main/test_sdm_sleep.cpp diff --git a/components/esp_driver_sdm/include/driver/sdm.h b/components/esp_driver_sdm/include/driver/sdm.h index b4f66b578f..55849e2635 100644 --- a/components/esp_driver_sdm/include/driver/sdm.h +++ b/components/esp_driver_sdm/include/driver/sdm.h @@ -29,6 +29,8 @@ typedef struct { uint32_t sample_rate_hz; /*!< Over sample rate in Hz, it determines the frequency of the carrier pulses */ struct { uint32_t invert_out: 1; /*!< Whether to invert the output signal */ + uint32_t allow_pd: 1; /*!< If set, driver allows the power domain to be powered off when system enters sleep mode. + This can save power, but at the expense of more RAM being consumed to save register context. */ } flags; /*!< Extra flags */ } sdm_config_t; diff --git a/components/esp_driver_sdm/src/sdm.c b/components/esp_driver_sdm/src/sdm.c index e4ce80a0ef..4ea47994aa 100644 --- a/components/esp_driver_sdm/src/sdm.c +++ b/components/esp_driver_sdm/src/sdm.c @@ -39,6 +39,8 @@ #define SDM_MEM_ALLOC_CAPS MALLOC_CAP_DEFAULT #endif +#define SDM_USE_RETENTION_LINK (SOC_SDM_SUPPORT_SLEEP_RETENTION && CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP) + ///!< Logging settings #define TAG "sdm" @@ -81,6 +83,31 @@ struct sdm_channel_t { // sdm driver platform, it's always a singleton static sdm_platform_t s_platform; +#if SDM_USE_RETENTION_LINK +static esp_err_t sdm_create_sleep_retention_link_cb(void *group) +{ + int group_id = ((sdm_group_t *)group)->group_id; + esp_err_t err = sleep_retention_entries_create(soc_sdm_retention_infos[group_id].regdma_entry_array, + soc_sdm_retention_infos[group_id].array_size, + REGDMA_LINK_PRI_SDM, soc_sdm_retention_infos[group_id].module); + return err; +} + +static void sdm_create_retention_module(sdm_group_t *group) +{ + int group_id = group->group_id; + sleep_retention_module_t module = soc_sdm_retention_infos[group_id].module; + _lock_acquire(&s_platform.mutex); + if (sleep_retention_is_module_inited(module) && !sleep_retention_is_module_created(module)) { + if (sleep_retention_module_allocate(module) != ESP_OK) { + // even though the sleep retention module create failed, SDM driver should still work, so just warning here + ESP_LOGW(TAG, "create retention link failed on SDM Group%d, power domain won't be turned off during sleep", group_id); + } + } + _lock_release(&s_platform.mutex); +} +#endif // SDM_USE_RETENTION_LINK + static sdm_group_t *sdm_acquire_group_handle(int group_id, sdm_clock_source_t clk_src) { bool new_group = false; @@ -97,6 +124,25 @@ static sdm_group_t *sdm_acquire_group_handle(int group_id, sdm_clock_source_t cl group->group_id = group_id; group->spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED; group->clk_src = clk_src; + +#if SDM_USE_RETENTION_LINK + sleep_retention_module_t module = soc_sdm_retention_infos[group->group_id].module; + sleep_retention_module_init_param_t init_param = { + .cbs = { + .create = { + .handle = sdm_create_sleep_retention_link_cb, + .arg = group, + }, + }, + .depends = RETENTION_MODULE_BITMAP_INIT(CLOCK_SYSTEM) + }; + // retention module init must be called BEFORE the hal init + if (sleep_retention_module_init(module, &init_param) != ESP_OK) { + ESP_LOGW(TAG, "init sleep retention failed on SDM Group%d, power domain may be turned off during sleep", group->group_id); + } +#endif // SDM_USE_RETENTION_LINK + + // [IDF-12975]: enable APB register clock explicitly // initialize HAL context sdm_hal_init_config_t hal_config = { .group_id = group_id, @@ -142,6 +188,16 @@ static void sdm_release_group_handle(sdm_group_t *group) do_deinitialize = true; s_platform.groups[group_id] = NULL; // deregister from platform sdm_hal_deinit(&group->hal); + +#if SDM_USE_RETENTION_LINK + sleep_retention_module_t module = soc_sdm_retention_infos[group_id].module; + if (sleep_retention_is_module_created(module)) { + sleep_retention_module_free(module); + } + if (sleep_retention_is_module_inited(module)) { + sleep_retention_module_deinit(module); + } +#endif // SDM_USE_RETENTION_LINK } _lock_release(&s_platform.mutex); @@ -216,6 +272,10 @@ esp_err_t sdm_new_channel(const sdm_config_t *config, sdm_channel_handle_t *ret_ ESP_RETURN_ON_FALSE(config && ret_chan, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); ESP_RETURN_ON_FALSE(GPIO_IS_VALID_OUTPUT_GPIO(config->gpio_num), ESP_ERR_INVALID_ARG, TAG, "invalid GPIO number"); + [[maybe_unused]] bool allow_pd = config->flags.allow_pd == 1; +#if !SOC_SDM_SUPPORT_SLEEP_RETENTION + ESP_RETURN_ON_FALSE(allow_pd == false, ESP_ERR_NOT_SUPPORTED, TAG, "not able to power down in light sleep"); +#endif // SOC_SDM_SUPPORT_SLEEP_RETENTION // allocate channel memory from internal memory because it contains atomic variable chan = heap_caps_calloc(1, sizeof(sdm_channel_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); @@ -271,6 +331,12 @@ esp_err_t sdm_new_channel(const sdm_config_t *config, sdm_channel_handle_t *ret_ chan->spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED; atomic_init(&chan->fsm, SDM_FSM_INIT); // set the initial state to INIT +#if SDM_USE_RETENTION_LINK + if (allow_pd) { + sdm_create_retention_module(group); + } +#endif // SDM_USE_RETENTION_LINK + ESP_LOGD(TAG, "new sdm channel (%d,%d) at %p, gpio=%d, sample rate=%"PRIu32"Hz", group_id, chan_id, chan, chan->gpio_num, chan->sample_rate_hz); *ret_chan = chan; return ESP_OK; diff --git a/components/esp_driver_sdm/test_apps/sigma_delta/main/CMakeLists.txt b/components/esp_driver_sdm/test_apps/sigma_delta/main/CMakeLists.txt index b416b209f1..4c644fce2d 100644 --- a/components/esp_driver_sdm/test_apps/sigma_delta/main/CMakeLists.txt +++ b/components/esp_driver_sdm/test_apps/sigma_delta/main/CMakeLists.txt @@ -1,7 +1,7 @@ -set(srcs "test_app_main.c") +set(srcs "test_app_main.c" "test_sdm.cpp") -if(CONFIG_SOC_SDM_SUPPORTED) - list(APPEND srcs "test_sdm.cpp") +if(CONFIG_SOC_LIGHT_SLEEP_SUPPORTED AND CONFIG_PM_ENABLE) + list(APPEND srcs "test_sdm_sleep.cpp") endif() # In order for the cases defined by `TEST_CASE` to be linked into the final elf, diff --git a/components/esp_driver_sdm/test_apps/sigma_delta/main/test_sdm.cpp b/components/esp_driver_sdm/test_apps/sigma_delta/main/test_sdm.cpp index 75f4626e9d..c10468a61e 100644 --- a/components/esp_driver_sdm/test_apps/sigma_delta/main/test_sdm.cpp +++ b/components/esp_driver_sdm/test_apps/sigma_delta/main/test_sdm.cpp @@ -22,6 +22,7 @@ TEST_CASE("sdm_channel_install_uninstall", "[sdm]") .sample_rate_hz = 1000000, .flags = { .invert_out = false, + .allow_pd = false, }, }; sdm_channel_handle_t chans[SOC_SDM_ATTR(INST_NUM)][SOC_SDM_ATTR(CHANS_PER_INST)] = {}; @@ -49,6 +50,7 @@ TEST_CASE("sdm_channel_set_pulse_density", "[sdm]") .sample_rate_hz = 1000000, .flags = { .invert_out = false, + .allow_pd = false, }, }; sdm_channel_handle_t chans[2] = {}; diff --git a/components/esp_driver_sdm/test_apps/sigma_delta/main/test_sdm_sleep.cpp b/components/esp_driver_sdm/test_apps/sigma_delta/main/test_sdm_sleep.cpp new file mode 100644 index 0000000000..e08b6e5549 --- /dev/null +++ b/components/esp_driver_sdm/test_apps/sigma_delta/main/test_sdm_sleep.cpp @@ -0,0 +1,92 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "sdkconfig.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "unity.h" +#include "driver/sdm.h" +#include "soc/soc_caps.h" +#include "esp_sleep.h" +#include "esp_private/sleep_cpu.h" +#include "esp_private/esp_sleep_internal.h" +#include "esp_private/esp_pmu.h" + +/** + * @brief Test the SDM driver can still work after light sleep + * + * @param allow_pd Whether to allow power down the peripheral in light sleep + */ +static void test_sdm_sleep_retention(bool allow_pd) +{ + const gpio_num_t sdm_chan_gpios[2] = {GPIO_NUM_0, GPIO_NUM_2}; + sdm_config_t sdm_config = { + .gpio_num = GPIO_NUM_NC, // will be set later + .clk_src = SDM_CLK_SRC_DEFAULT, + .sample_rate_hz = 1000000, + .flags = { + .invert_out = false, + .allow_pd = allow_pd, + }, + }; + sdm_channel_handle_t chans[2] = {0}; + for (int i = 0; i < 2; i++) { + sdm_config.gpio_num = sdm_chan_gpios[i]; + TEST_ESP_OK(sdm_new_channel(&sdm_config, &chans[i])); + // should see a ~250KHz (sample_rate/4) square wave + TEST_ESP_OK(sdm_channel_set_pulse_density(chans[i], 0)); + TEST_ESP_OK(sdm_channel_enable(chans[i])); + } + vTaskDelay(pdMS_TO_TICKS(500)); + + // Note: disable the sdm before going to sleep, ensure no power management lock is acquired by it + for (int i = 0; i < 2; i++) { + TEST_ESP_OK(sdm_channel_disable(chans[i])); + } + + esp_sleep_context_t sleep_ctx; + esp_sleep_set_sleep_context(&sleep_ctx); + printf("go to light sleep for 2 seconds\r\n"); +#if ESP_SLEEP_POWER_DOWN_CPU + TEST_ESP_OK(sleep_cpu_configure(true)); +#endif + TEST_ESP_OK(esp_sleep_enable_timer_wakeup(2 * 1000 * 1000)); + TEST_ESP_OK(esp_light_sleep_start()); + + printf("Waked up! Let's see if SDM driver can still work...\r\n"); +#if ESP_SLEEP_POWER_DOWN_CPU + TEST_ESP_OK(sleep_cpu_configure(false)); +#endif + + printf("check if the sleep happened as expected\r\n"); + TEST_ASSERT_EQUAL(0, sleep_ctx.sleep_request_result); +#if SOC_SDM_SUPPORT_SLEEP_RETENTION && !SOC_PM_TOP_PD_NOT_ALLOWED + // check if the power domain also is powered down + TEST_ASSERT_EQUAL(allow_pd ? PMU_SLEEP_PD_TOP : 0, (sleep_ctx.sleep_flags) & PMU_SLEEP_PD_TOP); +#endif + esp_sleep_set_sleep_context(NULL); + + // re-enable the SDM channel + for (int i = 0; i < 2; i++) { + TEST_ESP_OK(sdm_channel_enable(chans[i])); + } + // should see a ~250KHz (sample_rate/4) square wave again + vTaskDelay(pdMS_TO_TICKS(500)); + + for (int i = 0; i < 2; i++) { + TEST_ESP_OK(sdm_channel_disable(chans[i])); + TEST_ESP_OK(sdm_del_channel(chans[i])); + } +} + +TEST_CASE("sdm can work after light sleep", "[sdm]") +{ + test_sdm_sleep_retention(false); +#if SOC_SDM_SUPPORT_SLEEP_RETENTION + test_sdm_sleep_retention(true); +#endif +} diff --git a/components/esp_driver_sdm/test_apps/sigma_delta/sdkconfig.ci.release b/components/esp_driver_sdm/test_apps/sigma_delta/sdkconfig.ci.release index 91d93f163e..1a87ebbb4a 100644 --- a/components/esp_driver_sdm/test_apps/sigma_delta/sdkconfig.ci.release +++ b/components/esp_driver_sdm/test_apps/sigma_delta/sdkconfig.ci.release @@ -1,5 +1,7 @@ CONFIG_PM_ENABLE=y CONFIG_FREERTOS_USE_TICKLESS_IDLE=y +CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP=y +CONFIG_PM_DFS_INIT_AUTO=y CONFIG_COMPILER_OPTIMIZATION_SIZE=y CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y diff --git a/components/esp_driver_sdm/test_apps/sigma_delta/sdkconfig.defaults b/components/esp_driver_sdm/test_apps/sigma_delta/sdkconfig.defaults index fa8ac618b9..488ad46859 100644 --- a/components/esp_driver_sdm/test_apps/sigma_delta/sdkconfig.defaults +++ b/components/esp_driver_sdm/test_apps/sigma_delta/sdkconfig.defaults @@ -1,2 +1,5 @@ CONFIG_FREERTOS_HZ=1000 CONFIG_ESP_TASK_WDT_EN=n + +# primitives for checking sleep internal state +CONFIG_ESP_SLEEP_DEBUG=y diff --git a/components/esp_hw_support/sleep_system_peripheral.c b/components/esp_hw_support/sleep_system_peripheral.c index 9c1a62a48b..91020a5e98 100644 --- a/components/esp_hw_support/sleep_system_peripheral.c +++ b/components/esp_hw_support/sleep_system_peripheral.c @@ -291,6 +291,10 @@ bool peripheral_domain_pd_allowed(void) mask.bitmap[SLEEP_RETENTION_MODULE_MCPWM0 >> 5] |= BIT(SLEEP_RETENTION_MODULE_MCPWM0 % 32); #endif +#if SOC_SDM_SUPPORT_SLEEP_RETENTION + mask.bitmap[SLEEP_RETENTION_MODULE_SDM0 >> 5] |= BIT(SLEEP_RETENTION_MODULE_SDM0 % 32); +#endif + const sleep_retention_module_bitmap_t peripheral_domain_inited_modules = sleep_retention_module_bitmap_and(inited_modules, mask); const sleep_retention_module_bitmap_t peripheral_domain_created_modules = sleep_retention_module_bitmap_and(created_modules, mask); return sleep_retention_module_bitmap_eq(peripheral_domain_inited_modules, peripheral_domain_created_modules); diff --git a/components/hal/esp32p4/include/hal/pmu_ll.h b/components/hal/esp32p4/include/hal/pmu_ll.h index 599dcbb79a..eefa07ea57 100644 --- a/components/hal/esp32p4/include/hal/pmu_ll.h +++ b/components/hal/esp32p4/include/hal/pmu_ll.h @@ -638,9 +638,9 @@ FORCE_INLINE_ATTR uint32_t pmu_ll_hp_get_analog_wait_target_cycle(pmu_dev_t *hw) return HAL_FORCE_READ_U32_REG_FIELD(hw->wakeup.cntl7, ana_wait_target); } -FORCE_INLINE_ATTR uint32_t pmu_ll_hp_set_lite_wakeup_enable(pmu_dev_t *hw, bool wakeup_en) +FORCE_INLINE_ATTR void pmu_ll_hp_set_lite_wakeup_enable(pmu_dev_t *hw, bool wakeup_en) { - return hw->wakeup.cntl8.lp_lite_wakeup_ena = wakeup_en; + hw->wakeup.cntl8.lp_lite_wakeup_ena = wakeup_en; } FORCE_INLINE_ATTR void pmu_ll_hp_set_digital_power_supply_wait_cycle(pmu_dev_t *hw, uint32_t cycle) diff --git a/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in index 7440849224..ad32bd89e7 100644 --- a/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in @@ -647,6 +647,10 @@ config SOC_DEDIC_PERIPH_ALWAYS_ENABLE bool default y +config SOC_SDM_SUPPORT_SLEEP_RETENTION + bool + default y + config SOC_ANA_CMPR_NUM int default 1 diff --git a/components/soc/esp32c5/include/soc/retention_periph_defs.h b/components/soc/esp32c5/include/soc/retention_periph_defs.h index a9cda6140e..9ceee5a2b9 100644 --- a/components/soc/esp32c5/include/soc/retention_periph_defs.h +++ b/components/soc/esp32c5/include/soc/retention_periph_defs.h @@ -44,6 +44,7 @@ typedef enum periph_retention_module { SLEEP_RETENTION_MODULE_GPSPI2 = 20, SLEEP_RETENTION_MODULE_LEDC = 21, SLEEP_RETENTION_MODULE_MCPWM0 = 22, + SLEEP_RETENTION_MODULE_SDM0 = 23, /* modem module, which includes WiFi, BLE and 802.15.4 */ SLEEP_RETENTION_MODULE_WIFI_MAC = 26, @@ -80,6 +81,7 @@ typedef enum periph_retention_module { : ((m) == SLEEP_RETENTION_MODULE_GPSPI2) ? true \ : ((m) == SLEEP_RETENTION_MODULE_LEDC) ? true \ : ((m) == SLEEP_RETENTION_MODULE_MCPWM0) ? true \ + : ((m) == SLEEP_RETENTION_MODULE_SDM0) ? true \ : false) #ifdef __cplusplus diff --git a/components/soc/esp32c5/include/soc/soc_caps.h b/components/soc/esp32c5/include/soc/soc_caps.h index 34b3944b87..1cacb6a7bf 100644 --- a/components/soc/esp32c5/include/soc/soc_caps.h +++ b/components/soc/esp32c5/include/soc/soc_caps.h @@ -267,6 +267,8 @@ #define SOC_DEDIC_GPIO_IN_CHANNELS_NUM (8) /*!< 8 inward channels on each CPU core */ #define SOC_DEDIC_PERIPH_ALWAYS_ENABLE (1) /*!< The dedicated GPIO (a.k.a. fast GPIO) is featured by some customized CPU instructions, which is always enabled */ +#define SOC_SDM_SUPPORT_SLEEP_RETENTION 1 + /*------------------------- Analog Comparator CAPS ---------------------------*/ #define SOC_ANA_CMPR_NUM (1U) #define SOC_ANA_CMPR_CAN_DISTINGUISH_EDGE (1) // Support positive/negative/any cross interrupt diff --git a/components/soc/esp32c5/sdm_periph.c b/components/soc/esp32c5/sdm_periph.c index b92e215fb5..ef1b0c1ded 100644 --- a/components/soc/esp32c5/sdm_periph.c +++ b/components/soc/esp32c5/sdm_periph.c @@ -6,6 +6,7 @@ #include "soc/sdm_periph.h" #include "soc/gpio_sig_map.h" +#include "soc/gpio_ext_reg.h" const soc_sdm_signal_desc_t soc_sdm_signals[1] = { [0] = { @@ -26,3 +27,32 @@ const soc_sdm_signal_desc_t soc_sdm_signals[1] = { } } }; + +/** + * @brief Registers in retention context: + * GPIO_EXT_SIGMADELTA[x]_REG + * GPIO_EXT_SIGMADELTA_MISC_REG + */ +#define GPIO_EXT_RETENTION_REGS_CNT 5 +#define GPIO_EXT_RETENTION_REGS_BASE (DR_REG_GPIO_EXT_BASE + 0x4) +static const uint32_t gpio_ext_regs_map[4] = {0x1f, 0x0, 0x0, 0x0}; +static const regdma_entries_config_t gpio_ext_regdma_entries[] = { + // backup stage: save configuration and status registers + // restore stage: restore the configuration and status registers + [0] = { + .config = REGDMA_LINK_ADDR_MAP_INIT(REGDMA_SDM_LINK(0x00), + GPIO_EXT_RETENTION_REGS_BASE, GPIO_EXT_RETENTION_REGS_BASE, + GPIO_EXT_RETENTION_REGS_CNT, 0, 0, + gpio_ext_regs_map[0], gpio_ext_regs_map[1], + gpio_ext_regs_map[2], gpio_ext_regs_map[3]), + .owner = ENTRY(0) | ENTRY(2), + }, +}; + +const soc_sdm_retention_desc_t soc_sdm_retention_infos[1] = { + [0] = { + .module = SLEEP_RETENTION_MODULE_SDM0, + .regdma_entry_array = gpio_ext_regdma_entries, + .array_size = ARRAY_SIZE(gpio_ext_regdma_entries) + } +}; diff --git a/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in index eb3ba8d31a..d263d930de 100644 --- a/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in @@ -579,6 +579,10 @@ config SOC_DEDIC_PERIPH_ALWAYS_ENABLE bool default y +config SOC_SDM_SUPPORT_SLEEP_RETENTION + bool + default y + config SOC_I2C_NUM int default 2 diff --git a/components/soc/esp32c6/include/soc/retention_periph_defs.h b/components/soc/esp32c6/include/soc/retention_periph_defs.h index d944f62397..ee48a60b13 100644 --- a/components/soc/esp32c6/include/soc/retention_periph_defs.h +++ b/components/soc/esp32c6/include/soc/retention_periph_defs.h @@ -46,6 +46,7 @@ typedef enum periph_retention_module { SLEEP_RETENTION_MODULE_GPSPI2 = 22, SLEEP_RETENTION_MODULE_LEDC = 23, SLEEP_RETENTION_MODULE_MCPWM0 = 24, + SLEEP_RETENTION_MODULE_SDM0 = 25, /* Modem module, which includes WiFi, BLE and 802.15.4 */ SLEEP_RETENTION_MODULE_WIFI_MAC = 26, @@ -82,6 +83,7 @@ typedef enum periph_retention_module { : ((m) == SLEEP_RETENTION_MODULE_GPSPI2) ? true \ : ((m) == SLEEP_RETENTION_MODULE_LEDC) ? true \ : ((m) == SLEEP_RETENTION_MODULE_MCPWM0) ? true \ + : ((m) == SLEEP_RETENTION_MODULE_SDM0) ? true \ : false) #ifdef __cplusplus diff --git a/components/soc/esp32c6/include/soc/soc_caps.h b/components/soc/esp32c6/include/soc/soc_caps.h index 46580ed16e..7e6d5ac37d 100644 --- a/components/soc/esp32c6/include/soc/soc_caps.h +++ b/components/soc/esp32c6/include/soc/soc_caps.h @@ -245,6 +245,8 @@ #define SOC_DEDIC_GPIO_IN_CHANNELS_NUM (8) /*!< 8 inward channels on each CPU core */ #define SOC_DEDIC_PERIPH_ALWAYS_ENABLE (1) /*!< The dedicated GPIO (a.k.a. fast GPIO) is featured by some customized CPU instructions, which is always enabled */ +#define SOC_SDM_SUPPORT_SLEEP_RETENTION 1 + /*-------------------------- I2C CAPS ----------------------------------------*/ // ESP32-C6 has 1 I2C #define SOC_I2C_NUM (2U) // I2C_NUM = HP_I2C + LP_I2C diff --git a/components/soc/esp32c6/sdm_periph.c b/components/soc/esp32c6/sdm_periph.c index b92e215fb5..c4c4319411 100644 --- a/components/soc/esp32c6/sdm_periph.c +++ b/components/soc/esp32c6/sdm_periph.c @@ -6,6 +6,7 @@ #include "soc/sdm_periph.h" #include "soc/gpio_sig_map.h" +#include "soc/gpio_ext_reg.h" const soc_sdm_signal_desc_t soc_sdm_signals[1] = { [0] = { @@ -26,3 +27,32 @@ const soc_sdm_signal_desc_t soc_sdm_signals[1] = { } } }; + +/** + * @brief Registers in retention context: + * GPIO_EXT_SIGMADELTA[x]_REG + * GPIO_EXT_SIGMADELTA_MISC_REG + */ +#define GPIO_EXT_RETENTION_REGS_CNT 5 +#define GPIO_EXT_RETENTION_REGS_BASE (DR_REG_GPIO_EXT_BASE + 0x0) +static const uint32_t gpio_ext_regs_map[4] = {0x20f, 0x0, 0x0, 0x0}; +static const regdma_entries_config_t gpio_ext_regdma_entries[] = { + // backup stage: save configuration and status registers + // restore stage: restore the configuration and status registers + [0] = { + .config = REGDMA_LINK_ADDR_MAP_INIT(REGDMA_SDM_LINK(0x00), + GPIO_EXT_RETENTION_REGS_BASE, GPIO_EXT_RETENTION_REGS_BASE, + GPIO_EXT_RETENTION_REGS_CNT, 0, 0, + gpio_ext_regs_map[0], gpio_ext_regs_map[1], + gpio_ext_regs_map[2], gpio_ext_regs_map[3]), + .owner = ENTRY(0) | ENTRY(2), + }, +}; + +const soc_sdm_retention_desc_t soc_sdm_retention_infos[1] = { + [0] = { + .module = SLEEP_RETENTION_MODULE_SDM0, + .regdma_entry_array = gpio_ext_regdma_entries, + .array_size = ARRAY_SIZE(gpio_ext_regdma_entries) + } +}; diff --git a/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in b/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in index dc57925b10..2824306da9 100644 --- a/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in @@ -583,6 +583,10 @@ config SOC_DEDIC_PERIPH_ALWAYS_ENABLE bool default y +config SOC_SDM_SUPPORT_SLEEP_RETENTION + bool + default y + config SOC_ANA_CMPR_NUM int default 1 diff --git a/components/soc/esp32h2/include/soc/retention_periph_defs.h b/components/soc/esp32h2/include/soc/retention_periph_defs.h index e4ef9608dd..b4585071ca 100644 --- a/components/soc/esp32h2/include/soc/retention_periph_defs.h +++ b/components/soc/esp32h2/include/soc/retention_periph_defs.h @@ -46,6 +46,7 @@ typedef enum periph_retention_module { SLEEP_RETENTION_MODULE_GPSPI2 = 22, SLEEP_RETENTION_MODULE_LEDC = 23, SLEEP_RETENTION_MODULE_MCPWM0 = 24, + SLEEP_RETENTION_MODULE_SDM0 = 25, /* Modem module, which includes BLE and 802.15.4 */ SLEEP_RETENTION_MODULE_BLE_MAC = 28, @@ -80,6 +81,7 @@ typedef enum periph_retention_module { : ((m) == SLEEP_RETENTION_MODULE_GPSPI2) ? true \ : ((m) == SLEEP_RETENTION_MODULE_LEDC) ? true \ : ((m) == SLEEP_RETENTION_MODULE_MCPWM0) ? true \ + : ((m) == SLEEP_RETENTION_MODULE_SDM0) ? true \ : false) #ifdef __cplusplus diff --git a/components/soc/esp32h2/include/soc/soc_caps.h b/components/soc/esp32h2/include/soc/soc_caps.h index b64fb789d4..d4e7a19267 100644 --- a/components/soc/esp32h2/include/soc/soc_caps.h +++ b/components/soc/esp32h2/include/soc/soc_caps.h @@ -265,6 +265,8 @@ #define SOC_DEDIC_GPIO_IN_CHANNELS_NUM (8) /*!< 8 inward channels on each CPU core */ #define SOC_DEDIC_PERIPH_ALWAYS_ENABLE (1) /*!< The dedicated GPIO (a.k.a. fast GPIO) is featured by some customized CPU instructions, which is always enabled */ +#define SOC_SDM_SUPPORT_SLEEP_RETENTION 1 + /*------------------------- Analog Comparator CAPS ---------------------------*/ #define SOC_ANA_CMPR_NUM (1U) #define SOC_ANA_CMPR_INTR_SHARE_WITH_GPIO (1) diff --git a/components/soc/esp32h2/sdm_periph.c b/components/soc/esp32h2/sdm_periph.c index b92e215fb5..c4c4319411 100644 --- a/components/soc/esp32h2/sdm_periph.c +++ b/components/soc/esp32h2/sdm_periph.c @@ -6,6 +6,7 @@ #include "soc/sdm_periph.h" #include "soc/gpio_sig_map.h" +#include "soc/gpio_ext_reg.h" const soc_sdm_signal_desc_t soc_sdm_signals[1] = { [0] = { @@ -26,3 +27,32 @@ const soc_sdm_signal_desc_t soc_sdm_signals[1] = { } } }; + +/** + * @brief Registers in retention context: + * GPIO_EXT_SIGMADELTA[x]_REG + * GPIO_EXT_SIGMADELTA_MISC_REG + */ +#define GPIO_EXT_RETENTION_REGS_CNT 5 +#define GPIO_EXT_RETENTION_REGS_BASE (DR_REG_GPIO_EXT_BASE + 0x0) +static const uint32_t gpio_ext_regs_map[4] = {0x20f, 0x0, 0x0, 0x0}; +static const regdma_entries_config_t gpio_ext_regdma_entries[] = { + // backup stage: save configuration and status registers + // restore stage: restore the configuration and status registers + [0] = { + .config = REGDMA_LINK_ADDR_MAP_INIT(REGDMA_SDM_LINK(0x00), + GPIO_EXT_RETENTION_REGS_BASE, GPIO_EXT_RETENTION_REGS_BASE, + GPIO_EXT_RETENTION_REGS_CNT, 0, 0, + gpio_ext_regs_map[0], gpio_ext_regs_map[1], + gpio_ext_regs_map[2], gpio_ext_regs_map[3]), + .owner = ENTRY(0) | ENTRY(2), + }, +}; + +const soc_sdm_retention_desc_t soc_sdm_retention_infos[1] = { + [0] = { + .module = SLEEP_RETENTION_MODULE_SDM0, + .regdma_entry_array = gpio_ext_regdma_entries, + .array_size = ARRAY_SIZE(gpio_ext_regdma_entries) + } +}; diff --git a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in index 812dfafa3f..2bcd5eac7e 100644 --- a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in @@ -767,6 +767,10 @@ config SOC_DEDIC_PERIPH_ALWAYS_ENABLE bool default y +config SOC_SDM_SUPPORT_SLEEP_RETENTION + bool + default y + config SOC_ANA_CMPR_NUM int default 2 diff --git a/components/soc/esp32p4/include/soc/retention_periph_defs.h b/components/soc/esp32p4/include/soc/retention_periph_defs.h index d68770ef3a..09640ba728 100644 --- a/components/soc/esp32p4/include/soc/retention_periph_defs.h +++ b/components/soc/esp32p4/include/soc/retention_periph_defs.h @@ -59,6 +59,7 @@ typedef enum periph_retention_module { SLEEP_RETENTION_MODULE_LEDC = 33, SLEEP_RETENTION_MODULE_MCPWM0 = 34, SLEEP_RETENTION_MODULE_MCPWM1 = 35, + SLEEP_RETENTION_MODULE_SDM0 = 36, SLEEP_RETENTION_MODULE_MAX = SOC_PM_RETENTION_MODULE_NUM - 1 } periph_retention_module_t; @@ -100,6 +101,7 @@ typedef enum periph_retention_module { : ((m) == SLEEP_RETENTION_MODULE_LEDC) ? true \ : ((m) == SLEEP_RETENTION_MODULE_MCPWM0) ? true \ : ((m) == SLEEP_RETENTION_MODULE_MCPWM1) ? true \ + : ((m) == SLEEP_RETENTION_MODULE_SDM0) ? true \ : false) #ifdef __cplusplus diff --git a/components/soc/esp32p4/include/soc/soc_caps.h b/components/soc/esp32p4/include/soc/soc_caps.h index e6491e1463..b392b7d3ef 100644 --- a/components/soc/esp32p4/include/soc/soc_caps.h +++ b/components/soc/esp32p4/include/soc/soc_caps.h @@ -298,6 +298,8 @@ #define SOC_DEDIC_GPIO_IN_CHANNELS_NUM (8) /*!< 8 inward channels on each CPU core */ #define SOC_DEDIC_PERIPH_ALWAYS_ENABLE (1) /*!< The dedicated GPIO (a.k.a. fast GPIO) is featured by some customized CPU instructions, which is always enabled */ +#define SOC_SDM_SUPPORT_SLEEP_RETENTION 1 + /*------------------------- Analog Comparator CAPS ---------------------------*/ #define SOC_ANA_CMPR_NUM (2) #define SOC_ANA_CMPR_CAN_DISTINGUISH_EDGE (1) // Support positive/negative/any cross interrupt diff --git a/components/soc/esp32p4/sdm_periph.c b/components/soc/esp32p4/sdm_periph.c index d013c5a45c..4b89dce5a3 100644 --- a/components/soc/esp32p4/sdm_periph.c +++ b/components/soc/esp32p4/sdm_periph.c @@ -6,6 +6,7 @@ #include "soc/sdm_periph.h" #include "soc/gpio_sig_map.h" +#include "soc/gpio_ext_reg.h" const soc_sdm_signal_desc_t soc_sdm_signals[1] = { [0] = { @@ -38,3 +39,32 @@ const soc_sdm_signal_desc_t soc_sdm_signals[1] = { } } }; + +/** + * @brief Registers in retention context: + * GPIO_EXT_SIGMADELTA[x]_REG + * GPIO_EXT_SIGMADELTA_MISC_REG + */ +#define GPIO_EXT_RETENTION_REGS_CNT 9 +#define GPIO_EXT_RETENTION_REGS_BASE (DR_REG_GPIO_EXT_BASE + 0x0) +static const uint32_t gpio_ext_regs_map[4] = {0x2ff, 0x0, 0x0, 0x0}; +static const regdma_entries_config_t gpio_ext_regdma_entries[] = { + // backup stage: save configuration and status registers + // restore stage: restore the configuration and status registers + [0] = { + .config = REGDMA_LINK_ADDR_MAP_INIT(REGDMA_SDM_LINK(0x00), + GPIO_EXT_RETENTION_REGS_BASE, GPIO_EXT_RETENTION_REGS_BASE, + GPIO_EXT_RETENTION_REGS_CNT, 0, 0, + gpio_ext_regs_map[0], gpio_ext_regs_map[1], + gpio_ext_regs_map[2], gpio_ext_regs_map[3]), + .owner = ENTRY(0), + }, +}; + +const soc_sdm_retention_desc_t soc_sdm_retention_infos[1] = { + [0] = { + .module = SLEEP_RETENTION_MODULE_SDM0, + .regdma_entry_array = gpio_ext_regdma_entries, + .array_size = ARRAY_SIZE(gpio_ext_regdma_entries) + } +}; diff --git a/components/soc/include/soc/regdma.h b/components/soc/include/soc/regdma.h index 67b5c1d7fb..e3015fcbb7 100644 --- a/components/soc/include/soc/regdma.h +++ b/components/soc/include/soc/regdma.h @@ -64,6 +64,7 @@ extern "C" { #define REGDMA_GPSPI_LINK(_pri) ((0x23 << 8) | _pri) #define REGDMA_LEDC_LINK(_pri) ((0x24 << 8) | _pri) #define REGDMA_MCPWM_LINK(_pri) ((0x25 << 8) | _pri) +#define REGDMA_SDM_LINK(_pri) ((0x26 << 8) | _pri) #define REGDMA_MODEM_FE_LINK(_pri) ((0xFF << 8) | _pri) @@ -90,6 +91,7 @@ extern "C" { #define REGDMA_LINK_PRI_GPSPI REGDMA_LINK_PRI_GENERAL_PERIPH #define REGDMA_LINK_PRI_LEDC REGDMA_LINK_PRI_GENERAL_PERIPH #define REGDMA_LINK_PRI_MCPWM REGDMA_LINK_PRI_GENERAL_PERIPH +#define REGDMA_LINK_PRI_SDM REGDMA_LINK_PRI_GENERAL_PERIPH typedef enum { REGDMA_LINK_PRI_0 = 0, diff --git a/components/soc/include/soc/sdm_periph.h b/components/soc/include/soc/sdm_periph.h index c304196fd1..65f37a3dd9 100644 --- a/components/soc/include/soc/sdm_periph.h +++ b/components/soc/include/soc/sdm_periph.h @@ -23,6 +23,8 @@ extern "C" { #endif +#if SOC_HAS(SDM) + typedef struct { const char *module_name; // Module name struct { @@ -32,6 +34,20 @@ typedef struct { extern const soc_sdm_signal_desc_t soc_sdm_signals[SOC_SDM_ATTR(INST_NUM)]; +#if SOC_HAS(PAU) + +typedef struct { + const periph_retention_module_t module; // ID of the SDM as a retention module + const regdma_entries_config_t *regdma_entry_array; // Array of regdma entries for retention + const size_t array_size; // Size of the regdma_entry_array +} soc_sdm_retention_desc_t; + +extern const soc_sdm_retention_desc_t soc_sdm_retention_infos[SOC_SDM_ATTR(INST_NUM)]; + +#endif // SOC_HAS(PAU) + +#endif // SOC_HAS(SDM) + #ifdef __cplusplus } #endif From 0eb611a7971a7545f81498123a63a7a6894669d9 Mon Sep 17 00:00:00 2001 From: morris Date: Fri, 8 Aug 2025 14:22:11 +0800 Subject: [PATCH 3/3] feat(sdm): add driver support for esp32-h4 --- .../test_apps/sigma_delta/README.md | 4 +- components/hal/esp32h4/include/hal/sdm_ll.h | 64 +++++++++++++++++++ .../esp32h4/include/soc/Kconfig.soc_caps.in | 8 +++ .../soc/esp32h4/include/soc/clk_tree_defs.h | 25 +++++--- .../include/soc/retention_periph_defs.h | 2 + components/soc/esp32h4/include/soc/soc_caps.h | 10 +-- .../soc/esp32h4/include/soc/soc_caps_full.h | 4 ++ .../soc/esp32h4/ld/esp32h4.peripherals.ld | 2 + .../esp32h4/register/soc/gpio_ext_struct.h | 18 ++++-- components/soc/esp32h4/sdm_periph.c | 58 +++++++++++++++++ .../peripherals/sigma_delta/sdm_dac/README.md | 4 +- .../peripherals/sigma_delta/sdm_led/README.md | 4 +- 12 files changed, 177 insertions(+), 26 deletions(-) create mode 100644 components/hal/esp32h4/include/hal/sdm_ll.h create mode 100644 components/soc/esp32h4/sdm_periph.c diff --git a/components/esp_driver_sdm/test_apps/sigma_delta/README.md b/components/esp_driver_sdm/test_apps/sigma_delta/README.md index 46d16c788c..e16f43d09c 100644 --- a/components/esp_driver_sdm/test_apps/sigma_delta/README.md +++ b/components/esp_driver_sdm/test_apps/sigma_delta/README.md @@ -1,2 +1,2 @@ -| Supported Targets | ESP32 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | +| Supported Targets | ESP32 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-H4 | ESP32-P4 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | diff --git a/components/hal/esp32h4/include/hal/sdm_ll.h b/components/hal/esp32h4/include/hal/sdm_ll.h new file mode 100644 index 0000000000..2c646fc4b5 --- /dev/null +++ b/components/hal/esp32h4/include/hal/sdm_ll.h @@ -0,0 +1,64 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include "hal/misc.h" +#include "hal/assert.h" +#include "soc/gpio_ext_struct.h" +#include "soc/gpio_ext_reg.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// Get SDM register base address with giving group number +#define SDM_LL_GET_HW(group_id) ((group_id == 0) ? (&SDM) : NULL) + +#define SDM_LL_PRESCALE_MAX (GPIO_EXT_SD0_PRESCALE_V + 1) + +/** + * @brief Set Sigma-delta enable + * + * @param hw Peripheral SIGMADELTA hardware instance address. + * @param en Sigma-delta enable value + */ +static inline void sdm_ll_enable_clock(gpio_sd_dev_t *hw, bool en) +{ + hw->misc.ext_sigmadelta_clk_en = en; +} + +/** + * @brief Set Sigma-delta channel duty. + * + * @param hw Peripheral SIGMADELTA hardware instance address. + * @param channel Sigma-delta channel number + * @param density Sigma-delta quantized density of one channel, the value ranges from -128 to 127, recommended range is -90 ~ 90. + * The waveform is more like a random one in this range. + */ +__attribute__((always_inline)) +static inline void sdm_ll_set_pulse_density(gpio_sd_dev_t *hw, int channel, int8_t density) +{ + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->channel[channel], ext_sdn_in, (uint32_t)density); +} + +/** + * @brief Set Sigma-delta channel's clock pre-scale value. + * + * @param hw Peripheral SIGMADELTA hardware instance address. + * @param channel Sigma-delta channel number + * @param prescale The divider of source clock, ranges from 1 to 256 + */ +static inline void sdm_ll_set_prescale(gpio_sd_dev_t *hw, int channel, uint32_t prescale) +{ + HAL_ASSERT(prescale && prescale <= SDM_LL_PRESCALE_MAX); + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->channel[channel], ext_sdn_prescale, prescale - 1); +} + +#ifdef __cplusplus +} +#endif diff --git a/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in index b80a9c9d0c..06a28d8d1d 100644 --- a/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in @@ -47,6 +47,10 @@ config SOC_RMT_SUPPORTED bool default y +config SOC_SDM_SUPPORTED + bool + default y + config SOC_GPSPI_SUPPORTED bool default y @@ -335,6 +339,10 @@ config SOC_RTCIO_EDGE_WAKE_SUPPORTED bool default y +config SOC_SDM_SUPPORT_SLEEP_RETENTION + bool + default y + config SOC_I2C_NUM int default 2 diff --git a/components/soc/esp32h4/include/soc/clk_tree_defs.h b/components/soc/esp32h4/include/soc/clk_tree_defs.h index 41810eb430..c2403cf339 100644 --- a/components/soc/esp32h4/include/soc/clk_tree_defs.h +++ b/components/soc/esp32h4/include/soc/clk_tree_defs.h @@ -190,15 +190,6 @@ typedef enum { #endif } soc_periph_gptimer_clk_src_t; -/** - * @brief Type of Timer Group clock source, reserved for the legacy timer group driver - */ -typedef enum { - TIMER_SRC_CLK_PLL_F48M = SOC_MOD_CLK_PLL_F48M, /*!< Timer group clock source is PLL_F48M */ - TIMER_SRC_CLK_XTAL = SOC_MOD_CLK_XTAL, /*!< Timer group clock source is XTAL */ - TIMER_SRC_CLK_DEFAULT = SOC_MOD_CLK_PLL_F48M, /*!< Timer group clock source default choice is PLL_F48M */ -} soc_periph_tg_clk_src_legacy_t; - //////////////////////////////////////////////////RMT/////////////////////////////////////////////////////////////////// /** @@ -348,6 +339,22 @@ typedef enum { I2S_CLK_SRC_EXTERNAL = -1, /*!< Select external clock as source clock */ } soc_periph_i2s_clk_src_t; +//////////////////////////////////////////////////SDM////////////////////////////////////////////////////////////// + +/** + * @brief Array initializer for all supported clock sources of SDM + */ +#define SOC_SDM_CLKS {SOC_MOD_CLK_PLL_F48M, SOC_MOD_CLK_XTAL} + +/** + * @brief Sigma Delta Modulator clock source + */ +typedef enum { + SDM_CLK_SRC_XTAL = SOC_MOD_CLK_XTAL, /*!< Select XTAL clock as the source clock */ + SDM_CLK_SRC_PLL_F48M = SOC_MOD_CLK_PLL_F48M, /*!< Select PLL_F48M clock as the source clock */ + SDM_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_F48M, /*!< Select PLL_F48M clock as the default clock choice */ +} soc_periph_sdm_clk_src_t; + #ifdef __cplusplus } #endif diff --git a/components/soc/esp32h4/include/soc/retention_periph_defs.h b/components/soc/esp32h4/include/soc/retention_periph_defs.h index 9306653f66..56379894b6 100644 --- a/components/soc/esp32h4/include/soc/retention_periph_defs.h +++ b/components/soc/esp32h4/include/soc/retention_periph_defs.h @@ -49,6 +49,7 @@ typedef enum periph_retention_module { SLEEP_RETENTION_MODULE_GPSPI3 = 25, SLEEP_RETENTION_MODULE_LEDC = 26, SLEEP_RETENTION_MODULE_MCPWM0 = 27, + SLEEP_RETENTION_MODULE_SDM0 = 28, /* Modem module, which includes BLE and 802.15.4 */ SLEEP_RETENTION_MODULE_BLE_MAC = 29, @@ -86,6 +87,7 @@ typedef enum periph_retention_module { : ((m) == SLEEP_RETENTION_MODULE_GPSPI3) ? true \ : ((m) == SLEEP_RETENTION_MODULE_LEDC) ? true \ : ((m) == SLEEP_RETENTION_MODULE_MCPWM0) ? true \ + : ((m) == SLEEP_RETENTION_MODULE_SDM0) ? true \ : false) #ifdef __cplusplus diff --git a/components/soc/esp32h4/include/soc/soc_caps.h b/components/soc/esp32h4/include/soc/soc_caps.h index 383a99c7e4..eaedb5326c 100644 --- a/components/soc/esp32h4/include/soc/soc_caps.h +++ b/components/soc/esp32h4/include/soc/soc_caps.h @@ -56,7 +56,7 @@ // #define SOC_RTC_MEM_SUPPORTED 1 // TODO: [ESP32H4] IDF-12313 #define SOC_I2S_SUPPORTED 1 #define SOC_RMT_SUPPORTED 1 -// #define SOC_SDM_SUPPORTED 1 // TODO: [ESP32H4] IDF-12348 +#define SOC_SDM_SUPPORTED 1 #define SOC_GPSPI_SUPPORTED 1 // #define SOC_LEDC_SUPPORTED 1 // TODO: [ESP32H4] IDF-12343 #define SOC_I2C_SUPPORTED 1 @@ -254,6 +254,8 @@ // #define SOC_DEDIC_GPIO_IN_CHANNELS_NUM (8) /*!< 8 inward channels on each CPU core */ // #define SOC_DEDIC_PERIPH_ALWAYS_ENABLE (1) /*!< The dedicated GPIO (a.k.a. fast GPIO) is featured by some customized CPU instructions, which is always enabled */ +#define SOC_SDM_SUPPORT_SLEEP_RETENTION 1 + /*-------------------------- I2C CAPS ----------------------------------------*/ // ESP32-H4 has 2 I2C #define SOC_I2C_NUM (2U) @@ -396,12 +398,6 @@ // #define SOC_SHA_SUPPORT_SHA224 (1) // #define SOC_SHA_SUPPORT_SHA256 (1) -/*-------------------------- Sigma Delta Modulator CAPS -----------------*/ -// #define SOC_SDM_GROUPS 1U -// #define SOC_SDM_CHANNELS_PER_GROUP 4 -// #define SOC_SDM_CLK_SUPPORT_PLL_F80M 1 -// #define SOC_SDM_CLK_SUPPORT_XTAL 1 - /*-------------------------- SPI CAPS ----------------------------------------*/ #define SOC_SPI_PERIPH_NUM 3 #define SOC_SPI_PERIPH_CS_NUM(i) (((i)==0)? 2: (((i)==1)? 6: 3)) diff --git a/components/soc/esp32h4/include/soc/soc_caps_full.h b/components/soc/esp32h4/include/soc/soc_caps_full.h index 6ccb00bd76..63d2d2eec5 100644 --- a/components/soc/esp32h4/include/soc/soc_caps_full.h +++ b/components/soc/esp32h4/include/soc/soc_caps_full.h @@ -19,3 +19,7 @@ /*--------------------------- Watch Dog ------------------------------------------*/ #define _SOC_CAPS_WDT_MWDTS_PER_TIMG 1 // Number of main watchdog timers in each Timer Group + +/*--------------------------- SDM (Sigma-Delta Modulator) ------------------------*/ +#define _SOC_CAPS_SDM_INST_NUM 1 // Number of SDM instances +#define _SOC_CAPS_SDM_CHANS_PER_INST 4 // Number of channels in each SDM instance diff --git a/components/soc/esp32h4/ld/esp32h4.peripherals.ld b/components/soc/esp32h4/ld/esp32h4.peripherals.ld index 4cba2c9ecb..4ecd54aa6c 100644 --- a/components/soc/esp32h4/ld/esp32h4.peripherals.ld +++ b/components/soc/esp32h4/ld/esp32h4.peripherals.ld @@ -44,6 +44,8 @@ PROVIDE ( TIMERG1 = 0x60091000 ); PROVIDE ( IO_MUX = 0x60092000 ); PROVIDE ( GPIO = 0x60093000 ); PROVIDE ( GPIO_EXT = 0x60093E00 ); +PROVIDE ( SDM = 0x60093E00 ); +PROVIDE ( GLITCH_FILTER = 0x60093ED8 ); PROVIDE ( GPIO_ETM = 0x60093F18 ); PROVIDE ( PCR = 0x60094000 ); PROVIDE ( SPIMEM0 = 0x60098000 ); diff --git a/components/soc/esp32h4/register/soc/gpio_ext_struct.h b/components/soc/esp32h4/register/soc/gpio_ext_struct.h index da06484c0b..17167ae71c 100644 --- a/components/soc/esp32h4/register/soc/gpio_ext_struct.h +++ b/components/soc/esp32h4/register/soc/gpio_ext_struct.h @@ -218,6 +218,12 @@ typedef union { uint32_t val; } gpio_ext_version_reg_t; +typedef struct gpio_sd_dev_t { + volatile uint32_t reserved; + volatile gpio_ext_sigmadelta_misc_reg_t misc; + volatile gpio_ext_sigmadeltan_reg_t channel[4]; +} gpio_sd_dev_t; + typedef struct gpio_etm_dev_t { volatile gpio_ext_etm_event_chn_cfg_reg_t etm_event_chn_cfg[8]; uint32_t reserved_080[8]; @@ -225,17 +231,21 @@ typedef struct gpio_etm_dev_t { } gpio_etm_dev_t; typedef struct { - uint32_t reserved_000; - volatile gpio_ext_sigmadelta_misc_reg_t ext_sigmadelta_misc; - volatile gpio_ext_sigmadeltan_reg_t ext_sigmadeltan[4]; + volatile gpio_ext_glitch_filter_chn_reg_t glitch_filter_chn[8]; +} gpio_glitch_filter_dev_t; + +typedef struct { + volatile gpio_sd_dev_t sigma_delta; uint32_t reserved_018[48]; - volatile gpio_ext_glitch_filter_chn_reg_t ext_glitch_filter_chn[8]; + volatile gpio_glitch_filter_dev_t ext_glitch_filter; uint32_t reserved_0f8[8]; volatile gpio_etm_dev_t etm; uint32_t reserved_178[33]; volatile gpio_ext_version_reg_t ext_version; } gpio_ext_dev_t; +extern gpio_sd_dev_t SDM; +extern gpio_glitch_filter_dev_t GLITCH_FILTER; extern gpio_etm_dev_t GPIO_ETM; extern gpio_ext_dev_t GPIO_EXT; diff --git a/components/soc/esp32h4/sdm_periph.c b/components/soc/esp32h4/sdm_periph.c new file mode 100644 index 0000000000..6fd08e451b --- /dev/null +++ b/components/soc/esp32h4/sdm_periph.c @@ -0,0 +1,58 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "soc/sdm_periph.h" +#include "soc/gpio_sig_map.h" +#include "soc/gpio_ext_reg.h" + +const soc_sdm_signal_desc_t soc_sdm_signals[1] = { + [0] = { + .module_name = "SDM0", + .channels = { + [0] = { + .sig_id_matrix = GPIO_SD0_OUT_IDX + }, + [1] = { + .sig_id_matrix = GPIO_SD1_OUT_IDX + }, + [2] = { + .sig_id_matrix = GPIO_SD2_OUT_IDX + }, + [3] = { + .sig_id_matrix = GPIO_SD3_OUT_IDX + } + } + } +}; + +/** + * @brief Registers in retention context: + * GPIO_EXT_SIGMADELTA[x]_REG + * GPIO_EXT_SIGMADELTA_MISC_REG + */ +#define GPIO_EXT_RETENTION_REGS_CNT 5 +#define GPIO_EXT_RETENTION_REGS_BASE (DR_REG_GPIO_EXT_BASE + 0x4) +static const uint32_t gpio_ext_regs_map[4] = {0x1f, 0x0, 0x0, 0x0}; +static const regdma_entries_config_t gpio_ext_regdma_entries[] = { + // backup stage: save configuration and status registers + // restore stage: restore the configuration and status registers + [0] = { + .config = REGDMA_LINK_ADDR_MAP_INIT(REGDMA_SDM_LINK(0x00), + GPIO_EXT_RETENTION_REGS_BASE, GPIO_EXT_RETENTION_REGS_BASE, + GPIO_EXT_RETENTION_REGS_CNT, 0, 0, + gpio_ext_regs_map[0], gpio_ext_regs_map[1], + gpio_ext_regs_map[2], gpio_ext_regs_map[3]), + .owner = ENTRY(0) | ENTRY(2), + }, +}; + +const soc_sdm_retention_desc_t soc_sdm_retention_infos[1] = { + [0] = { + .module = SLEEP_RETENTION_MODULE_SDM0, + .regdma_entry_array = gpio_ext_regdma_entries, + .array_size = ARRAY_SIZE(gpio_ext_regdma_entries) + } +}; diff --git a/examples/peripherals/sigma_delta/sdm_dac/README.md b/examples/peripherals/sigma_delta/sdm_dac/README.md index 3409ff0256..e3960d6de5 100644 --- a/examples/peripherals/sigma_delta/sdm_dac/README.md +++ b/examples/peripherals/sigma_delta/sdm_dac/README.md @@ -1,5 +1,5 @@ -| Supported Targets | ESP32 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | +| Supported Targets | ESP32 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-H4 | ESP32-P4 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | # Sigma Delta Modulation DAC Example diff --git a/examples/peripherals/sigma_delta/sdm_led/README.md b/examples/peripherals/sigma_delta/sdm_led/README.md index 754fc57468..5a13be780a 100644 --- a/examples/peripherals/sigma_delta/sdm_led/README.md +++ b/examples/peripherals/sigma_delta/sdm_led/README.md @@ -1,5 +1,5 @@ -| Supported Targets | ESP32 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | +| Supported Targets | ESP32 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-H4 | ESP32-P4 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | # Sigma Delta Modulation LED Example