diff --git a/components/esp_driver_ledc/CMakeLists.txt b/components/esp_driver_ledc/CMakeLists.txt index e16690efab..41b3ca9a9d 100644 --- a/components/esp_driver_ledc/CMakeLists.txt +++ b/components/esp_driver_ledc/CMakeLists.txt @@ -5,6 +5,10 @@ set(public_include "include") if(CONFIG_SOC_LEDC_SUPPORTED) list(APPEND srcs "src/ledc.c") + + if(CONFIG_SOC_ETM_SUPPORTED AND CONFIG_SOC_LEDC_SUPPORT_ETM) + list(APPEND srcs "src/ledc_etm.c") + endif() endif() if(${target} STREQUAL "linux") diff --git a/components/esp_driver_ledc/include/driver/ledc.h b/components/esp_driver_ledc/include/driver/ledc.h index 07d1211684..4ce85c0f50 100644 --- a/components/esp_driver_ledc/include/driver/ledc.h +++ b/components/esp_driver_ledc/include/driver/ledc.h @@ -8,6 +8,7 @@ #include "esp_err.h" #include "esp_intr_alloc.h" +#include "driver/ledc_etm.h" #include "hal/ledc_types.h" #ifdef __cplusplus @@ -385,6 +386,25 @@ esp_err_t ledc_timer_resume(ledc_mode_t speed_mode, ledc_timer_t timer_sel); */ esp_err_t ledc_bind_channel_timer(ledc_mode_t speed_mode, ledc_channel_t channel, ledc_timer_t timer_sel); +#if SOC_LEDC_SUPPORT_ETM +/** + * @brief Configure the maximum timer overflow times for the LEDC channel to be used to trigger `LEDC_ETM_EVENT_CHANNEL_REACH_MAX_OVF_CNT` ETM event + * + * When the overflow counter maximum value is re-configured, the counter will also be reset. + * Timer can be paused before calling this API by calling `ledc_timer_pause()`, and resumed afterwards by calling `ledc_timer_resume()`. + * + * @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode. + * @param channel LEDC channel index (0 - LEDC_CHANNEL_MAX-1), select from ledc_channel_t + * @param max_ovf_cnt The timer overflow counter maximum value. To disable the timer overflow count, set this parameter to 0. + * + * @return + * - ESP_ERR_INVALID_ARG Parameter error + * - ESP_ERR_INVALID_STATE Channel not initialized + * - ESP_OK Success + */ +esp_err_t ledc_channel_configure_maximum_timer_ovf_cnt(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t max_ovf_cnt); +#endif + /** * @brief Set LEDC fade function. * diff --git a/components/esp_driver_ledc/include/driver/ledc_etm.h b/components/esp_driver_ledc/include/driver/ledc_etm.h new file mode 100644 index 0000000000..2aa72521aa --- /dev/null +++ b/components/esp_driver_ledc/include/driver/ledc_etm.h @@ -0,0 +1,115 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include "esp_err.h" +#include "esp_etm.h" +#include "hal/ledc_types.h" +#include "soc/soc_caps.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if SOC_LEDC_SUPPORT_ETM + +/** + * @brief LEDC timer ETM event configuration + */ +typedef struct { + ledc_timer_etm_event_type_t event_type; /*!< LEDC timer ETM event type */ +} ledc_timer_etm_event_config_t; + +/** + * @brief LEDC channel ETM event configuration + */ +typedef struct { + ledc_channel_etm_event_type_t event_type; /*!< LEDC channel ETM event type */ +} ledc_channel_etm_event_config_t; + +/** + * @brief Get the ETM timer event for LEDC + * + * @note The created ETM event object can be deleted later by calling `esp_etm_del_event` + * + * @param[in] speed_mode Select the LEDC channel group with specified speed mode + * @param[in] timer_sel LEDC timer index, select from ledc_timer_t + * @param[in] config LEDC timer ETM event configuration + * @param[out] out_event Returned ETM event handle + * @return + * - ESP_OK: Get ETM event successfully + * - ESP_ERR_INVALID_ARG: Get ETM event failed because of invalid argument + * - ESP_ERR_NO_MEM: Get ETM event failed because of no memory + */ +esp_err_t ledc_timer_new_etm_event(ledc_mode_t speed_mode, ledc_timer_t timer_sel, const ledc_timer_etm_event_config_t *config, esp_etm_event_handle_t *out_event); + +/** + * @brief Get the ETM channel event for LEDC + * + * @note The created ETM event object can be deleted later by calling `esp_etm_del_event` + * + * @param[in] speed_mode Select the LEDC channel group with specified speed mode + * @param[in] channel LEDC channel index, select from ledc_channel_t + * @param[in] config LEDC channel ETM event configuration + * @param[out] out_event Returned ETM event handle + * @return + * - ESP_OK: Get ETM event successfully + * - ESP_ERR_INVALID_ARG: Get ETM event failed because of invalid argument + * - ESP_ERR_NO_MEM: Get ETM event failed because of no memory + */ +esp_err_t ledc_channel_new_etm_event(ledc_mode_t speed_mode, ledc_channel_t channel, const ledc_channel_etm_event_config_t *config, esp_etm_event_handle_t *out_event); + +/** + * @brief LEDC timer ETM task configuration + */ +typedef struct { + ledc_timer_etm_task_type_t task_type; /*!< LEDC timer ETM task type */ +} ledc_timer_etm_task_config_t; + +/** + * @brief LEDC channel ETM task configuration + */ +typedef struct { + ledc_channel_etm_task_type_t task_type; /*!< LEDC channel ETM task type */ +} ledc_channel_etm_task_config_t; + +/** + * @brief Get the ETM timer task for LEDC + * + * @note The created ETM task object can be deleted later by calling `esp_etm_del_task` + * + * @param[in] speed_mode Select the LEDC channel group with specified speed mode + * @param[in] timer_sel LEDC timer index, select from ledc_timer_t + * @param[in] config LEDC timer ETM task configuration + * @param[out] out_task Returned ETM task handle + * @return + * - ESP_OK: Get ETM task successfully + * - ESP_ERR_INVALID_ARG: Get ETM task failed because of invalid argument + * - ESP_ERR_NO_MEM: Get ETM task failed because of no memory + */ +esp_err_t ledc_timer_new_etm_task(ledc_mode_t speed_mode, ledc_timer_t timer_sel, const ledc_timer_etm_task_config_t *config, esp_etm_task_handle_t *out_task); + +/** + * @brief Get the ETM channel task for LEDC + * + * @note The created ETM task object can be deleted later by calling `esp_etm_del_task` + * + * @param[in] speed_mode Select the LEDC channel group with specified speed mode + * @param[in] channel LEDC channel index, select from ledc_channel_t + * @param[in] config LEDC channel ETM task configuration + * @param[out] out_task Returned ETM task handle + * @return + * - ESP_OK: Get ETM task successfully + * - ESP_ERR_INVALID_ARG: Get ETM task failed because of invalid argument + * - ESP_ERR_NO_MEM: Get ETM task failed because of no memory + */ +esp_err_t ledc_channel_new_etm_task(ledc_mode_t speed_mode, ledc_channel_t channel, const ledc_channel_etm_task_config_t *config, esp_etm_task_handle_t *out_task); + +#endif // SOC_LEDC_SUPPORT_ETM +#ifdef __cplusplus +} +#endif diff --git a/components/esp_driver_ledc/src/ledc.c b/components/esp_driver_ledc/src/ledc.c index 04bada46c8..4f72be70c9 100644 --- a/components/esp_driver_ledc/src/ledc.c +++ b/components/esp_driver_ledc/src/ledc.c @@ -277,6 +277,7 @@ static IRAM_ATTR esp_err_t ledc_duty_config(ledc_mode_t speed_mode, ledc_channel // Clear left-off LEDC gamma ram registers, random data in ram could cause output waveform error ledc_hal_clear_left_off_fade_param(&(p_ledc_obj[speed_mode]->ledc_hal), channel, 1); #endif + ESP_EARLY_LOGD(LEDC_TAG, "duty_config: duty-%d, dir-%d, cycle-%d, scale-%d, step-%d", duty_val, duty_direction, duty_cycle, duty_scale, duty_num); return ESP_OK; } @@ -392,6 +393,21 @@ esp_err_t ledc_timer_resume(ledc_mode_t speed_mode, ledc_timer_t timer_sel) return ESP_OK; } +#if SOC_LEDC_SUPPORT_ETM +esp_err_t ledc_channel_configure_maximum_timer_ovf_cnt(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t max_ovf_cnt) +{ + LEDC_ARG_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "speed_mode"); + LEDC_ARG_CHECK(channel < LEDC_CHANNEL_MAX, "channel"); + LEDC_ARG_CHECK(max_ovf_cnt <= LEDC_LL_OVF_CNT_MAX, "max_ovf_cnt"); + LEDC_CHECK(p_ledc_obj[speed_mode] != NULL, LEDC_NOT_INIT, ESP_ERR_INVALID_STATE); + + ledc_hal_channel_configure_maximum_timer_ovf_cnt(&(p_ledc_obj[speed_mode]->ledc_hal), channel, max_ovf_cnt); + ledc_ls_channel_update(speed_mode, channel); + + return ESP_OK; +} +#endif + esp_err_t ledc_isr_register(void (*fn)(void *), void *arg, int intr_alloc_flags, ledc_isr_handle_t *handle) { esp_err_t ret; diff --git a/components/esp_driver_ledc/src/ledc_etm.c b/components/esp_driver_ledc/src/ledc_etm.c new file mode 100644 index 0000000000..971c289ba6 --- /dev/null +++ b/components/esp_driver_ledc/src/ledc_etm.c @@ -0,0 +1,154 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "freertos/FreeRTOS.h" +#include "esp_check.h" +#include "driver/ledc.h" +#include "esp_private/etm_interface.h" +#include "esp_heap_caps.h" +#include "hal/ledc_ll.h" + +#define TAG "ledc_etm" + +typedef struct { + union { + esp_etm_event_t evt_base; + esp_etm_task_t task_base; + }; + ledc_mode_t speed_mode; + volatile uint32_t *en_reg_addr; + uint32_t en_bit; +} ledc_etm_event_task_t; + +static portMUX_TYPE s_ledc_etm_spinlock = portMUX_INITIALIZER_UNLOCKED; + +static esp_err_t ledc_del_etm_event(esp_etm_event_t *event) +{ + ledc_etm_event_task_t *etm_event = __containerof(event, ledc_etm_event_task_t, evt_base); + + if (etm_event->en_reg_addr != 0) { + portENTER_CRITICAL(&s_ledc_etm_spinlock); + ledc_ll_etm_enable_evt_task(LEDC_LL_GET_HW(), etm_event->speed_mode, etm_event->en_reg_addr, etm_event->en_bit, false); + portEXIT_CRITICAL(&s_ledc_etm_spinlock); + } + + free(etm_event); + return ESP_OK; +} + +static esp_err_t ledc_del_etm_task(esp_etm_task_t *task) +{ + ledc_etm_event_task_t *etm_task = __containerof(task, ledc_etm_event_task_t, task_base); + + if (etm_task->en_reg_addr != 0) { + portENTER_CRITICAL(&s_ledc_etm_spinlock); + ledc_ll_etm_enable_evt_task(LEDC_LL_GET_HW(), etm_task->speed_mode, etm_task->en_reg_addr, etm_task->en_bit, false); + portEXIT_CRITICAL(&s_ledc_etm_spinlock); + } + + free(etm_task); + return ESP_OK; +} + +esp_err_t ledc_timer_new_etm_event(ledc_mode_t speed_mode, ledc_timer_t timer_sel, const ledc_timer_etm_event_config_t *config, esp_etm_event_handle_t *out_event) +{ + ESP_RETURN_ON_FALSE(speed_mode < LEDC_SPEED_MODE_MAX && timer_sel < LEDC_TIMER_MAX && config && config->event_type < LEDC_TIMER_ETM_EVENT_MAX && out_event, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); + + ledc_etm_event_task_t *event = heap_caps_calloc(1, sizeof(ledc_etm_event_task_t), MALLOC_CAP_DEFAULT); + ESP_RETURN_ON_FALSE(event, ESP_ERR_NO_MEM, TAG, "no memory for ETM event"); + + uint32_t evt_id = LEDC_LL_ETM_TIMER_EVENT_ID(speed_mode, timer_sel, config->event_type); + volatile uint32_t *en_reg = LEDC_LL_ETM_TIMER_EVENT_EN_REG(speed_mode, config->event_type); + uint32_t en_bit = LEDC_LL_ETM_TIMER_EVENT_EN_BIT(speed_mode, timer_sel, config->event_type); + + portENTER_CRITICAL(&s_ledc_etm_spinlock); + ledc_ll_etm_enable_evt_task(LEDC_LL_GET_HW(), speed_mode, en_reg, en_bit, true); + portEXIT_CRITICAL(&s_ledc_etm_spinlock); + event->speed_mode = speed_mode; + event->en_reg_addr = en_reg; + event->en_bit = en_bit; + event->evt_base.event_id = evt_id; + event->evt_base.trig_periph = ETM_TRIG_PERIPH_LEDC; + event->evt_base.del = ledc_del_etm_event; + + *out_event = &event->evt_base; + return ESP_OK; +} + +esp_err_t ledc_channel_new_etm_event(ledc_mode_t speed_mode, ledc_channel_t channel, const ledc_channel_etm_event_config_t *config, esp_etm_event_handle_t *out_event) +{ + ESP_RETURN_ON_FALSE(speed_mode < LEDC_SPEED_MODE_MAX && channel < LEDC_CHANNEL_MAX && config && config->event_type < LEDC_CHANNEL_ETM_EVENT_MAX && out_event, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); + + ledc_etm_event_task_t *event = heap_caps_calloc(1, sizeof(ledc_etm_event_task_t), MALLOC_CAP_DEFAULT); + ESP_RETURN_ON_FALSE(event, ESP_ERR_NO_MEM, TAG, "no memory for ETM event"); + + uint32_t evt_id = LEDC_LL_ETM_CHANNEL_EVENT_ID(speed_mode, channel, config->event_type); + volatile uint32_t *en_reg = LEDC_LL_ETM_CHANNEL_EVENT_EN_REG(speed_mode, config->event_type); + uint32_t en_bit = LEDC_LL_ETM_CHANNEL_EVENT_EN_BIT(speed_mode, channel, config->event_type); + + portENTER_CRITICAL(&s_ledc_etm_spinlock); + ledc_ll_etm_enable_evt_task(LEDC_LL_GET_HW(), speed_mode, en_reg, en_bit, true); + portEXIT_CRITICAL(&s_ledc_etm_spinlock); + event->speed_mode = speed_mode; + event->en_reg_addr = en_reg; + event->en_bit = en_bit; + event->evt_base.event_id = evt_id; + event->evt_base.trig_periph = ETM_TRIG_PERIPH_LEDC; + event->evt_base.del = ledc_del_etm_event; + + *out_event = &event->evt_base; + return ESP_OK; +} + +esp_err_t ledc_timer_new_etm_task(ledc_mode_t speed_mode, ledc_timer_t timer_sel, const ledc_timer_etm_task_config_t *config, esp_etm_task_handle_t *out_task) +{ + ESP_RETURN_ON_FALSE(speed_mode < LEDC_SPEED_MODE_MAX && timer_sel < LEDC_TIMER_MAX && config && config->task_type < LEDC_TIMER_ETM_TASK_MAX && out_task, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); + + ledc_etm_event_task_t *task = heap_caps_calloc(1, sizeof(ledc_etm_event_task_t), MALLOC_CAP_DEFAULT); + ESP_RETURN_ON_FALSE(task, ESP_ERR_NO_MEM, TAG, "no memory for ETM task"); + + uint32_t task_id = LEDC_LL_ETM_TIMER_TASK_ID(speed_mode, timer_sel, config->task_type); + volatile uint32_t *en_reg = LEDC_LL_ETM_TIMER_TASK_EN_REG(speed_mode, config->task_type); + uint32_t en_bit = LEDC_LL_ETM_TIMER_TASK_EN_BIT(speed_mode, timer_sel, config->task_type); + + portENTER_CRITICAL(&s_ledc_etm_spinlock); + ledc_ll_etm_enable_evt_task(LEDC_LL_GET_HW(), speed_mode, en_reg, en_bit, true); + portEXIT_CRITICAL(&s_ledc_etm_spinlock); + task->speed_mode = speed_mode; + task->en_reg_addr = en_reg; + task->en_bit = en_bit; + task->task_base.task_id = task_id; + task->task_base.trig_periph = ETM_TRIG_PERIPH_LEDC; + task->task_base.del = ledc_del_etm_task; + + *out_task = &task->task_base; + return ESP_OK; +} + +esp_err_t ledc_channel_new_etm_task(ledc_mode_t speed_mode, ledc_channel_t channel, const ledc_channel_etm_task_config_t *config, esp_etm_task_handle_t *out_task) +{ + ESP_RETURN_ON_FALSE(speed_mode < LEDC_SPEED_MODE_MAX && channel < LEDC_CHANNEL_MAX && config && config->task_type < LEDC_CHANNEL_ETM_TASK_MAX && out_task, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); + + ledc_etm_event_task_t *task = heap_caps_calloc(1, sizeof(ledc_etm_event_task_t), MALLOC_CAP_DEFAULT); + ESP_RETURN_ON_FALSE(task, ESP_ERR_NO_MEM, TAG, "no memory for ETM task"); + + uint32_t task_id = LEDC_LL_ETM_CHANNEL_TASK_ID(speed_mode, channel, config->task_type); + volatile uint32_t *en_reg = LEDC_LL_ETM_CHANNEL_TASK_EN_REG(speed_mode, config->task_type); + uint32_t en_bit = LEDC_LL_ETM_CHANNEL_TASK_EN_BIT(speed_mode, channel, config->task_type); + + portENTER_CRITICAL(&s_ledc_etm_spinlock); + ledc_ll_etm_enable_evt_task(LEDC_LL_GET_HW(), speed_mode, en_reg, en_bit, true); + portEXIT_CRITICAL(&s_ledc_etm_spinlock); + task->speed_mode = speed_mode; + task->en_reg_addr = en_reg; + task->en_bit = en_bit; + task->task_base.task_id = task_id; + task->task_base.trig_periph = ETM_TRIG_PERIPH_LEDC; + task->task_base.del = ledc_del_etm_task; + + *out_task = &task->task_base; + return ESP_OK; +} diff --git a/components/esp_driver_ledc/test_apps/ledc/main/CMakeLists.txt b/components/esp_driver_ledc/test_apps/ledc/main/CMakeLists.txt index b68eb188e2..64222b781e 100644 --- a/components/esp_driver_ledc/test_apps/ledc/main/CMakeLists.txt +++ b/components/esp_driver_ledc/test_apps/ledc/main/CMakeLists.txt @@ -6,6 +6,10 @@ if(CONFIG_SOC_LIGHT_SLEEP_SUPPORTED) list(APPEND srcs "test_ledc_sleep.cpp") endif() +if(CONFIG_SOC_ETM_SUPPORTED AND CONFIG_SOC_LEDC_SUPPORT_ETM) + list(APPEND srcs "test_ledc_etm.cpp") +endif() + # In order for the cases defined by `TEST_CASE` to be linked into the final elf, # the component can be registered as WHOLE_ARCHIVE idf_component_register( diff --git a/components/esp_driver_ledc/test_apps/ledc/main/test_ledc_etm.cpp b/components/esp_driver_ledc/test_apps/ledc/main/test_ledc_etm.cpp new file mode 100644 index 0000000000..9f302ea192 --- /dev/null +++ b/components/esp_driver_ledc/test_apps/ledc/main/test_ledc_etm.cpp @@ -0,0 +1,72 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "unity.h" +#include "test_utils.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "driver/ledc.h" +#include "test_ledc_utils.h" +#include "esp_etm.h" +#include "esp_attr.h" +#include "driver/uart.h" + +TEST_CASE("ledc etm event and task", "[ledc]") +{ + // Generate a PWM signal with certain number of pulses + + ledc_timer_config_t ledc_time_config = create_default_timer_config(); + TEST_ESP_OK(ledc_timer_config(&ledc_time_config)); + + ledc_channel_config_t ledc_ch_config = initialize_channel_config(); + TEST_ESP_OK(ledc_channel_config(&ledc_ch_config)); + + vTaskDelay(pdMS_TO_TICKS(50)); + + ledc_timer_pause(TEST_SPEED_MODE, LEDC_TIMER_0); + TEST_ESP_OK(ledc_channel_configure_maximum_timer_ovf_cnt(TEST_SPEED_MODE, LEDC_CHANNEL_0, 500)); + + esp_etm_channel_config_t etm_config = {}; + esp_etm_channel_handle_t etm_channel_a = NULL; + TEST_ESP_OK(esp_etm_new_channel(&etm_config, &etm_channel_a)); + + esp_etm_event_handle_t event_handle = NULL; + ledc_channel_etm_event_config_t event_config = { + .event_type = LEDC_CHANNEL_ETM_EVENT_REACH_MAX_OVF_CNT, + }; + TEST_ESP_OK(ledc_channel_new_etm_event(TEST_SPEED_MODE, LEDC_CHANNEL_0, &event_config, &event_handle)); + + esp_etm_task_handle_t task_handle_a = NULL; + ledc_timer_etm_task_config_t task_config_a = { + .task_type = LEDC_TIMER_ETM_TASK_PAUSE, + }; + TEST_ESP_OK(ledc_timer_new_etm_task(TEST_SPEED_MODE, LEDC_TIMER_0, &task_config_a, &task_handle_a)); + + TEST_ESP_OK(esp_etm_channel_connect(etm_channel_a, event_handle, task_handle_a)); + + TEST_ESP_OK(esp_etm_channel_enable(etm_channel_a)); + + // use UART auto baud rate detection feature to count the PWM pulse count + uart_bitrate_detect_config_t conf = { + .rx_io_num = PULSE_IO, + .source_clk = UART_SCLK_DEFAULT, + }; + uart_bitrate_res_t res = {}; + + uart_detect_bitrate_start(UART_NUM_1, &conf); + TEST_ESP_OK(ledc_timer_rst(TEST_SPEED_MODE, LEDC_TIMER_0)); + TEST_ESP_OK(ledc_timer_resume(TEST_SPEED_MODE, LEDC_TIMER_0)); + vTaskDelay(pdMS_TO_TICKS(500)); + uart_detect_bitrate_stop(UART_NUM_1, true, &res); + uint32_t pulse_count = (res.edge_cnt + 1) / 2; + TEST_ASSERT_INT32_WITHIN(1, 500, pulse_count); + + TEST_ESP_OK(esp_etm_channel_disable(etm_channel_a)); + + TEST_ESP_OK(esp_etm_del_event(event_handle)); + TEST_ESP_OK(esp_etm_del_task(task_handle_a)); + TEST_ESP_OK(esp_etm_del_channel(etm_channel_a)); +} diff --git a/components/esp_hw_support/etm/include/esp_private/etm_interface.h b/components/esp_hw_support/etm/include/esp_private/etm_interface.h index 5b22a38dea..720d70da65 100644 --- a/components/esp_hw_support/etm/include/esp_private/etm_interface.h +++ b/components/esp_hw_support/etm/include/esp_private/etm_interface.h @@ -30,6 +30,7 @@ typedef enum { ETM_TRIG_PERIPH_I2S, /*!< ETM trigger source: I2S */ ETM_TRIG_PERIPH_LP_CORE, /*!< ETM trigger source: Low-Power Core */ ETM_TRIG_PERIPH_MODEM, /*!< ETM trigger source: Modem */ + ETM_TRIG_PERIPH_LEDC, /*!< ETM trigger source: LEDC */ } etm_trigger_peripheral_t; /** diff --git a/components/hal/esp32c2/include/hal/ledc_ll.h b/components/hal/esp32c2/include/hal/ledc_ll.h index 2c415b4d92..2a4d1b21f3 100644 --- a/components/hal/esp32c2/include/hal/ledc_ll.h +++ b/components/hal/esp32c2/include/hal/ledc_ll.h @@ -20,10 +20,13 @@ extern "C" { #define LEDC_LL_GET_HW() &LEDC +#define LEDC_LL_CHANNEL_SUPPORT_OVF_CNT 1 + #define LEDC_LL_DUTY_NUM_MAX (LEDC_DUTY_NUM_CH0_V) #define LEDC_LL_DUTY_CYCLE_MAX (LEDC_DUTY_CYCLE_CH0_V) #define LEDC_LL_DUTY_SCALE_MAX (LEDC_DUTY_SCALE_CH0_V) #define LEDC_LL_HPOINT_VAL_MAX (LEDC_HPOINT_CH0_V) +#define LEDC_LL_OVF_CNT_MAX (LEDC_OVF_NUM_CH0_V + 1) #define LEDC_LL_FRACTIONAL_BITS (8) #define LEDC_LL_FRACTIONAL_MAX ((1 << LEDC_LL_FRACTIONAL_BITS) - 1) @@ -587,6 +590,51 @@ static inline void ledc_ll_get_channel_timer(ledc_dev_t *hw, ledc_mode_t speed_m *timer_sel = (ledc_timer_t)(hw->channel_group[speed_mode].channel[channel_num].conf0.timer_sel); } +/** + * @brief Enable or disable the timer overflow counter for the specified channel + * + * @param hw Beginning address of the peripheral registers + * @param speed_mode LEDC speed_mode, low-speed mode only + * @param channel LEDC channel index (0-5), select from ledc_channel_t + * @param enable True to enable; false to disable + * + * @return None + */ +static inline void ledc_ll_channel_enable_timer_ovt_cnt(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel, bool enable) +{ + hw->channel_group[speed_mode].channel[channel].conf0.ovf_cnt_en = enable; +} + +/** + * @brief Set the maximum timer overflow count for the specified channel + * + * @param hw Beginning address of the peripheral registers + * @param speed_mode LEDC speed_mode, low-speed mode only + * @param channel LEDC channel index (0-5), select from ledc_channel_t + * @param max_ovf_cnt The maximum timer overflow count + * + * @return None + */ +static inline void ledc_ll_channel_set_maximum_timer_ovf_cnt(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t max_ovf_cnt) +{ + HAL_ASSERT(max_ovf_cnt > 0 && max_ovf_cnt <= LEDC_LL_OVF_CNT_MAX); + hw->channel_group[speed_mode].channel[channel].conf0.ovf_num = max_ovf_cnt - 1; +} + +/** + * @brief Reset the timer overflow counter for the specified channel + * + * @param hw Beginning address of the peripheral registers + * @param speed_mode LEDC speed_mode, low-speed mode only + * @param channel LEDC channel index (0-5), select from ledc_channel_t + * + * @return None + */ +static inline void ledc_ll_channel_reset_timer_ovf_cnt(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel) +{ + hw->channel_group[speed_mode].channel[channel].conf0.ovf_cnt_reset = 1; +} + #ifdef __cplusplus } #endif diff --git a/components/hal/esp32c3/include/hal/ledc_ll.h b/components/hal/esp32c3/include/hal/ledc_ll.h index 6ed34c630d..c9d71ea1d8 100644 --- a/components/hal/esp32c3/include/hal/ledc_ll.h +++ b/components/hal/esp32c3/include/hal/ledc_ll.h @@ -21,10 +21,13 @@ extern "C" { #define LEDC_LL_GET_HW() &LEDC +#define LEDC_LL_CHANNEL_SUPPORT_OVF_CNT 1 + #define LEDC_LL_DUTY_NUM_MAX (LEDC_DUTY_NUM_LSCH0_V) #define LEDC_LL_DUTY_CYCLE_MAX (LEDC_DUTY_CYCLE_LSCH0_V) #define LEDC_LL_DUTY_SCALE_MAX (LEDC_DUTY_SCALE_LSCH0_V) #define LEDC_LL_HPOINT_VAL_MAX (LEDC_HPOINT_LSCH0_V) +#define LEDC_LL_OVF_CNT_MAX (LEDC_OVF_NUM_LSCH0_V + 1) #define LEDC_LL_FRACTIONAL_BITS (8) #define LEDC_LL_FRACTIONAL_MAX ((1 << LEDC_LL_FRACTIONAL_BITS) - 1) @@ -589,6 +592,51 @@ static inline void ledc_ll_get_channel_timer(ledc_dev_t *hw, ledc_mode_t speed_m *timer_sel = (ledc_timer_t)(hw->channel_group[speed_mode].channel[channel_num].conf0.timer_sel); } +/** + * @brief Enable or disable the timer overflow counter for the specified channel + * + * @param hw Beginning address of the peripheral registers + * @param speed_mode LEDC speed_mode, low-speed mode only + * @param channel LEDC channel index (0-5), select from ledc_channel_t + * @param enable True to enable; false to disable + * + * @return None + */ +static inline void ledc_ll_channel_enable_timer_ovt_cnt(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel, bool enable) +{ + hw->channel_group[speed_mode].channel[channel].conf0.ovf_cnt_en = enable; +} + +/** + * @brief Set the maximum timer overflow count for the specified channel + * + * @param hw Beginning address of the peripheral registers + * @param speed_mode LEDC speed_mode, low-speed mode only + * @param channel LEDC channel index (0-5), select from ledc_channel_t + * @param max_ovf_cnt The maximum timer overflow count + * + * @return None + */ +static inline void ledc_ll_channel_set_maximum_timer_ovf_cnt(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t max_ovf_cnt) +{ + HAL_ASSERT(max_ovf_cnt > 0 && max_ovf_cnt <= LEDC_LL_OVF_CNT_MAX); + hw->channel_group[speed_mode].channel[channel].conf0.ovf_num = max_ovf_cnt - 1; +} + +/** + * @brief Reset the timer overflow counter for the specified channel + * + * @param hw Beginning address of the peripheral registers + * @param speed_mode LEDC speed_mode, low-speed mode only + * @param channel LEDC channel index (0-5), select from ledc_channel_t + * + * @return None + */ +static inline void ledc_ll_channel_reset_timer_ovf_cnt(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel) +{ + hw->channel_group[speed_mode].channel[channel].conf0.ovf_cnt_rst = 1; +} + #ifdef __cplusplus } #endif diff --git a/components/hal/esp32c5/include/hal/ledc_ll.h b/components/hal/esp32c5/include/hal/ledc_ll.h index 977fb08e8f..0728be3f9a 100644 --- a/components/hal/esp32c5/include/hal/ledc_ll.h +++ b/components/hal/esp32c5/include/hal/ledc_ll.h @@ -16,6 +16,7 @@ #include "soc/clk_tree_defs.h" #include "soc/pcr_struct.h" #include "soc/soc_caps.h" +#include "soc/soc_etm_source.h" #ifdef __cplusplus extern "C" { @@ -23,14 +24,105 @@ extern "C" { #define LEDC_LL_GET_HW() &LEDC +#define LEDC_LL_CHANNEL_SUPPORT_OVF_CNT 1 + #define LEDC_LL_DUTY_NUM_MAX (LEDC_CH0_GAMMA_RANGE0_DUTY_NUM_V) #define LEDC_LL_DUTY_CYCLE_MAX (LEDC_CH0_GAMMA_RANGE0_DUTY_CYCLE_V) #define LEDC_LL_DUTY_SCALE_MAX (LEDC_CH0_GAMMA_RANGE0_SCALE_V) #define LEDC_LL_HPOINT_VAL_MAX (LEDC_HPOINT_CH0_V) +#define LEDC_LL_OVF_CNT_MAX (LEDC_OVF_NUM_CH0_V + 1) #define LEDC_LL_FRACTIONAL_BITS (8) #define LEDC_LL_FRACTIONAL_MAX ((1 << LEDC_LL_FRACTIONAL_BITS) - 1) #define LEDC_LL_GLOBAL_CLOCKS SOC_LEDC_CLKS +// Channel tasks: ID, enable register and bit +#define LEDC_LL_ETM_CHANNEL_TASK_ID(group, channel, task) \ + ((uint32_t [1][LEDC_CHANNEL_ETM_TASK_MAX]){{ \ + [LEDC_CHANNEL_ETM_TASK_FADE_SCALE_UPDATE] = LEDC_TASK_DUTY_SCALE_UPDATE_CH0, \ + [LEDC_CHANNEL_ETM_TASK_SIG_OUT_DIS] = LEDC_TASK_SIG_OUT_DIS_CH0, \ + [LEDC_CHANNEL_ETM_TASK_OVF_CNT_RST] = LEDC_TASK_OVF_CNT_RST_CH0, \ + [LEDC_CHANNEL_ETM_TASK_FADE_RESTART] = LEDC_TASK_GAMMA_RESTART_CH0, \ + [LEDC_CHANNEL_ETM_TASK_FADE_PAUSE] = LEDC_TASK_GAMMA_PAUSE_CH0, \ + [LEDC_CHANNEL_ETM_TASK_FADE_RESUME] = LEDC_TASK_GAMMA_RESUME_CH0, \ + }}[(group)][(task)] + (channel)) + +#define LEDC_LL_ETM_CHANNEL_TASK_EN_REG(group, task) \ + ((volatile uint32_t *[1][LEDC_CHANNEL_ETM_TASK_MAX]){{ \ + [LEDC_CHANNEL_ETM_TASK_FADE_SCALE_UPDATE] = (volatile uint32_t *)LEDC_EVT_TASK_EN0_REG, \ + [LEDC_CHANNEL_ETM_TASK_SIG_OUT_DIS] = (volatile uint32_t *)LEDC_EVT_TASK_EN1_REG, \ + [LEDC_CHANNEL_ETM_TASK_OVF_CNT_RST] = (volatile uint32_t *)LEDC_EVT_TASK_EN1_REG, \ + [LEDC_CHANNEL_ETM_TASK_FADE_RESTART] = (volatile uint32_t *)LEDC_EVT_TASK_EN2_REG, \ + [LEDC_CHANNEL_ETM_TASK_FADE_PAUSE] = (volatile uint32_t *)LEDC_EVT_TASK_EN2_REG, \ + [LEDC_CHANNEL_ETM_TASK_FADE_RESUME] = (volatile uint32_t *)LEDC_EVT_TASK_EN2_REG, \ + }}[(group)][(task)]) + +#define LEDC_LL_ETM_CHANNEL_TASK_EN_BIT(group, channel, task) \ + ((uint32_t [1][LEDC_CHANNEL_ETM_TASK_MAX]){{ \ + [LEDC_CHANNEL_ETM_TASK_FADE_SCALE_UPDATE] = BIT(LEDC_TASK_DUTY_SCALE_UPDATE_CH0_EN_S), \ + [LEDC_CHANNEL_ETM_TASK_SIG_OUT_DIS] = BIT(LEDC_TASK_SIG_OUT_DIS_CH0_EN_S), \ + [LEDC_CHANNEL_ETM_TASK_OVF_CNT_RST] = BIT(LEDC_TASK_OVF_CNT_RST_CH0_EN_S), \ + [LEDC_CHANNEL_ETM_TASK_FADE_RESTART] = BIT(LEDC_TASK_GAMMA_RESTART_CH0_EN_S), \ + [LEDC_CHANNEL_ETM_TASK_FADE_PAUSE] = BIT(LEDC_TASK_GAMMA_PAUSE_CH0_EN_S), \ + [LEDC_CHANNEL_ETM_TASK_FADE_RESUME] = BIT(LEDC_TASK_GAMMA_RESUME_CH0_EN_S), \ + }}[(group)][(task)] << (channel)) + +// Channel events: ID, enable register and bit +#define LEDC_LL_ETM_CHANNEL_EVENT_ID(group, channel, event) \ + ((uint32_t [1][LEDC_CHANNEL_ETM_EVENT_MAX]){{ \ + [LEDC_CHANNEL_ETM_EVENT_FADE_END] = LEDC_EVT_DUTY_CHNG_END_CH0, \ + [LEDC_CHANNEL_ETM_EVENT_REACH_MAX_OVF_CNT] = LEDC_EVT_OVF_CNT_PLS_CH0, \ + }}[(group)][(event)] + (channel)) + +#define LEDC_LL_ETM_CHANNEL_EVENT_EN_REG(group, event) \ + ((volatile uint32_t *[1][LEDC_CHANNEL_ETM_EVENT_MAX]){{ \ + [LEDC_CHANNEL_ETM_EVENT_FADE_END] = (volatile uint32_t *)LEDC_EVT_TASK_EN0_REG, \ + [LEDC_CHANNEL_ETM_EVENT_REACH_MAX_OVF_CNT] = (volatile uint32_t *)LEDC_EVT_TASK_EN0_REG, \ + }}[(group)][(event)]) + +#define LEDC_LL_ETM_CHANNEL_EVENT_EN_BIT(group, channel, event) \ + ((uint32_t [1][LEDC_CHANNEL_ETM_EVENT_MAX]){{ \ + [LEDC_CHANNEL_ETM_EVENT_FADE_END] = BIT(LEDC_EVT_DUTY_CHNG_END_CH0_EN_S), \ + [LEDC_CHANNEL_ETM_EVENT_REACH_MAX_OVF_CNT] = BIT(LEDC_EVT_OVF_CNT_PLS_CH0_EN_S), \ + }}[(group)][(event)] << (channel)) + +// Timer tasks: ID, enable register and bit +#define LEDC_LL_ETM_TIMER_TASK_ID(group, timer, task) \ + ((uint32_t [1][LEDC_TIMER_ETM_TASK_MAX]){{ \ + [LEDC_TIMER_ETM_TASK_RST] = LEDC_TASK_TIMER0_RST, \ + [LEDC_TIMER_ETM_TASK_RESUME] = LEDC_TASK_TIMER0_RESUME, \ + [LEDC_TIMER_ETM_TASK_PAUSE] = LEDC_TASK_TIMER0_PAUSE, \ + }}[(group)][(task)] + (timer)) + +#define LEDC_LL_ETM_TIMER_TASK_EN_REG(group, task) \ + ((volatile uint32_t *[1][LEDC_TIMER_ETM_TASK_MAX]){{ \ + [LEDC_TIMER_ETM_TASK_RST] = (volatile uint32_t *)LEDC_EVT_TASK_EN1_REG, \ + [LEDC_TIMER_ETM_TASK_RESUME] = (volatile uint32_t *)LEDC_EVT_TASK_EN1_REG, \ + [LEDC_TIMER_ETM_TASK_PAUSE] = (volatile uint32_t *)LEDC_EVT_TASK_EN1_REG, \ + }}[(group)][(task)]) + +#define LEDC_LL_ETM_TIMER_TASK_EN_BIT(group, timer, task) \ + ((uint32_t [1][LEDC_TIMER_ETM_TASK_MAX]){{ \ + [LEDC_TIMER_ETM_TASK_RST] = BIT(LEDC_TASK_TIMER0_RST_EN_S), \ + [LEDC_TIMER_ETM_TASK_RESUME] = BIT(LEDC_TASK_TIMER0_PAUSE_RESUME_EN_S), \ + [LEDC_TIMER_ETM_TASK_PAUSE] = BIT(LEDC_TASK_TIMER0_PAUSE_RESUME_EN_S), \ + }}[(group)][(task)] << (timer)) + +// Timer events: ID, enable register and bit +#define LEDC_LL_ETM_TIMER_EVENT_ID(group, timer, event) \ + ((uint32_t [1][LEDC_TIMER_ETM_EVENT_MAX]){{ \ + [LEDC_TIMER_ETM_EVENT_OVF] = LEDC_EVT_TIME_OVF_TIMER0, \ + }}[(group)][(event)] + (timer)) + +#define LEDC_LL_ETM_TIMER_EVENT_EN_REG(group, event) \ + ((volatile uint32_t *[1][LEDC_TIMER_ETM_EVENT_MAX]){{ \ + [LEDC_TIMER_ETM_EVENT_OVF] = (volatile uint32_t *)LEDC_EVT_TASK_EN0_REG, \ + }}[(group)][(event)]) + +#define LEDC_LL_ETM_TIMER_EVENT_EN_BIT(group, timer, event) \ + ((uint32_t [1][LEDC_TIMER_ETM_EVENT_MAX]){{ \ + [LEDC_TIMER_ETM_EVENT_OVF] = BIT(LEDC_EVT_TIME_OVF_TIMER0_EN_S), \ + }}[(group)][(event)] << (timer)) + /** * @brief Enable peripheral register clock * @@ -587,6 +679,69 @@ static inline void ledc_ll_get_channel_timer(ledc_dev_t *hw, ledc_mode_t speed_m *timer_sel = (ledc_timer_t)(hw->channel_group[speed_mode].channel[channel_num].conf0.timer_sel); } +/** + * @brief Enable or disable ETM event/task + * + * @param hw Beginning address of the peripheral registers + * @param speed_mode LEDC speed_mode, low-speed mode only + * @param reg_addr Register address to control the ETM event/task + * @param bit Bit position in the register + * @param enable Enable or disable the ETM event/task + */ +static inline void ledc_ll_etm_enable_evt_task(ledc_dev_t *hw, ledc_mode_t speed_mode, volatile uint32_t *reg_addr, uint32_t bit, bool enable) +{ + if (enable) { + REG_SET_BIT(reg_addr, bit); + } else { + REG_CLR_BIT(reg_addr, bit); + } +} + +/** + * @brief Enable or disable the timer overflow counter for the specified channel + * + * @param hw Beginning address of the peripheral registers + * @param speed_mode LEDC speed_mode, low-speed mode only + * @param channel LEDC channel index (0-5), select from ledc_channel_t + * @param enable True to enable; false to disable + * + * @return None + */ +static inline void ledc_ll_channel_enable_timer_ovt_cnt(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel, bool enable) +{ + hw->channel_group[speed_mode].channel[channel].conf0.ovf_cnt_en = enable; +} + +/** + * @brief Set the maximum timer overflow count for the specified channel + * + * @param hw Beginning address of the peripheral registers + * @param speed_mode LEDC speed_mode, low-speed mode only + * @param channel LEDC channel index (0-5), select from ledc_channel_t + * @param max_ovf_cnt The maximum timer overflow count + * + * @return None + */ +static inline void ledc_ll_channel_set_maximum_timer_ovf_cnt(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t max_ovf_cnt) +{ + HAL_ASSERT(max_ovf_cnt > 0 && max_ovf_cnt <= LEDC_LL_OVF_CNT_MAX); + hw->channel_group[speed_mode].channel[channel].conf0.ovf_num = max_ovf_cnt - 1; +} + +/** + * @brief Reset the timer overflow counter for the specified channel + * + * @param hw Beginning address of the peripheral registers + * @param speed_mode LEDC speed_mode, low-speed mode only + * @param channel LEDC channel index (0-5), select from ledc_channel_t + * + * @return None + */ +static inline void ledc_ll_channel_reset_timer_ovf_cnt(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel) +{ + hw->channel_group[speed_mode].channel[channel].conf0.ovf_cnt_reset = 1; +} + #ifdef __cplusplus } #endif diff --git a/components/hal/esp32c6/include/hal/ledc_ll.h b/components/hal/esp32c6/include/hal/ledc_ll.h index e3d691de20..d80a675e32 100644 --- a/components/hal/esp32c6/include/hal/ledc_ll.h +++ b/components/hal/esp32c6/include/hal/ledc_ll.h @@ -17,6 +17,7 @@ #include "hal/assert.h" #include "esp_rom_sys.h" //for sync issue workaround #include "soc/soc_caps.h" +#include "soc/soc_etm_source.h" #ifdef __cplusplus extern "C" { @@ -24,10 +25,13 @@ extern "C" { #define LEDC_LL_GET_HW() &LEDC +#define LEDC_LL_CHANNEL_SUPPORT_OVF_CNT 1 + #define LEDC_LL_DUTY_NUM_MAX (LEDC_CH0_GAMMA_DUTY_NUM_V) #define LEDC_LL_DUTY_CYCLE_MAX (LEDC_CH0_GAMMA_DUTY_CYCLE_V) #define LEDC_LL_DUTY_SCALE_MAX (LEDC_CH0_GAMMA_SCALE_V) #define LEDC_LL_HPOINT_VAL_MAX (LEDC_HPOINT_CH0_V) +#define LEDC_LL_OVF_CNT_MAX (LEDC_OVF_NUM_CH0_V + 1) #define LEDC_LL_FRACTIONAL_BITS (8) #define LEDC_LL_FRACTIONAL_MAX ((1 << LEDC_LL_FRACTIONAL_BITS) - 1) #define LEDC_LL_GLOBAL_CLOCKS SOC_LEDC_CLKS @@ -35,6 +39,94 @@ extern "C" { #define LEDC_LL_GLOBAL_CLK_NC_BY_DEFAULT 1 #define LEDC_LL_GLOBAL_CLK_DEFAULT LEDC_SLOW_CLK_RC_FAST // The temporal global clock source to set to at least make the LEDC core clock on +// Channel tasks: ID, enable register and bit +#define LEDC_LL_ETM_CHANNEL_TASK_ID(group, channel, task) \ + ((uint32_t [1][LEDC_CHANNEL_ETM_TASK_MAX]){{ \ + [LEDC_CHANNEL_ETM_TASK_FADE_SCALE_UPDATE] = LEDC_TASK_DUTY_SCALE_UPDATE_CH0, \ + [LEDC_CHANNEL_ETM_TASK_SIG_OUT_DIS] = LEDC_TASK_SIG_OUT_DIS_CH0, \ + [LEDC_CHANNEL_ETM_TASK_OVF_CNT_RST] = LEDC_TASK_OVF_CNT_RST_CH0, \ + [LEDC_CHANNEL_ETM_TASK_FADE_RESTART] = LEDC_TASK_GAMMA_RESTART_CH0, \ + [LEDC_CHANNEL_ETM_TASK_FADE_PAUSE] = LEDC_TASK_GAMMA_PAUSE_CH0, \ + [LEDC_CHANNEL_ETM_TASK_FADE_RESUME] = LEDC_TASK_GAMMA_RESUME_CH0, \ + }}[(group)][(task)] + (channel)) + +#define LEDC_LL_ETM_CHANNEL_TASK_EN_REG(group, task) \ + ((volatile uint32_t *[1][LEDC_CHANNEL_ETM_TASK_MAX]){{ \ + [LEDC_CHANNEL_ETM_TASK_FADE_SCALE_UPDATE] = (volatile uint32_t *)LEDC_EVT_TASK_EN0_REG, \ + [LEDC_CHANNEL_ETM_TASK_SIG_OUT_DIS] = (volatile uint32_t *)LEDC_EVT_TASK_EN1_REG, \ + [LEDC_CHANNEL_ETM_TASK_OVF_CNT_RST] = (volatile uint32_t *)LEDC_EVT_TASK_EN1_REG, \ + [LEDC_CHANNEL_ETM_TASK_FADE_RESTART] = (volatile uint32_t *)LEDC_EVT_TASK_EN2_REG, \ + [LEDC_CHANNEL_ETM_TASK_FADE_PAUSE] = (volatile uint32_t *)LEDC_EVT_TASK_EN2_REG, \ + [LEDC_CHANNEL_ETM_TASK_FADE_RESUME] = (volatile uint32_t *)LEDC_EVT_TASK_EN2_REG, \ + }}[(group)][(task)]) + +#define LEDC_LL_ETM_CHANNEL_TASK_EN_BIT(group, channel, task) \ + ((uint32_t [1][LEDC_CHANNEL_ETM_TASK_MAX]){{ \ + [LEDC_CHANNEL_ETM_TASK_FADE_SCALE_UPDATE] = BIT(LEDC_TASK_DUTY_SCALE_UPDATE_CH0_EN_S), \ + [LEDC_CHANNEL_ETM_TASK_SIG_OUT_DIS] = BIT(LEDC_TASK_SIG_OUT_DIS_CH0_EN_S), \ + [LEDC_CHANNEL_ETM_TASK_OVF_CNT_RST] = BIT(LEDC_TASK_OVF_CNT_RST_CH0_EN_S), \ + [LEDC_CHANNEL_ETM_TASK_FADE_RESTART] = BIT(LEDC_TASK_GAMMA_RESTART_CH0_EN_S), \ + [LEDC_CHANNEL_ETM_TASK_FADE_PAUSE] = BIT(LEDC_TASK_GAMMA_PAUSE_CH0_EN_S), \ + [LEDC_CHANNEL_ETM_TASK_FADE_RESUME] = BIT(LEDC_TASK_GAMMA_RESUME_CH0_EN_S), \ + }}[(group)][(task)] << (channel)) + +// Channel events: ID, enable register and bit +#define LEDC_LL_ETM_CHANNEL_EVENT_ID(group, channel, event) \ + ((uint32_t [1][LEDC_CHANNEL_ETM_EVENT_MAX]){{ \ + [LEDC_CHANNEL_ETM_EVENT_FADE_END] = LEDC_EVT_DUTY_CHNG_END_CH0, \ + [LEDC_CHANNEL_ETM_EVENT_REACH_MAX_OVF_CNT] = LEDC_EVT_OVF_CNT_PLS_CH0, \ + }}[(group)][(event)] + (channel)) + +#define LEDC_LL_ETM_CHANNEL_EVENT_EN_REG(group, event) \ + ((volatile uint32_t *[1][LEDC_CHANNEL_ETM_EVENT_MAX]){{ \ + [LEDC_CHANNEL_ETM_EVENT_FADE_END] = (volatile uint32_t *)LEDC_EVT_TASK_EN0_REG, \ + [LEDC_CHANNEL_ETM_EVENT_REACH_MAX_OVF_CNT] = (volatile uint32_t *)LEDC_EVT_TASK_EN0_REG, \ + }}[(group)][(event)]) + +#define LEDC_LL_ETM_CHANNEL_EVENT_EN_BIT(group, channel, event) \ + ((uint32_t [1][LEDC_CHANNEL_ETM_EVENT_MAX]){{ \ + [LEDC_CHANNEL_ETM_EVENT_FADE_END] = BIT(LEDC_EVT_DUTY_CHNG_END_CH0_EN_S), \ + [LEDC_CHANNEL_ETM_EVENT_REACH_MAX_OVF_CNT] = BIT(LEDC_EVT_OVF_CNT_PLS_CH0_EN_S), \ + }}[(group)][(event)] << (channel)) + +// Timer tasks: ID, enable register and bit +#define LEDC_LL_ETM_TIMER_TASK_ID(group, timer, task) \ + ((uint32_t [1][LEDC_TIMER_ETM_TASK_MAX]){{ \ + [LEDC_TIMER_ETM_TASK_RST] = LEDC_TASK_TIMER0_RST, \ + [LEDC_TIMER_ETM_TASK_RESUME] = LEDC_TASK_TIMER0_RESUME, \ + [LEDC_TIMER_ETM_TASK_PAUSE] = LEDC_TASK_TIMER0_PAUSE, \ + }}[(group)][(task)] + (timer)) + +#define LEDC_LL_ETM_TIMER_TASK_EN_REG(group, task) \ + ((volatile uint32_t *[1][LEDC_TIMER_ETM_TASK_MAX]){{ \ + [LEDC_TIMER_ETM_TASK_RST] = (volatile uint32_t *)LEDC_EVT_TASK_EN1_REG, \ + [LEDC_TIMER_ETM_TASK_RESUME] = (volatile uint32_t *)LEDC_EVT_TASK_EN1_REG, \ + [LEDC_TIMER_ETM_TASK_PAUSE] = (volatile uint32_t *)LEDC_EVT_TASK_EN1_REG, \ + }}[(group)][(task)]) + +#define LEDC_LL_ETM_TIMER_TASK_EN_BIT(group, timer, task) \ + ((uint32_t [1][LEDC_TIMER_ETM_TASK_MAX]){{ \ + [LEDC_TIMER_ETM_TASK_RST] = BIT(LEDC_TASK_TIMER0_RST_EN_S), \ + [LEDC_TIMER_ETM_TASK_RESUME] = BIT(LEDC_TASK_TIMER0_PAUSE_RESUME_EN_S), \ + [LEDC_TIMER_ETM_TASK_PAUSE] = BIT(LEDC_TASK_TIMER0_PAUSE_RESUME_EN_S), \ + }}[(group)][(task)] << (timer)) + +// Timer events: ID, enable register and bit +#define LEDC_LL_ETM_TIMER_EVENT_ID(group, timer, event) \ + ((uint32_t [1][LEDC_TIMER_ETM_EVENT_MAX]){{ \ + [LEDC_TIMER_ETM_EVENT_OVF] = LEDC_EVT_TIME_OVF_TIMER0, \ + }}[(group)][(event)] + (timer)) + +#define LEDC_LL_ETM_TIMER_EVENT_EN_REG(group, event) \ + ((volatile uint32_t *[1][LEDC_TIMER_ETM_EVENT_MAX]){{ \ + [LEDC_TIMER_ETM_EVENT_OVF] = (volatile uint32_t *)LEDC_EVT_TASK_EN0_REG, \ + }}[(group)][(event)]) + +#define LEDC_LL_ETM_TIMER_EVENT_EN_BIT(group, timer, event) \ + ((uint32_t [1][LEDC_TIMER_ETM_EVENT_MAX]){{ \ + [LEDC_TIMER_ETM_EVENT_OVF] = BIT(LEDC_EVT_TIME_OVF_TIMER0_EN_S), \ + }}[(group)][(event)] << (timer)) + /** * @brief Enable peripheral register clock * @@ -709,6 +801,69 @@ static inline void ledc_ll_get_channel_timer(ledc_dev_t *hw, ledc_mode_t speed_m *timer_sel = (ledc_timer_t)(hw->channel_group[speed_mode].channel[channel_num].conf0.timer_sel); } +/** + * @brief Enable or disable ETM event/task + * + * @param hw Beginning address of the peripheral registers + * @param speed_mode LEDC speed_mode, low-speed mode only + * @param reg_addr Register address to control the ETM event/task + * @param bit Bit position in the register + * @param enable Enable or disable the ETM event/task + */ +static inline void ledc_ll_etm_enable_evt_task(ledc_dev_t *hw, ledc_mode_t speed_mode, volatile uint32_t *reg_addr, uint32_t bit, bool enable) +{ + if (enable) { + REG_SET_BIT(reg_addr, bit); + } else { + REG_CLR_BIT(reg_addr, bit); + } +} + +/** + * @brief Enable or disable the timer overflow counter for the specified channel + * + * @param hw Beginning address of the peripheral registers + * @param speed_mode LEDC speed_mode, low-speed mode only + * @param channel LEDC channel index (0-5), select from ledc_channel_t + * @param enable True to enable; false to disable + * + * @return None + */ +static inline void ledc_ll_channel_enable_timer_ovt_cnt(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel, bool enable) +{ + hw->channel_group[speed_mode].channel[channel].conf0.ovf_cnt_en = enable; +} + +/** + * @brief Set the maximum timer overflow count for the specified channel + * + * @param hw Beginning address of the peripheral registers + * @param speed_mode LEDC speed_mode, low-speed mode only + * @param channel LEDC channel index (0-5), select from ledc_channel_t + * @param max_ovf_cnt The maximum timer overflow count + * + * @return None + */ +static inline void ledc_ll_channel_set_maximum_timer_ovf_cnt(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t max_ovf_cnt) +{ + HAL_ASSERT(max_ovf_cnt > 0 && max_ovf_cnt <= LEDC_LL_OVF_CNT_MAX); + hw->channel_group[speed_mode].channel[channel].conf0.ovf_num = max_ovf_cnt - 1; +} + +/** + * @brief Reset the timer overflow counter for the specified channel + * + * @param hw Beginning address of the peripheral registers + * @param speed_mode LEDC speed_mode, low-speed mode only + * @param channel LEDC channel index (0-5), select from ledc_channel_t + * + * @return None + */ +static inline void ledc_ll_channel_reset_timer_ovf_cnt(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel) +{ + hw->channel_group[speed_mode].channel[channel].conf0.ovf_cnt_reset = 1; +} + #ifdef __cplusplus } #endif diff --git a/components/hal/esp32c61/include/hal/ledc_ll.h b/components/hal/esp32c61/include/hal/ledc_ll.h index 333238be17..0f00af8dc4 100644 --- a/components/hal/esp32c61/include/hal/ledc_ll.h +++ b/components/hal/esp32c61/include/hal/ledc_ll.h @@ -16,6 +16,7 @@ #include "soc/clk_tree_defs.h" #include "soc/pcr_struct.h" #include "soc/soc_caps.h" +#include "soc/soc_etm_source.h" #ifdef __cplusplus extern "C" { @@ -23,14 +24,105 @@ extern "C" { #define LEDC_LL_GET_HW() &LEDC +#define LEDC_LL_CHANNEL_SUPPORT_OVF_CNT 1 + #define LEDC_LL_DUTY_NUM_MAX (LEDC_CH0_GAMMA_RANGE0_DUTY_NUM_V) #define LEDC_LL_DUTY_CYCLE_MAX (LEDC_CH0_GAMMA_RANGE0_DUTY_CYCLE_V) #define LEDC_LL_DUTY_SCALE_MAX (LEDC_CH0_GAMMA_RANGE0_SCALE_V) #define LEDC_LL_HPOINT_VAL_MAX (LEDC_HPOINT_CH0_V) +#define LEDC_LL_OVF_CNT_MAX (LEDC_OVF_NUM_CH0_V + 1) #define LEDC_LL_FRACTIONAL_BITS (8) #define LEDC_LL_FRACTIONAL_MAX ((1 << LEDC_LL_FRACTIONAL_BITS) - 1) #define LEDC_LL_GLOBAL_CLOCKS SOC_LEDC_CLKS +// Channel tasks: ID, enable register and bit +#define LEDC_LL_ETM_CHANNEL_TASK_ID(group, channel, task) \ + ((uint32_t [1][LEDC_CHANNEL_ETM_TASK_MAX]){{ \ + [LEDC_CHANNEL_ETM_TASK_FADE_SCALE_UPDATE] = LEDC_TASK_DUTY_SCALE_UPDATE_CH0, \ + [LEDC_CHANNEL_ETM_TASK_SIG_OUT_DIS] = LEDC_TASK_SIG_OUT_DIS_CH0, \ + [LEDC_CHANNEL_ETM_TASK_OVF_CNT_RST] = LEDC_TASK_OVF_CNT_RST_CH0, \ + [LEDC_CHANNEL_ETM_TASK_FADE_RESTART] = LEDC_TASK_GAMMA_RESTART_CH0, \ + [LEDC_CHANNEL_ETM_TASK_FADE_PAUSE] = LEDC_TASK_GAMMA_PAUSE_CH0, \ + [LEDC_CHANNEL_ETM_TASK_FADE_RESUME] = LEDC_TASK_GAMMA_RESUME_CH0, \ + }}[(group)][(task)] + (channel)) + +#define LEDC_LL_ETM_CHANNEL_TASK_EN_REG(group, task) \ + ((volatile uint32_t *[1][LEDC_CHANNEL_ETM_TASK_MAX]){{ \ + [LEDC_CHANNEL_ETM_TASK_FADE_SCALE_UPDATE] = (volatile uint32_t *)LEDC_EVT_TASK_EN0_REG, \ + [LEDC_CHANNEL_ETM_TASK_SIG_OUT_DIS] = (volatile uint32_t *)LEDC_EVT_TASK_EN1_REG, \ + [LEDC_CHANNEL_ETM_TASK_OVF_CNT_RST] = (volatile uint32_t *)LEDC_EVT_TASK_EN1_REG, \ + [LEDC_CHANNEL_ETM_TASK_FADE_RESTART] = (volatile uint32_t *)LEDC_EVT_TASK_EN2_REG, \ + [LEDC_CHANNEL_ETM_TASK_FADE_PAUSE] = (volatile uint32_t *)LEDC_EVT_TASK_EN2_REG, \ + [LEDC_CHANNEL_ETM_TASK_FADE_RESUME] = (volatile uint32_t *)LEDC_EVT_TASK_EN2_REG, \ + }}[(group)][(task)]) + +#define LEDC_LL_ETM_CHANNEL_TASK_EN_BIT(group, channel, task) \ + ((uint32_t [1][LEDC_CHANNEL_ETM_TASK_MAX]){{ \ + [LEDC_CHANNEL_ETM_TASK_FADE_SCALE_UPDATE] = BIT(LEDC_TASK_DUTY_SCALE_UPDATE_CH0_EN_S), \ + [LEDC_CHANNEL_ETM_TASK_SIG_OUT_DIS] = BIT(LEDC_TASK_SIG_OUT_DIS_CH0_EN_S), \ + [LEDC_CHANNEL_ETM_TASK_OVF_CNT_RST] = BIT(LEDC_TASK_OVF_CNT_RST_CH0_EN_S), \ + [LEDC_CHANNEL_ETM_TASK_FADE_RESTART] = BIT(LEDC_TASK_GAMMA_RESTART_CH0_EN_S), \ + [LEDC_CHANNEL_ETM_TASK_FADE_PAUSE] = BIT(LEDC_TASK_GAMMA_PAUSE_CH0_EN_S), \ + [LEDC_CHANNEL_ETM_TASK_FADE_RESUME] = BIT(LEDC_TASK_GAMMA_RESUME_CH0_EN_S), \ + }}[(group)][(task)] << (channel)) + +// Channel events: ID, enable register and bit +#define LEDC_LL_ETM_CHANNEL_EVENT_ID(group, channel, event) \ + ((uint32_t [1][LEDC_CHANNEL_ETM_EVENT_MAX]){{ \ + [LEDC_CHANNEL_ETM_EVENT_FADE_END] = LEDC_EVT_DUTY_CHNG_END_CH0, \ + [LEDC_CHANNEL_ETM_EVENT_REACH_MAX_OVF_CNT] = LEDC_EVT_OVF_CNT_PLS_CH0, \ + }}[(group)][(event)] + (channel)) + +#define LEDC_LL_ETM_CHANNEL_EVENT_EN_REG(group, event) \ + ((volatile uint32_t *[1][LEDC_CHANNEL_ETM_EVENT_MAX]){{ \ + [LEDC_CHANNEL_ETM_EVENT_FADE_END] = (volatile uint32_t *)LEDC_EVT_TASK_EN0_REG, \ + [LEDC_CHANNEL_ETM_EVENT_REACH_MAX_OVF_CNT] = (volatile uint32_t *)LEDC_EVT_TASK_EN0_REG, \ + }}[(group)][(event)]) + +#define LEDC_LL_ETM_CHANNEL_EVENT_EN_BIT(group, channel, event) \ + ((uint32_t [1][LEDC_CHANNEL_ETM_EVENT_MAX]){{ \ + [LEDC_CHANNEL_ETM_EVENT_FADE_END] = BIT(LEDC_EVT_DUTY_CHNG_END_CH0_EN_S), \ + [LEDC_CHANNEL_ETM_EVENT_REACH_MAX_OVF_CNT] = BIT(LEDC_EVT_OVF_CNT_PLS_CH0_EN_S), \ + }}[(group)][(event)] << (channel)) + +// Timer tasks: ID, enable register and bit +#define LEDC_LL_ETM_TIMER_TASK_ID(group, timer, task) \ + ((uint32_t [1][LEDC_TIMER_ETM_TASK_MAX]){{ \ + [LEDC_TIMER_ETM_TASK_RST] = LEDC_TASK_TIMER0_RST, \ + [LEDC_TIMER_ETM_TASK_RESUME] = LEDC_TASK_TIMER0_RESUME, \ + [LEDC_TIMER_ETM_TASK_PAUSE] = LEDC_TASK_TIMER0_PAUSE, \ + }}[(group)][(task)] + (timer)) + +#define LEDC_LL_ETM_TIMER_TASK_EN_REG(group, task) \ + ((volatile uint32_t *[1][LEDC_TIMER_ETM_TASK_MAX]){{ \ + [LEDC_TIMER_ETM_TASK_RST] = (volatile uint32_t *)LEDC_EVT_TASK_EN1_REG, \ + [LEDC_TIMER_ETM_TASK_RESUME] = (volatile uint32_t *)LEDC_EVT_TASK_EN1_REG, \ + [LEDC_TIMER_ETM_TASK_PAUSE] = (volatile uint32_t *)LEDC_EVT_TASK_EN1_REG, \ + }}[(group)][(task)]) + +#define LEDC_LL_ETM_TIMER_TASK_EN_BIT(group, timer, task) \ + ((uint32_t [1][LEDC_TIMER_ETM_TASK_MAX]){{ \ + [LEDC_TIMER_ETM_TASK_RST] = BIT(LEDC_TASK_TIMER0_RST_EN_S), \ + [LEDC_TIMER_ETM_TASK_RESUME] = BIT(LEDC_TASK_TIMER0_PAUSE_RESUME_EN_S), \ + [LEDC_TIMER_ETM_TASK_PAUSE] = BIT(LEDC_TASK_TIMER0_PAUSE_RESUME_EN_S), \ + }}[(group)][(task)] << (timer)) + +// Timer events: ID, enable register and bit +#define LEDC_LL_ETM_TIMER_EVENT_ID(group, timer, event) \ + ((uint32_t [1][LEDC_TIMER_ETM_EVENT_MAX]){{ \ + [LEDC_TIMER_ETM_EVENT_OVF] = LEDC_EVT_TIME_OVF_TIMER0, \ + }}[(group)][(event)] + (timer)) + +#define LEDC_LL_ETM_TIMER_EVENT_EN_REG(group, event) \ + ((volatile uint32_t *[1][LEDC_TIMER_ETM_EVENT_MAX]){{ \ + [LEDC_TIMER_ETM_EVENT_OVF] = (volatile uint32_t *)LEDC_EVT_TASK_EN0_REG, \ + }}[(group)][(event)]) + +#define LEDC_LL_ETM_TIMER_EVENT_EN_BIT(group, timer, event) \ + ((uint32_t [1][LEDC_TIMER_ETM_EVENT_MAX]){{ \ + [LEDC_TIMER_ETM_EVENT_OVF] = BIT(LEDC_EVT_TIME_OVF_TIMER0_EN_S), \ + }}[(group)][(event)] << (timer)) + /** * @brief Enable peripheral register clock * @@ -587,6 +679,71 @@ static inline void ledc_ll_get_channel_timer(ledc_dev_t *hw, ledc_mode_t speed_m *timer_sel = (ledc_timer_t)(hw->channel_group[speed_mode].channel[channel_num].conf0.timer_sel); } +/** + * @brief Enable or disable ETM event/task + * + * @param hw Beginning address of the peripheral registers + * @param speed_mode LEDC speed_mode, low-speed mode only + * @param reg_addr Register address to control the ETM event/task + * @param bit Bit position in the register + * @param enable Enable or disable the ETM event/task + * + * @return None + */ +static inline void ledc_ll_etm_enable_evt_task(ledc_dev_t *hw, ledc_mode_t speed_mode, volatile uint32_t *reg_addr, uint32_t bit, bool enable) +{ + if (enable) { + REG_SET_BIT(reg_addr, bit); + } else { + REG_CLR_BIT(reg_addr, bit); + } +} + +/** + * @brief Enable or disable the timer overflow counter for the specified channel + * + * @param hw Beginning address of the peripheral registers + * @param speed_mode LEDC speed_mode, low-speed mode only + * @param channel LEDC channel index (0-5), select from ledc_channel_t + * @param enable True to enable; false to disable + * + * @return None + */ +static inline void ledc_ll_channel_enable_timer_ovt_cnt(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel, bool enable) +{ + hw->channel_group[speed_mode].channel[channel].conf0.ovf_cnt_en = enable; +} + +/** + * @brief Set the maximum timer overflow count for the specified channel + * + * @param hw Beginning address of the peripheral registers + * @param speed_mode LEDC speed_mode, low-speed mode only + * @param channel LEDC channel index (0-5), select from ledc_channel_t + * @param max_ovf_cnt The maximum timer overflow count + * + * @return None + */ +static inline void ledc_ll_channel_set_maximum_timer_ovf_cnt(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t max_ovf_cnt) +{ + HAL_ASSERT(max_ovf_cnt > 0 && max_ovf_cnt <= LEDC_LL_OVF_CNT_MAX); + hw->channel_group[speed_mode].channel[channel].conf0.ovf_num = max_ovf_cnt - 1; +} + +/** + * @brief Reset the timer overflow counter for the specified channel + * + * @param hw Beginning address of the peripheral registers + * @param speed_mode LEDC speed_mode, low-speed mode only + * @param channel LEDC channel index (0-5), select from ledc_channel_t + * + * @return None + */ +static inline void ledc_ll_channel_reset_timer_ovf_cnt(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel) +{ + hw->channel_group[speed_mode].channel[channel].conf0.ovf_cnt_reset = 1; +} + #ifdef __cplusplus } #endif diff --git a/components/hal/esp32h2/include/hal/ledc_ll.h b/components/hal/esp32h2/include/hal/ledc_ll.h index d17c51b037..ee79b47b7d 100644 --- a/components/hal/esp32h2/include/hal/ledc_ll.h +++ b/components/hal/esp32h2/include/hal/ledc_ll.h @@ -17,6 +17,7 @@ #include "hal/assert.h" #include "esp_rom_sys.h" //for sync issue workaround #include "soc/soc_caps.h" +#include "soc/soc_etm_source.h" #ifdef __cplusplus extern "C" { @@ -24,14 +25,105 @@ extern "C" { #define LEDC_LL_GET_HW() &LEDC +#define LEDC_LL_CHANNEL_SUPPORT_OVF_CNT 1 + #define LEDC_LL_DUTY_NUM_MAX (LEDC_CH0_GAMMA_DUTY_NUM_V) #define LEDC_LL_DUTY_CYCLE_MAX (LEDC_CH0_GAMMA_DUTY_CYCLE_V) #define LEDC_LL_DUTY_SCALE_MAX (LEDC_CH0_GAMMA_SCALE_V) #define LEDC_LL_HPOINT_VAL_MAX (LEDC_HPOINT_CH0_V) +#define LEDC_LL_OVF_CNT_MAX (LEDC_OVF_NUM_CH0_V + 1) #define LEDC_LL_FRACTIONAL_BITS (8) #define LEDC_LL_FRACTIONAL_MAX ((1 << LEDC_LL_FRACTIONAL_BITS) - 1) #define LEDC_LL_GLOBAL_CLOCKS SOC_LEDC_CLKS +// Channel tasks: ID, enable register and bit +#define LEDC_LL_ETM_CHANNEL_TASK_ID(group, channel, task) \ + ((uint32_t [1][LEDC_CHANNEL_ETM_TASK_MAX]){{ \ + [LEDC_CHANNEL_ETM_TASK_FADE_SCALE_UPDATE] = LEDC_TASK_DUTY_SCALE_UPDATE_CH0, \ + [LEDC_CHANNEL_ETM_TASK_SIG_OUT_DIS] = LEDC_TASK_SIG_OUT_DIS_CH0, \ + [LEDC_CHANNEL_ETM_TASK_OVF_CNT_RST] = LEDC_TASK_OVF_CNT_RST_CH0, \ + [LEDC_CHANNEL_ETM_TASK_FADE_RESTART] = LEDC_TASK_GAMMA_RESTART_CH0, \ + [LEDC_CHANNEL_ETM_TASK_FADE_PAUSE] = LEDC_TASK_GAMMA_PAUSE_CH0, \ + [LEDC_CHANNEL_ETM_TASK_FADE_RESUME] = LEDC_TASK_GAMMA_RESUME_CH0, \ + }}[(group)][(task)] + (channel)) + +#define LEDC_LL_ETM_CHANNEL_TASK_EN_REG(group, task) \ + ((volatile uint32_t *[1][LEDC_CHANNEL_ETM_TASK_MAX]){{ \ + [LEDC_CHANNEL_ETM_TASK_FADE_SCALE_UPDATE] = (volatile uint32_t *)LEDC_EVT_TASK_EN0_REG, \ + [LEDC_CHANNEL_ETM_TASK_SIG_OUT_DIS] = (volatile uint32_t *)LEDC_EVT_TASK_EN1_REG, \ + [LEDC_CHANNEL_ETM_TASK_OVF_CNT_RST] = (volatile uint32_t *)LEDC_EVT_TASK_EN1_REG, \ + [LEDC_CHANNEL_ETM_TASK_FADE_RESTART] = (volatile uint32_t *)LEDC_EVT_TASK_EN2_REG, \ + [LEDC_CHANNEL_ETM_TASK_FADE_PAUSE] = (volatile uint32_t *)LEDC_EVT_TASK_EN2_REG, \ + [LEDC_CHANNEL_ETM_TASK_FADE_RESUME] = (volatile uint32_t *)LEDC_EVT_TASK_EN2_REG, \ + }}[(group)][(task)]) + +#define LEDC_LL_ETM_CHANNEL_TASK_EN_BIT(group, channel, task) \ + ((uint32_t [1][LEDC_CHANNEL_ETM_TASK_MAX]){{ \ + [LEDC_CHANNEL_ETM_TASK_FADE_SCALE_UPDATE] = BIT(LEDC_TASK_DUTY_SCALE_UPDATE_CH0_EN_S), \ + [LEDC_CHANNEL_ETM_TASK_SIG_OUT_DIS] = BIT(LEDC_TASK_SIG_OUT_DIS_CH0_EN_S), \ + [LEDC_CHANNEL_ETM_TASK_OVF_CNT_RST] = BIT(LEDC_TASK_OVF_CNT_RST_CH0_EN_S), \ + [LEDC_CHANNEL_ETM_TASK_FADE_RESTART] = BIT(LEDC_TASK_GAMMA_RESTART_CH0_EN_S), \ + [LEDC_CHANNEL_ETM_TASK_FADE_PAUSE] = BIT(LEDC_TASK_GAMMA_PAUSE_CH0_EN_S), \ + [LEDC_CHANNEL_ETM_TASK_FADE_RESUME] = BIT(LEDC_TASK_GAMMA_RESUME_CH0_EN_S), \ + }}[(group)][(task)] << (channel)) + +// Channel events: ID, enable register and bit +#define LEDC_LL_ETM_CHANNEL_EVENT_ID(group, channel, event) \ + ((uint32_t [1][LEDC_CHANNEL_ETM_EVENT_MAX]){{ \ + [LEDC_CHANNEL_ETM_EVENT_FADE_END] = LEDC_EVT_DUTY_CHNG_END_CH0, \ + [LEDC_CHANNEL_ETM_EVENT_REACH_MAX_OVF_CNT] = LEDC_EVT_OVF_CNT_PLS_CH0, \ + }}[(group)][(event)] + (channel)) + +#define LEDC_LL_ETM_CHANNEL_EVENT_EN_REG(group, event) \ + ((volatile uint32_t *[1][LEDC_CHANNEL_ETM_EVENT_MAX]){{ \ + [LEDC_CHANNEL_ETM_EVENT_FADE_END] = (volatile uint32_t *)LEDC_EVT_TASK_EN0_REG, \ + [LEDC_CHANNEL_ETM_EVENT_REACH_MAX_OVF_CNT] = (volatile uint32_t *)LEDC_EVT_TASK_EN0_REG, \ + }}[(group)][(event)]) + +#define LEDC_LL_ETM_CHANNEL_EVENT_EN_BIT(group, channel, event) \ + ((uint32_t [1][LEDC_CHANNEL_ETM_EVENT_MAX]){{ \ + [LEDC_CHANNEL_ETM_EVENT_FADE_END] = BIT(LEDC_EVT_DUTY_CHNG_END_CH0_EN_S), \ + [LEDC_CHANNEL_ETM_EVENT_REACH_MAX_OVF_CNT] = BIT(LEDC_EVT_OVF_CNT_PLS_CH0_EN_S), \ + }}[(group)][(event)] << (channel)) + +// Timer tasks: ID, enable register and bit +#define LEDC_LL_ETM_TIMER_TASK_ID(group, timer, task) \ + ((uint32_t [1][LEDC_TIMER_ETM_TASK_MAX]){{ \ + [LEDC_TIMER_ETM_TASK_RST] = LEDC_TASK_TIMER0_RST, \ + [LEDC_TIMER_ETM_TASK_RESUME] = LEDC_TASK_TIMER0_RESUME, \ + [LEDC_TIMER_ETM_TASK_PAUSE] = LEDC_TASK_TIMER0_PAUSE, \ + }}[(group)][(task)] + (timer)) + +#define LEDC_LL_ETM_TIMER_TASK_EN_REG(group, task) \ + ((volatile uint32_t *[1][LEDC_TIMER_ETM_TASK_MAX]){{ \ + [LEDC_TIMER_ETM_TASK_RST] = (volatile uint32_t *)LEDC_EVT_TASK_EN1_REG, \ + [LEDC_TIMER_ETM_TASK_RESUME] = (volatile uint32_t *)LEDC_EVT_TASK_EN1_REG, \ + [LEDC_TIMER_ETM_TASK_PAUSE] = (volatile uint32_t *)LEDC_EVT_TASK_EN1_REG, \ + }}[(group)][(task)]) + +#define LEDC_LL_ETM_TIMER_TASK_EN_BIT(group, timer, task) \ + ((uint32_t [1][LEDC_TIMER_ETM_TASK_MAX]){{ \ + [LEDC_TIMER_ETM_TASK_RST] = BIT(LEDC_TASK_TIMER0_RST_EN_S), \ + [LEDC_TIMER_ETM_TASK_RESUME] = BIT(LEDC_TASK_TIMER0_PAUSE_RESUME_EN_S), \ + [LEDC_TIMER_ETM_TASK_PAUSE] = BIT(LEDC_TASK_TIMER0_PAUSE_RESUME_EN_S), \ + }}[(group)][(task)] << (timer)) + +// Timer events: ID, enable register and bit +#define LEDC_LL_ETM_TIMER_EVENT_ID(group, timer, event) \ + ((uint32_t [1][LEDC_TIMER_ETM_EVENT_MAX]){{ \ + [LEDC_TIMER_ETM_EVENT_OVF] = LEDC_EVT_TIME_OVF_TIMER0, \ + }}[(group)][(event)] + (timer)) + +#define LEDC_LL_ETM_TIMER_EVENT_EN_REG(group, event) \ + ((volatile uint32_t *[1][LEDC_TIMER_ETM_EVENT_MAX]){{ \ + [LEDC_TIMER_ETM_EVENT_OVF] = (volatile uint32_t *)LEDC_EVT_TASK_EN0_REG, \ + }}[(group)][(event)]) + +#define LEDC_LL_ETM_TIMER_EVENT_EN_BIT(group, timer, event) \ + ((uint32_t [1][LEDC_TIMER_ETM_EVENT_MAX]){{ \ + [LEDC_TIMER_ETM_EVENT_OVF] = BIT(LEDC_EVT_TIME_OVF_TIMER0_EN_S), \ + }}[(group)][(event)] << (timer)) + /** * @brief Enable peripheral register clock * @@ -706,6 +798,69 @@ static inline void ledc_ll_get_channel_timer(ledc_dev_t *hw, ledc_mode_t speed_m *timer_sel = (ledc_timer_t)(hw->channel_group[speed_mode].channel[channel_num].conf0.timer_sel); } +/** + * @brief Enable or disable ETM event/task + * + * @param hw Beginning address of the peripheral registers + * @param speed_mode LEDC speed_mode, low-speed mode only + * @param reg_addr Register address to control the ETM event/task + * @param bit Bit position in the register + * @param enable Enable or disable the ETM event/task + */ +static inline void ledc_ll_etm_enable_evt_task(ledc_dev_t *hw, ledc_mode_t speed_mode, volatile uint32_t *reg_addr, uint32_t bit, bool enable) +{ + if (enable) { + REG_SET_BIT(reg_addr, bit); + } else { + REG_CLR_BIT(reg_addr, bit); + } +} + +/** + * @brief Enable or disable the timer overflow counter for the specified channel + * + * @param hw Beginning address of the peripheral registers + * @param speed_mode LEDC speed_mode, low-speed mode only + * @param channel LEDC channel index (0-5), select from ledc_channel_t + * @param enable True to enable; false to disable + * + * @return None + */ +static inline void ledc_ll_channel_enable_timer_ovt_cnt(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel, bool enable) +{ + hw->channel_group[speed_mode].channel[channel].conf0.ovf_cnt_en = enable; +} + +/** + * @brief Set the maximum timer overflow count for the specified channel + * + * @param hw Beginning address of the peripheral registers + * @param speed_mode LEDC speed_mode, low-speed mode only + * @param channel LEDC channel index (0-5), select from ledc_channel_t + * @param max_ovf_cnt The maximum timer overflow count + * + * @return None + */ +static inline void ledc_ll_channel_set_maximum_timer_ovf_cnt(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t max_ovf_cnt) +{ + HAL_ASSERT(max_ovf_cnt > 0 && max_ovf_cnt <= LEDC_LL_OVF_CNT_MAX); + hw->channel_group[speed_mode].channel[channel].conf0.ovf_num = max_ovf_cnt - 1; +} + +/** + * @brief Reset the timer overflow counter for the specified channel + * + * @param hw Beginning address of the peripheral registers + * @param speed_mode LEDC speed_mode, low-speed mode only + * @param channel LEDC channel index (0-5), select from ledc_channel_t + * + * @return None + */ +static inline void ledc_ll_channel_reset_timer_ovf_cnt(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel) +{ + hw->channel_group[speed_mode].channel[channel].conf0.ovf_cnt_reset = 1; +} + #ifdef __cplusplus } #endif diff --git a/components/hal/esp32h21/include/hal/ledc_ll.h b/components/hal/esp32h21/include/hal/ledc_ll.h index 2e4f6e5840..db4c06031e 100644 --- a/components/hal/esp32h21/include/hal/ledc_ll.h +++ b/components/hal/esp32h21/include/hal/ledc_ll.h @@ -17,6 +17,7 @@ #include "hal/assert.h" #include "esp_rom_sys.h" //for sync issue workaround #include "soc/soc_caps.h" +#include "soc/soc_etm_source.h" #ifdef __cplusplus extern "C" { @@ -24,14 +25,105 @@ extern "C" { #define LEDC_LL_GET_HW() &LEDC +#define LEDC_LL_CHANNEL_SUPPORT_OVF_CNT 1 + #define LEDC_LL_DUTY_NUM_MAX (LEDC_CH0_GAMMA_DUTY_NUM_V) #define LEDC_LL_DUTY_CYCLE_MAX (LEDC_CH0_GAMMA_DUTY_CYCLE_V) #define LEDC_LL_DUTY_SCALE_MAX (LEDC_CH0_GAMMA_SCALE_V) #define LEDC_LL_HPOINT_VAL_MAX (LEDC_HPOINT_CH0_V) +#define LEDC_LL_OVF_CNT_MAX (LEDC_OVF_NUM_CH0_V + 1) #define LEDC_LL_FRACTIONAL_BITS (8) #define LEDC_LL_FRACTIONAL_MAX ((1 << LEDC_LL_FRACTIONAL_BITS) - 1) #define LEDC_LL_GLOBAL_CLOCKS SOC_LEDC_CLKS +// Channel tasks: ID, enable register and bit +#define LEDC_LL_ETM_CHANNEL_TASK_ID(group, channel, task) \ + ((uint32_t [1][LEDC_CHANNEL_ETM_TASK_MAX]){{ \ + [LEDC_CHANNEL_ETM_TASK_FADE_SCALE_UPDATE] = LEDC_TASK_DUTY_SCALE_UPDATE_CH0, \ + [LEDC_CHANNEL_ETM_TASK_SIG_OUT_DIS] = LEDC_TASK_SIG_OUT_DIS_CH0, \ + [LEDC_CHANNEL_ETM_TASK_OVF_CNT_RST] = LEDC_TASK_OVF_CNT_RST_CH0, \ + [LEDC_CHANNEL_ETM_TASK_FADE_RESTART] = LEDC_TASK_GAMMA_RESTART_CH0, \ + [LEDC_CHANNEL_ETM_TASK_FADE_PAUSE] = LEDC_TASK_GAMMA_PAUSE_CH0, \ + [LEDC_CHANNEL_ETM_TASK_FADE_RESUME] = LEDC_TASK_GAMMA_RESUME_CH0, \ + }}[(group)][(task)] + (channel)) + +#define LEDC_LL_ETM_CHANNEL_TASK_EN_REG(group, task) \ + ((volatile uint32_t *[1][LEDC_CHANNEL_ETM_TASK_MAX]){{ \ + [LEDC_CHANNEL_ETM_TASK_FADE_SCALE_UPDATE] = (volatile uint32_t *)LEDC_EVT_TASK_EN0_REG, \ + [LEDC_CHANNEL_ETM_TASK_SIG_OUT_DIS] = (volatile uint32_t *)LEDC_EVT_TASK_EN1_REG, \ + [LEDC_CHANNEL_ETM_TASK_OVF_CNT_RST] = (volatile uint32_t *)LEDC_EVT_TASK_EN1_REG, \ + [LEDC_CHANNEL_ETM_TASK_FADE_RESTART] = (volatile uint32_t *)LEDC_EVT_TASK_EN2_REG, \ + [LEDC_CHANNEL_ETM_TASK_FADE_PAUSE] = (volatile uint32_t *)LEDC_EVT_TASK_EN2_REG, \ + [LEDC_CHANNEL_ETM_TASK_FADE_RESUME] = (volatile uint32_t *)LEDC_EVT_TASK_EN2_REG, \ + }}[(group)][(task)]) + +#define LEDC_LL_ETM_CHANNEL_TASK_EN_BIT(group, channel, task) \ + ((uint32_t [1][LEDC_CHANNEL_ETM_TASK_MAX]){{ \ + [LEDC_CHANNEL_ETM_TASK_FADE_SCALE_UPDATE] = BIT(LEDC_TASK_DUTY_SCALE_UPDATE_CH0_EN_S), \ + [LEDC_CHANNEL_ETM_TASK_SIG_OUT_DIS] = BIT(LEDC_TASK_SIG_OUT_DIS_CH0_EN_S), \ + [LEDC_CHANNEL_ETM_TASK_OVF_CNT_RST] = BIT(LEDC_TASK_OVF_CNT_RST_CH0_EN_S), \ + [LEDC_CHANNEL_ETM_TASK_FADE_RESTART] = BIT(LEDC_TASK_GAMMA_RESTART_CH0_EN_S), \ + [LEDC_CHANNEL_ETM_TASK_FADE_PAUSE] = BIT(LEDC_TASK_GAMMA_PAUSE_CH0_EN_S), \ + [LEDC_CHANNEL_ETM_TASK_FADE_RESUME] = BIT(LEDC_TASK_GAMMA_RESUME_CH0_EN_S), \ + }}[(group)][(task)] << (channel)) + +// Channel events: ID, enable register and bit +#define LEDC_LL_ETM_CHANNEL_EVENT_ID(group, channel, event) \ + ((uint32_t [1][LEDC_CHANNEL_ETM_EVENT_MAX]){{ \ + [LEDC_CHANNEL_ETM_EVENT_FADE_END] = LEDC_EVT_DUTY_CHNG_END_CH0, \ + [LEDC_CHANNEL_ETM_EVENT_REACH_MAX_OVF_CNT] = LEDC_EVT_OVF_CNT_PLS_CH0, \ + }}[(group)][(event)] + (channel)) + +#define LEDC_LL_ETM_CHANNEL_EVENT_EN_REG(group, event) \ + ((volatile uint32_t *[1][LEDC_CHANNEL_ETM_EVENT_MAX]){{ \ + [LEDC_CHANNEL_ETM_EVENT_FADE_END] = (volatile uint32_t *)LEDC_EVT_TASK_EN0_REG, \ + [LEDC_CHANNEL_ETM_EVENT_REACH_MAX_OVF_CNT] = (volatile uint32_t *)LEDC_EVT_TASK_EN0_REG, \ + }}[(group)][(event)]) + +#define LEDC_LL_ETM_CHANNEL_EVENT_EN_BIT(group, channel, event) \ + ((uint32_t [1][LEDC_CHANNEL_ETM_EVENT_MAX]){{ \ + [LEDC_CHANNEL_ETM_EVENT_FADE_END] = BIT(LEDC_EVT_DUTY_CHNG_END_CH0_EN_S), \ + [LEDC_CHANNEL_ETM_EVENT_REACH_MAX_OVF_CNT] = BIT(LEDC_EVT_OVF_CNT_PLS_CH0_EN_S), \ + }}[(group)][(event)] << (channel)) + +// Timer tasks: ID, enable register and bit +#define LEDC_LL_ETM_TIMER_TASK_ID(group, timer, task) \ + ((uint32_t [1][LEDC_TIMER_ETM_TASK_MAX]){{ \ + [LEDC_TIMER_ETM_TASK_RST] = LEDC_TASK_TIMER0_RST, \ + [LEDC_TIMER_ETM_TASK_RESUME] = LEDC_TASK_TIMER0_RESUME, \ + [LEDC_TIMER_ETM_TASK_PAUSE] = LEDC_TASK_TIMER0_PAUSE, \ + }}[(group)][(task)] + (timer)) + +#define LEDC_LL_ETM_TIMER_TASK_EN_REG(group, task) \ + ((volatile uint32_t *[1][LEDC_TIMER_ETM_TASK_MAX]){{ \ + [LEDC_TIMER_ETM_TASK_RST] = (volatile uint32_t *)LEDC_EVT_TASK_EN1_REG, \ + [LEDC_TIMER_ETM_TASK_RESUME] = (volatile uint32_t *)LEDC_EVT_TASK_EN1_REG, \ + [LEDC_TIMER_ETM_TASK_PAUSE] = (volatile uint32_t *)LEDC_EVT_TASK_EN1_REG, \ + }}[(group)][(task)]) + +#define LEDC_LL_ETM_TIMER_TASK_EN_BIT(group, timer, task) \ + ((uint32_t [1][LEDC_TIMER_ETM_TASK_MAX]){{ \ + [LEDC_TIMER_ETM_TASK_RST] = BIT(LEDC_TASK_TIMER0_RST_EN_S), \ + [LEDC_TIMER_ETM_TASK_RESUME] = BIT(LEDC_TASK_TIMER0_PAUSE_RESUME_EN_S), \ + [LEDC_TIMER_ETM_TASK_PAUSE] = BIT(LEDC_TASK_TIMER0_PAUSE_RESUME_EN_S), \ + }}[(group)][(task)] << (timer)) + +// Timer events: ID, enable register and bit +#define LEDC_LL_ETM_TIMER_EVENT_ID(group, timer, event) \ + ((uint32_t [1][LEDC_TIMER_ETM_EVENT_MAX]){{ \ + [LEDC_TIMER_ETM_EVENT_OVF] = LEDC_EVT_TIME_OVF_TIMER0, \ + }}[(group)][(event)] + (timer)) + +#define LEDC_LL_ETM_TIMER_EVENT_EN_REG(group, event) \ + ((volatile uint32_t *[1][LEDC_TIMER_ETM_EVENT_MAX]){{ \ + [LEDC_TIMER_ETM_EVENT_OVF] = (volatile uint32_t *)LEDC_EVT_TASK_EN0_REG, \ + }}[(group)][(event)]) + +#define LEDC_LL_ETM_TIMER_EVENT_EN_BIT(group, timer, event) \ + ((uint32_t [1][LEDC_TIMER_ETM_EVENT_MAX]){{ \ + [LEDC_TIMER_ETM_EVENT_OVF] = BIT(LEDC_EVT_TIME_OVF_TIMER0_EN_S), \ + }}[(group)][(event)] << (timer)) + /** * @brief Enable peripheral register clock * @@ -705,6 +797,71 @@ static inline void ledc_ll_get_channel_timer(ledc_dev_t *hw, ledc_mode_t speed_m *timer_sel = (ledc_timer_t)(hw->channel_group[speed_mode].channel[channel_num].conf0.timer_sel); } +/** + * @brief Enable or disable ETM event/task + * + * @param hw Beginning address of the peripheral registers + * @param speed_mode LEDC speed_mode, low-speed mode only + * @param reg_addr Register address to control the ETM event/task + * @param bit Bit position in the register + * @param enable Enable or disable the ETM event/task + * + * @return None + */ +static inline void ledc_ll_etm_enable_evt_task(ledc_dev_t *hw, ledc_mode_t speed_mode, volatile uint32_t *reg_addr, uint32_t bit, bool enable) +{ + if (enable) { + REG_SET_BIT(reg_addr, bit); + } else { + REG_CLR_BIT(reg_addr, bit); + } +} + +/** + * @brief Enable or disable the timer overflow counter for the specified channel + * + * @param hw Beginning address of the peripheral registers + * @param speed_mode LEDC speed_mode, low-speed mode only + * @param channel LEDC channel index (0-5), select from ledc_channel_t + * @param enable True to enable; false to disable + * + * @return None + */ +static inline void ledc_ll_channel_enable_timer_ovt_cnt(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel, bool enable) +{ + hw->channel_group[speed_mode].channel[channel].conf0.ovf_cnt_en = enable; +} + +/** + * @brief Set the maximum timer overflow count for the specified channel + * + * @param hw Beginning address of the peripheral registers + * @param speed_mode LEDC speed_mode, low-speed mode only + * @param channel LEDC channel index (0-5), select from ledc_channel_t + * @param max_ovf_cnt The maximum timer overflow count + * + * @return None + */ +static inline void ledc_ll_channel_set_maximum_timer_ovf_cnt(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t max_ovf_cnt) +{ + HAL_ASSERT(max_ovf_cnt > 0 && max_ovf_cnt <= LEDC_LL_OVF_CNT_MAX); + hw->channel_group[speed_mode].channel[channel].conf0.ovf_num = max_ovf_cnt - 1; +} + +/** + * @brief Reset the timer overflow counter for the specified channel + * + * @param hw Beginning address of the peripheral registers + * @param speed_mode LEDC speed_mode, low-speed mode only + * @param channel LEDC channel index (0-5), select from ledc_channel_t + * + * @return None + */ +static inline void ledc_ll_channel_reset_timer_ovf_cnt(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel) +{ + hw->channel_group[speed_mode].channel[channel].conf0.ovf_cnt_reset = 1; +} + #ifdef __cplusplus } #endif diff --git a/components/hal/esp32h4/include/hal/ledc_ll.h b/components/hal/esp32h4/include/hal/ledc_ll.h index e18f309acf..bf49ef3f05 100644 --- a/components/hal/esp32h4/include/hal/ledc_ll.h +++ b/components/hal/esp32h4/include/hal/ledc_ll.h @@ -16,6 +16,7 @@ #include "soc/clk_tree_defs.h" #include "soc/pcr_struct.h" #include "soc/soc_caps.h" +#include "soc/soc_etm_source.h" #ifdef __cplusplus extern "C" { @@ -23,14 +24,105 @@ extern "C" { #define LEDC_LL_GET_HW() &LEDC +#define LEDC_LL_CHANNEL_SUPPORT_OVF_CNT 1 + #define LEDC_LL_DUTY_NUM_MAX (LEDC_CH0_FADE_PARAM_DUTY_NUM_V) #define LEDC_LL_DUTY_CYCLE_MAX (LEDC_CH0_FADE_PARAM_DUTY_CYCLE_V) #define LEDC_LL_DUTY_SCALE_MAX (LEDC_CH0_FADE_PARAM_SCALE_V) #define LEDC_LL_HPOINT_VAL_MAX (LEDC_HPOINT_CH0_V) +#define LEDC_LL_OVF_CNT_MAX (LEDC_OVF_NUM_CH0_V + 1) #define LEDC_LL_FRACTIONAL_BITS (8) #define LEDC_LL_FRACTIONAL_MAX ((1 << LEDC_LL_FRACTIONAL_BITS) - 1) #define LEDC_LL_GLOBAL_CLOCKS SOC_LEDC_CLKS +// Channel tasks: ID, enable register and bit +#define LEDC_LL_ETM_CHANNEL_TASK_ID(group, channel, task) \ + ((uint32_t [1][LEDC_CHANNEL_ETM_TASK_MAX]){{ \ + [LEDC_CHANNEL_ETM_TASK_FADE_SCALE_UPDATE] = LEDC_TASK_DUTY_SCALE_UPDATE_CH0, \ + [LEDC_CHANNEL_ETM_TASK_SIG_OUT_DIS] = LEDC_TASK_SIG_OUT_DIS_CH0, \ + [LEDC_CHANNEL_ETM_TASK_OVF_CNT_RST] = LEDC_TASK_OVF_CNT_RST_CH0, \ + [LEDC_CHANNEL_ETM_TASK_FADE_RESTART] = LEDC_TASK_FADE_RESTART_CH0, \ + [LEDC_CHANNEL_ETM_TASK_FADE_PAUSE] = LEDC_TASK_FADE_PAUSE_CH0, \ + [LEDC_CHANNEL_ETM_TASK_FADE_RESUME] = LEDC_TASK_FADE_RESUME_CH0, \ + }}[(group)][(task)] + (channel)) + +#define LEDC_LL_ETM_CHANNEL_TASK_EN_REG(group, task) \ + ((volatile uint32_t *[1][LEDC_CHANNEL_ETM_TASK_MAX]){{ \ + [LEDC_CHANNEL_ETM_TASK_FADE_SCALE_UPDATE] = (volatile uint32_t *)LEDC_EVT_TASK_EN0_REG, \ + [LEDC_CHANNEL_ETM_TASK_SIG_OUT_DIS] = (volatile uint32_t *)LEDC_EVT_TASK_EN1_REG, \ + [LEDC_CHANNEL_ETM_TASK_OVF_CNT_RST] = (volatile uint32_t *)LEDC_EVT_TASK_EN1_REG, \ + [LEDC_CHANNEL_ETM_TASK_FADE_RESTART] = (volatile uint32_t *)LEDC_EVT_TASK_EN2_REG, \ + [LEDC_CHANNEL_ETM_TASK_FADE_PAUSE] = (volatile uint32_t *)LEDC_EVT_TASK_EN2_REG, \ + [LEDC_CHANNEL_ETM_TASK_FADE_RESUME] = (volatile uint32_t *)LEDC_EVT_TASK_EN2_REG, \ + }}[(group)][(task)]) + +#define LEDC_LL_ETM_CHANNEL_TASK_EN_BIT(group, channel, task) \ + ((uint32_t [1][LEDC_CHANNEL_ETM_TASK_MAX]){{ \ + [LEDC_CHANNEL_ETM_TASK_FADE_SCALE_UPDATE] = BIT(LEDC_TASK_DUTY_SCALE_UPDATE_CH0_EN_S), \ + [LEDC_CHANNEL_ETM_TASK_SIG_OUT_DIS] = BIT(LEDC_TASK_SIG_OUT_DIS_CH0_EN_S), \ + [LEDC_CHANNEL_ETM_TASK_OVF_CNT_RST] = BIT(LEDC_TASK_OVF_CNT_RST_CH0_EN_S), \ + [LEDC_CHANNEL_ETM_TASK_FADE_RESTART] = BIT(LEDC_TASK_FADE_RESTART_CH0_EN_S), \ + [LEDC_CHANNEL_ETM_TASK_FADE_PAUSE] = BIT(LEDC_TASK_FADE_PAUSE_CH0_EN_S), \ + [LEDC_CHANNEL_ETM_TASK_FADE_RESUME] = BIT(LEDC_TASK_FADE_RESUME_CH0_EN_S), \ + }}[(group)][(task)] << (channel)) + +// Channel events: ID, enable register and bit +#define LEDC_LL_ETM_CHANNEL_EVENT_ID(group, channel, event) \ + ((uint32_t [1][LEDC_CHANNEL_ETM_EVENT_MAX]){{ \ + [LEDC_CHANNEL_ETM_EVENT_FADE_END] = LEDC_EVT_DUTY_CHNG_END_CH0, \ + [LEDC_CHANNEL_ETM_EVENT_REACH_MAX_OVF_CNT] = LEDC_EVT_OVF_CNT_PLS_CH0, \ + }}[(group)][(event)] + (channel)) + +#define LEDC_LL_ETM_CHANNEL_EVENT_EN_REG(group, event) \ + ((volatile uint32_t *[1][LEDC_CHANNEL_ETM_EVENT_MAX]){{ \ + [LEDC_CHANNEL_ETM_EVENT_FADE_END] = (volatile uint32_t *)LEDC_EVT_TASK_EN0_REG, \ + [LEDC_CHANNEL_ETM_EVENT_REACH_MAX_OVF_CNT] = (volatile uint32_t *)LEDC_EVT_TASK_EN0_REG, \ + }}[(group)][(event)]) + +#define LEDC_LL_ETM_CHANNEL_EVENT_EN_BIT(group, channel, event) \ + ((uint32_t [1][LEDC_CHANNEL_ETM_EVENT_MAX]){{ \ + [LEDC_CHANNEL_ETM_EVENT_FADE_END] = BIT(LEDC_EVT_DUTY_CHNG_END_CH0_EN_S), \ + [LEDC_CHANNEL_ETM_EVENT_REACH_MAX_OVF_CNT] = BIT(LEDC_EVT_OVF_CNT_PLS_CH0_EN_S), \ + }}[(group)][(event)] << (channel)) + +// Timer tasks: ID, enable register and bit +#define LEDC_LL_ETM_TIMER_TASK_ID(group, timer, task) \ + ((uint32_t [1][LEDC_TIMER_ETM_TASK_MAX]){{ \ + [LEDC_TIMER_ETM_TASK_RST] = LEDC_TASK_TIMER0_RST, \ + [LEDC_TIMER_ETM_TASK_RESUME] = LEDC_TASK_TIMER0_RESUME, \ + [LEDC_TIMER_ETM_TASK_PAUSE] = LEDC_TASK_TIMER0_PAUSE, \ + }}[(group)][(task)] + (timer)) + +#define LEDC_LL_ETM_TIMER_TASK_EN_REG(group, task) \ + ((volatile uint32_t *[1][LEDC_TIMER_ETM_TASK_MAX]){{ \ + [LEDC_TIMER_ETM_TASK_RST] = (volatile uint32_t *)LEDC_EVT_TASK_EN1_REG, \ + [LEDC_TIMER_ETM_TASK_RESUME] = (volatile uint32_t *)LEDC_EVT_TASK_EN1_REG, \ + [LEDC_TIMER_ETM_TASK_PAUSE] = (volatile uint32_t *)LEDC_EVT_TASK_EN1_REG, \ + }}[(group)][(task)]) + +#define LEDC_LL_ETM_TIMER_TASK_EN_BIT(group, timer, task) \ + ((uint32_t [1][LEDC_TIMER_ETM_TASK_MAX]){{ \ + [LEDC_TIMER_ETM_TASK_RST] = BIT(LEDC_TASK_TIMER0_RST_EN_S), \ + [LEDC_TIMER_ETM_TASK_RESUME] = BIT(LEDC_TASK_TIMER0_PAUSE_RESUME_EN_S), \ + [LEDC_TIMER_ETM_TASK_PAUSE] = BIT(LEDC_TASK_TIMER0_PAUSE_RESUME_EN_S), \ + }}[(group)][(task)] << (timer)) + +// Timer events: ID, enable register and bit +#define LEDC_LL_ETM_TIMER_EVENT_ID(group, timer, event) \ + ((uint32_t [1][LEDC_TIMER_ETM_EVENT_MAX]){{ \ + [LEDC_TIMER_ETM_EVENT_OVF] = LEDC_EVT_TIME_OVF_TIMER0, \ + }}[(group)][(event)] + (timer)) + +#define LEDC_LL_ETM_TIMER_EVENT_EN_REG(group, event) \ + ((volatile uint32_t *[1][LEDC_TIMER_ETM_EVENT_MAX]){{ \ + [LEDC_TIMER_ETM_EVENT_OVF] = (volatile uint32_t *)LEDC_EVT_TASK_EN0_REG, \ + }}[(group)][(event)]) + +#define LEDC_LL_ETM_TIMER_EVENT_EN_BIT(group, timer, event) \ + ((uint32_t [1][LEDC_TIMER_ETM_EVENT_MAX]){{ \ + [LEDC_TIMER_ETM_EVENT_OVF] = BIT(LEDC_EVT_TIME_OVF_TIMER0_EN_S), \ + }}[(group)][(event)] << (timer)) + /** * @brief Enable peripheral register clock * @@ -534,6 +626,71 @@ static inline void ledc_ll_get_channel_timer(ledc_dev_t *hw, ledc_mode_t speed_m *timer_sel = (ledc_timer_t)(hw->channel_group[speed_mode].channel[channel_num].conf0.timer_sel); } +/** + * @brief Enable or disable ETM event/task + * + * @param hw Beginning address of the peripheral registers + * @param speed_mode LEDC speed_mode, low-speed mode only + * @param reg_addr Register address to control the ETM event/task + * @param bit Bit position in the register + * @param enable Enable or disable the ETM event/task + * + * @return None + */ +static inline void ledc_ll_etm_enable_evt_task(ledc_dev_t *hw, ledc_mode_t speed_mode, volatile uint32_t *reg_addr, uint32_t bit, bool enable) +{ + if (enable) { + REG_SET_BIT(reg_addr, bit); + } else { + REG_CLR_BIT(reg_addr, bit); + } +} + +/** + * @brief Enable or disable the timer overflow counter for the specified channel + * + * @param hw Beginning address of the peripheral registers + * @param speed_mode LEDC speed_mode, low-speed mode only + * @param channel LEDC channel index (0-5), select from ledc_channel_t + * @param enable True to enable; false to disable + * + * @return None + */ +static inline void ledc_ll_channel_enable_timer_ovt_cnt(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel, bool enable) +{ + hw->channel_group[speed_mode].channel[channel].conf0.ovf_cnt_en = enable; +} + +/** + * @brief Set the maximum timer overflow count for the specified channel + * + * @param hw Beginning address of the peripheral registers + * @param speed_mode LEDC speed_mode, low-speed mode only + * @param channel LEDC channel index (0-5), select from ledc_channel_t + * @param max_ovf_cnt The maximum timer overflow count + * + * @return None + */ +static inline void ledc_ll_channel_set_maximum_timer_ovf_cnt(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t max_ovf_cnt) +{ + HAL_ASSERT(max_ovf_cnt > 0 && max_ovf_cnt <= LEDC_LL_OVF_CNT_MAX); + hw->channel_group[speed_mode].channel[channel].conf0.ovf_num = max_ovf_cnt - 1; +} + +/** + * @brief Reset the timer overflow counter for the specified channel + * + * @param hw Beginning address of the peripheral registers + * @param speed_mode LEDC speed_mode, low-speed mode only + * @param channel LEDC channel index (0-5), select from ledc_channel_t + * + * @return None + */ +static inline void ledc_ll_channel_reset_timer_ovf_cnt(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel) +{ + hw->channel_group[speed_mode].channel[channel].conf0.ovf_cnt_reset = 1; +} + #ifdef __cplusplus } #endif diff --git a/components/hal/esp32p4/include/hal/ledc_ll.h b/components/hal/esp32p4/include/hal/ledc_ll.h index 134399b294..9eac6dee67 100644 --- a/components/hal/esp32p4/include/hal/ledc_ll.h +++ b/components/hal/esp32p4/include/hal/ledc_ll.h @@ -16,6 +16,7 @@ #include "soc/clk_tree_defs.h" #include "soc/hp_sys_clkrst_struct.h" #include "soc/soc_caps.h" +#include "soc/soc_etm_source.h" #ifdef __cplusplus extern "C" { @@ -23,14 +24,105 @@ extern "C" { #define LEDC_LL_GET_HW() &LEDC +#define LEDC_LL_CHANNEL_SUPPORT_OVF_CNT 1 + #define LEDC_LL_DUTY_NUM_MAX (LEDC_CH0_GAMMA_RANGE0_DUTY_NUM_V) #define LEDC_LL_DUTY_CYCLE_MAX (LEDC_CH0_GAMMA_RANGE0_DUTY_CYCLE_V) #define LEDC_LL_DUTY_SCALE_MAX (LEDC_CH0_GAMMA_RANGE0_SCALE_V) #define LEDC_LL_HPOINT_VAL_MAX (LEDC_HPOINT_CH0_V) +#define LEDC_LL_OVF_CNT_MAX (LEDC_OVF_NUM_CH0_V + 1) #define LEDC_LL_FRACTIONAL_BITS (8) #define LEDC_LL_FRACTIONAL_MAX ((1 << LEDC_LL_FRACTIONAL_BITS) - 1) #define LEDC_LL_GLOBAL_CLOCKS SOC_LEDC_CLKS +// Channel tasks: ID, enable register and bit +#define LEDC_LL_ETM_CHANNEL_TASK_ID(group, channel, task) \ + ((uint32_t [1][LEDC_CHANNEL_ETM_TASK_MAX]){{ \ + [LEDC_CHANNEL_ETM_TASK_FADE_SCALE_UPDATE] = LEDC_TASK_DUTY_SCALE_UPDATE_CH0, \ + [LEDC_CHANNEL_ETM_TASK_SIG_OUT_DIS] = LEDC_TASK_SIG_OUT_DIS_CH0, \ + [LEDC_CHANNEL_ETM_TASK_OVF_CNT_RST] = LEDC_TASK_OVF_CNT_RST_CH0, \ + [LEDC_CHANNEL_ETM_TASK_FADE_RESTART] = LEDC_TASK_GAMMA_RESTART_CH0, \ + [LEDC_CHANNEL_ETM_TASK_FADE_PAUSE] = LEDC_TASK_GAMMA_PAUSE_CH0, \ + [LEDC_CHANNEL_ETM_TASK_FADE_RESUME] = LEDC_TASK_GAMMA_RESUME_CH0, \ + }}[(group)][(task)] + (channel)) + +#define LEDC_LL_ETM_CHANNEL_TASK_EN_REG(group, task) \ + ((volatile uint32_t *[1][LEDC_CHANNEL_ETM_TASK_MAX]){{ \ + [LEDC_CHANNEL_ETM_TASK_FADE_SCALE_UPDATE] = (volatile uint32_t *)LEDC_EVT_TASK_EN0_REG, \ + [LEDC_CHANNEL_ETM_TASK_SIG_OUT_DIS] = (volatile uint32_t *)LEDC_EVT_TASK_EN1_REG, \ + [LEDC_CHANNEL_ETM_TASK_OVF_CNT_RST] = (volatile uint32_t *)LEDC_EVT_TASK_EN1_REG, \ + [LEDC_CHANNEL_ETM_TASK_FADE_RESTART] = (volatile uint32_t *)LEDC_EVT_TASK_EN2_REG, \ + [LEDC_CHANNEL_ETM_TASK_FADE_PAUSE] = (volatile uint32_t *)LEDC_EVT_TASK_EN2_REG, \ + [LEDC_CHANNEL_ETM_TASK_FADE_RESUME] = (volatile uint32_t *)LEDC_EVT_TASK_EN2_REG, \ + }}[(group)][(task)]) + +#define LEDC_LL_ETM_CHANNEL_TASK_EN_BIT(group, channel, task) \ + ((uint32_t [1][LEDC_CHANNEL_ETM_TASK_MAX]){{ \ + [LEDC_CHANNEL_ETM_TASK_FADE_SCALE_UPDATE] = BIT(LEDC_TASK_DUTY_SCALE_UPDATE_CH0_EN_S), \ + [LEDC_CHANNEL_ETM_TASK_SIG_OUT_DIS] = BIT(LEDC_TASK_SIG_OUT_DIS_CH0_EN_S), \ + [LEDC_CHANNEL_ETM_TASK_OVF_CNT_RST] = BIT(LEDC_TASK_OVF_CNT_RST_CH0_EN_S), \ + [LEDC_CHANNEL_ETM_TASK_FADE_RESTART] = BIT(LEDC_TASK_GAMMA_RESTART_CH0_EN_S), \ + [LEDC_CHANNEL_ETM_TASK_FADE_PAUSE] = BIT(LEDC_TASK_GAMMA_PAUSE_CH0_EN_S), \ + [LEDC_CHANNEL_ETM_TASK_FADE_RESUME] = BIT(LEDC_TASK_GAMMA_RESUME_CH0_EN_S), \ + }}[(group)][(task)] << (channel)) + +// Channel events: ID, enable register and bit +#define LEDC_LL_ETM_CHANNEL_EVENT_ID(group, channel, event) \ + ((uint32_t [1][LEDC_CHANNEL_ETM_EVENT_MAX]){{ \ + [LEDC_CHANNEL_ETM_EVENT_FADE_END] = LEDC_EVT_DUTY_CHNG_END_CH0, \ + [LEDC_CHANNEL_ETM_EVENT_REACH_MAX_OVF_CNT] = LEDC_EVT_OVF_CNT_PLS_CH0, \ + }}[(group)][(event)] + (channel)) + +#define LEDC_LL_ETM_CHANNEL_EVENT_EN_REG(group, event) \ + ((volatile uint32_t *[1][LEDC_CHANNEL_ETM_EVENT_MAX]){{ \ + [LEDC_CHANNEL_ETM_EVENT_FADE_END] = (volatile uint32_t *)LEDC_EVT_TASK_EN0_REG, \ + [LEDC_CHANNEL_ETM_EVENT_REACH_MAX_OVF_CNT] = (volatile uint32_t *)LEDC_EVT_TASK_EN0_REG, \ + }}[(group)][(event)]) + +#define LEDC_LL_ETM_CHANNEL_EVENT_EN_BIT(group, channel, event) \ + ((uint32_t [1][LEDC_CHANNEL_ETM_EVENT_MAX]){{ \ + [LEDC_CHANNEL_ETM_EVENT_FADE_END] = BIT(LEDC_EVT_DUTY_CHNG_END_CH0_EN_S), \ + [LEDC_CHANNEL_ETM_EVENT_REACH_MAX_OVF_CNT] = BIT(LEDC_EVT_OVF_CNT_PLS_CH0_EN_S), \ + }}[(group)][(event)] << (channel)) + +// Timer tasks: ID, enable register and bit +#define LEDC_LL_ETM_TIMER_TASK_ID(group, timer, task) \ + ((uint32_t [1][LEDC_TIMER_ETM_TASK_MAX]){{ \ + [LEDC_TIMER_ETM_TASK_RST] = LEDC_TASK_TIMER0_RST, \ + [LEDC_TIMER_ETM_TASK_RESUME] = LEDC_TASK_TIMER0_RESUME, \ + [LEDC_TIMER_ETM_TASK_PAUSE] = LEDC_TASK_TIMER0_PAUSE, \ + }}[(group)][(task)] + (timer)) + +#define LEDC_LL_ETM_TIMER_TASK_EN_REG(group, task) \ + ((volatile uint32_t *[1][LEDC_TIMER_ETM_TASK_MAX]){{ \ + [LEDC_TIMER_ETM_TASK_RST] = (volatile uint32_t *)LEDC_EVT_TASK_EN1_REG, \ + [LEDC_TIMER_ETM_TASK_RESUME] = (volatile uint32_t *)LEDC_EVT_TASK_EN1_REG, \ + [LEDC_TIMER_ETM_TASK_PAUSE] = (volatile uint32_t *)LEDC_EVT_TASK_EN1_REG, \ + }}[(group)][(task)]) + +#define LEDC_LL_ETM_TIMER_TASK_EN_BIT(group, timer, task) \ + ((uint32_t [1][LEDC_TIMER_ETM_TASK_MAX]){{ \ + [LEDC_TIMER_ETM_TASK_RST] = BIT(LEDC_TASK_TIMER0_RST_EN_S), \ + [LEDC_TIMER_ETM_TASK_RESUME] = BIT(LEDC_TASK_TIMER0_PAUSE_RESUME_EN_S), \ + [LEDC_TIMER_ETM_TASK_PAUSE] = BIT(LEDC_TASK_TIMER0_PAUSE_RESUME_EN_S), \ + }}[(group)][(task)] << (timer)) + +// Timer events: ID, enable register and bit +#define LEDC_LL_ETM_TIMER_EVENT_ID(group, timer, event) \ + ((uint32_t [1][LEDC_TIMER_ETM_EVENT_MAX]){{ \ + [LEDC_TIMER_ETM_EVENT_OVF] = LEDC_EVT_TIME_OVF_TIMER0, \ + }}[(group)][(event)] + (timer)) + +#define LEDC_LL_ETM_TIMER_EVENT_EN_REG(group, event) \ + ((volatile uint32_t *[1][LEDC_TIMER_ETM_EVENT_MAX]){{ \ + [LEDC_TIMER_ETM_EVENT_OVF] = (volatile uint32_t *)LEDC_EVT_TASK_EN0_REG, \ + }}[(group)][(event)]) + +#define LEDC_LL_ETM_TIMER_EVENT_EN_BIT(group, timer, event) \ + ((uint32_t [1][LEDC_TIMER_ETM_EVENT_MAX]){{ \ + [LEDC_TIMER_ETM_EVENT_OVF] = BIT(LEDC_EVT_TIME_OVF_TIMER0_EN_S), \ + }}[(group)][(event)] << (timer)) + /** * @brief Enable peripheral register clock * @@ -336,7 +428,7 @@ static inline void ledc_ll_get_max_duty(ledc_dev_t *hw, ledc_mode_t speed_mode, * * @param hw Beginning address of the peripheral registers * @param speed_mode LEDC speed_mode, low-speed mode only - * @param channel_num LEDC channel index (0-5), select from ledc_channel_t + * @param channel_num LEDC channel index (0-7), select from ledc_channel_t * * @return None */ @@ -350,7 +442,7 @@ static inline void ledc_ll_ls_channel_update(ledc_dev_t *hw, ledc_mode_t speed_m * * @param hw Beginning address of the peripheral registers * @param speed_mode LEDC speed_mode, low-speed mode only - * @param channel_num LEDC channel index (0-5), select from ledc_channel_t + * @param channel_num LEDC channel index (0-7), select from ledc_channel_t * @param hpoint_val LEDC hpoint value(max: 0xfffff) * * @return None @@ -365,7 +457,7 @@ static inline void ledc_ll_set_hpoint(ledc_dev_t *hw, ledc_mode_t speed_mode, le * * @param hw Beginning address of the peripheral registers * @param speed_mode LEDC speed_mode, low-speed mode only - * @param channel_num LEDC channel index (0-5), select from ledc_channel_t + * @param channel_num LEDC channel index (0-7), select from ledc_channel_t * @param hpoint_val Pointer to accept the LEDC hpoint value(max: 0xfffff) * * @return None @@ -380,7 +472,7 @@ static inline void ledc_ll_get_hpoint(ledc_dev_t *hw, ledc_mode_t speed_mode, le * * @param hw Beginning address of the peripheral registers * @param speed_mode LEDC speed_mode, low-speed mode only - * @param channel_num LEDC channel index (0-5), select from ledc_channel_t + * @param channel_num LEDC channel index (0-7), select from ledc_channel_t * @param duty_val LEDC duty value, the range of duty setting is [0, (2**duty_resolution)] * * @return None @@ -395,7 +487,7 @@ static inline void ledc_ll_set_duty_int_part(ledc_dev_t *hw, ledc_mode_t speed_m * * @param hw Beginning address of the peripheral registers * @param speed_mode LEDC speed_mode, low-speed mode only - * @param channel_num LEDC channel index (0-5), select from ledc_channel_t + * @param channel_num LEDC channel index (0-7), select from ledc_channel_t * @param duty_val Pointer to accept the LEDC duty value * * @return None @@ -410,7 +502,7 @@ static inline void ledc_ll_get_duty(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc * * @param hw Beginning address of the peripheral registers * @param speed_mode LEDC speed_mode, low-speed mode only - * @param channel_num LEDC channel index (0-5), select from ledc_channel_t + * @param channel_num LEDC channel index (0-7), select from ledc_channel_t * @param range Gamma fade range index, 0 ~ SOC_LEDC_GAMMA_CURVE_FADE_RANGE_MAX * @param dir LEDC duty change direction, increase or decrease * @param cycle The duty cycles @@ -436,7 +528,7 @@ static inline void ledc_ll_set_fade_param_range(ledc_dev_t *hw, ledc_mode_t spee * * @param hw Beginning address of the peripheral registers * @param speed_mode LEDC speed_mode, low-speed mode only - * @param channel_num LEDC channel index (0-5), select from ledc_channel_t + * @param channel_num LEDC channel index (0-7), select from ledc_channel_t * @param range_num Total number of ranges (1 - SOC_LEDC_GAMMA_CURVE_FADE_RANGE_MAX) of the fading configured * * @return None @@ -451,7 +543,7 @@ static inline void ledc_ll_set_range_number(ledc_dev_t *hw, ledc_mode_t speed_mo * * @param hw Beginning address of the peripheral registers * @param speed_mode LEDC speed_mode, low-speed mode only - * @param channel_num LEDC channel index (0-5), select from ledc_channel_t + * @param channel_num LEDC channel index (0-7), select from ledc_channel_t * @param range_num Pointer to accept fade range number * * @return None @@ -466,7 +558,7 @@ static inline void ledc_ll_get_range_number(ledc_dev_t *hw, ledc_mode_t speed_mo * * @param hw Beginning address of the peripheral registers * @param speed_mode LEDC speed_mode, low-speed mode only - * @param channel_num LEDC channel index (0-5), select from ledc_channel_t + * @param channel_num LEDC channel index (0-7), select from ledc_channel_t * @param range Gamma fade range index to get, 0 ~ SOC_LEDC_GAMMA_CURVE_FADE_RANGE_MAX * @param dir Pointer to accept fade direction value * @param cycle Pointer to accept fade cycle value @@ -492,7 +584,7 @@ static inline void ledc_ll_get_fade_param_range(ledc_dev_t *hw, ledc_mode_t spee * * @param hw Beginning address of the peripheral registers * @param speed_mode LEDC speed_mode, low-speed mode only - * @param channel_num LEDC channel index (0-5), select from ledc_channel_t + * @param channel_num LEDC channel index (0-7), select from ledc_channel_t * @param sig_out_en The output enable status * * @return None @@ -508,7 +600,7 @@ static inline void ledc_ll_set_sig_out_en(ledc_dev_t *hw, ledc_mode_t speed_mode * * @param hw Beginning address of the peripheral registers * @param speed_mode LEDC speed_mode, low-speed mode only - * @param channel_num LEDC channel index (0-5), select from ledc_channel_t + * @param channel_num LEDC channel index (0-7), select from ledc_channel_t * * @return None */ @@ -522,7 +614,7 @@ static inline void ledc_ll_set_duty_start(ledc_dev_t *hw, ledc_mode_t speed_mode * * @param hw Beginning address of the peripheral registers * @param speed_mode LEDC speed_mode, low-speed mode only - * @param channel_num LEDC channel index (0-5), select from ledc_channel_t + * @param channel_num LEDC channel index (0-7), select from ledc_channel_t * @param idle_level The output idle level * * @return None @@ -538,7 +630,7 @@ static inline void ledc_ll_set_idle_level(ledc_dev_t *hw, ledc_mode_t speed_mode * * @param hw Beginning address of the peripheral registers * @param speed_mode LEDC speed_mode, low-speed mode only - * @param channel_num LEDC channel index (0-5), select from ledc_channel_t + * @param channel_num LEDC channel index (0-7), select from ledc_channel_t * @param fade_end_intr_en The fade end interrupt enable status * * @return None @@ -555,7 +647,7 @@ static inline void ledc_ll_set_fade_end_intr(ledc_dev_t *hw, ledc_mode_t speed_m * * @param hw Beginning address of the peripheral registers * @param speed_mode LEDC speed_mode, low-speed mode only - * @param channel_num LEDC channel index (0-5), select from ledc_channel_t + * @param channel_num LEDC channel index (0-7), select from ledc_channel_t * @param intr_status The fade end interrupt status * * @return None @@ -572,7 +664,7 @@ static inline void ledc_ll_get_fade_end_intr_status(ledc_dev_t *hw, ledc_mode_t * * @param hw Beginning address of the peripheral registers * @param speed_mode LEDC speed_mode, low-speed mode only - * @param channel_num LEDC channel index (0-5), select from ledc_channel_t + * @param channel_num LEDC channel index (0-7), select from ledc_channel_t * * @return None */ @@ -587,7 +679,7 @@ static inline void ledc_ll_clear_fade_end_intr_status(ledc_dev_t *hw, ledc_mode_ * * @param hw Beginning address of the peripheral registers * @param speed_mode LEDC speed_mode, low-speed mode only - * @param channel_num LEDC channel index (0-5), select from ledc_channel_t + * @param channel_num LEDC channel index (0-7), select from ledc_channel_t * @param timer_sel LEDC timer index (0-3), select from ledc_timer_t * * @return None @@ -602,7 +694,7 @@ static inline void ledc_ll_bind_channel_timer(ledc_dev_t *hw, ledc_mode_t speed_ * * @param hw Beginning address of the peripheral registers * @param speed_mode LEDC speed_mode, low-speed mode only - * @param channel_num LEDC channel index (0-5), select from ledc_channel_t + * @param channel_num LEDC channel index (0-7), select from ledc_channel_t * @param timer_sel Pointer to accept the LEDC timer index * * @return None @@ -612,6 +704,69 @@ static inline void ledc_ll_get_channel_timer(ledc_dev_t *hw, ledc_mode_t speed_m *timer_sel = (ledc_timer_t)(hw->channel_group[speed_mode].channel[channel_num].conf0.timer_sel); } +/** + * @brief Enable or disable ETM event/task + * + * @param hw Beginning address of the peripheral registers + * @param speed_mode LEDC speed_mode, low-speed mode only + * @param reg_addr Register address to control the ETM event/task + * @param bit Bit position in the register + * @param enable Enable or disable the ETM event/task + */ +static inline void ledc_ll_etm_enable_evt_task(ledc_dev_t *hw, ledc_mode_t speed_mode, volatile uint32_t *reg_addr, uint32_t bit, bool enable) +{ + if (enable) { + REG_SET_BIT(reg_addr, bit); + } else { + REG_CLR_BIT(reg_addr, bit); + } +} + +/** + * @brief Enable or disable the timer overflow counter for the specified channel + * + * @param hw Beginning address of the peripheral registers + * @param speed_mode LEDC speed_mode, low-speed mode only + * @param channel LEDC channel index (0-7), select from ledc_channel_t + * @param enable True to enable; false to disable + * + * @return None + */ +static inline void ledc_ll_channel_enable_timer_ovt_cnt(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel, bool enable) +{ + hw->channel_group[speed_mode].channel[channel].conf0.ovf_cnt_en = enable; +} + +/** + * @brief Set the maximum timer overflow count for the specified channel + * + * @param hw Beginning address of the peripheral registers + * @param speed_mode LEDC speed_mode, low-speed mode only + * @param channel LEDC channel index (0-7), select from ledc_channel_t + * @param max_ovf_cnt The maximum timer overflow count + * + * @return None + */ +static inline void ledc_ll_channel_set_maximum_timer_ovf_cnt(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t max_ovf_cnt) +{ + HAL_ASSERT(max_ovf_cnt > 0 && max_ovf_cnt <= LEDC_LL_OVF_CNT_MAX); + hw->channel_group[speed_mode].channel[channel].conf0.ovf_num = max_ovf_cnt - 1; +} + +/** + * @brief Reset the timer overflow counter for the specified channel + * + * @param hw Beginning address of the peripheral registers + * @param speed_mode LEDC speed_mode, low-speed mode only + * @param channel LEDC channel index (0-7), select from ledc_channel_t + * + * @return None + */ +static inline void ledc_ll_channel_reset_timer_ovf_cnt(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel) +{ + hw->channel_group[speed_mode].channel[channel].conf0.ovf_cnt_reset = 1; +} + #ifdef __cplusplus } #endif diff --git a/components/hal/esp32s2/include/hal/ledc_ll.h b/components/hal/esp32s2/include/hal/ledc_ll.h index fc44fefe7c..441fae1f0b 100644 --- a/components/hal/esp32s2/include/hal/ledc_ll.h +++ b/components/hal/esp32s2/include/hal/ledc_ll.h @@ -21,10 +21,13 @@ extern "C" { #define LEDC_LL_GET_HW() &LEDC +#define LEDC_LL_CHANNEL_SUPPORT_OVF_CNT 1 + #define LEDC_LL_DUTY_NUM_MAX (LEDC_DUTY_NUM_LSCH0_V) #define LEDC_LL_DUTY_CYCLE_MAX (LEDC_DUTY_CYCLE_LSCH0_V) #define LEDC_LL_DUTY_SCALE_MAX (LEDC_DUTY_SCALE_LSCH0_V) #define LEDC_LL_HPOINT_VAL_MAX (LEDC_HPOINT_LSCH0_V) +#define LEDC_LL_OVF_CNT_MAX (LEDC_OVF_NUM_LSCH0_V + 1) #define LEDC_LL_FRACTIONAL_BITS (8) #define LEDC_LL_FRACTIONAL_MAX ((1 << LEDC_LL_FRACTIONAL_BITS) - 1) @@ -628,6 +631,51 @@ static inline void ledc_ll_get_channel_timer(ledc_dev_t *hw, ledc_mode_t speed_m *timer_sel = (ledc_timer_t)(hw->channel_group[speed_mode].channel[channel_num].conf0.timer_sel); } +/** + * @brief Enable or disable the timer overflow counter for the specified channel + * + * @param hw Beginning address of the peripheral registers + * @param speed_mode LEDC speed_mode, low-speed mode only + * @param channel LEDC channel index (0-7), select from ledc_channel_t + * @param enable True to enable; false to disable + * + * @return None + */ +static inline void ledc_ll_channel_enable_timer_ovt_cnt(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel, bool enable) +{ + hw->channel_group[speed_mode].channel[channel].conf0.ovf_cnt_en = enable; +} + +/** + * @brief Set the maximum timer overflow count for the specified channel + * + * @param hw Beginning address of the peripheral registers + * @param speed_mode LEDC speed_mode, low-speed mode only + * @param channel LEDC channel index (0-7), select from ledc_channel_t + * @param max_ovf_cnt The maximum timer overflow count + * + * @return None + */ +static inline void ledc_ll_channel_set_maximum_timer_ovf_cnt(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t max_ovf_cnt) +{ + HAL_ASSERT(max_ovf_cnt > 0 && max_ovf_cnt <= LEDC_LL_OVF_CNT_MAX); + hw->channel_group[speed_mode].channel[channel].conf0.ovf_num = max_ovf_cnt - 1; +} + +/** + * @brief Reset the timer overflow counter for the specified channel + * + * @param hw Beginning address of the peripheral registers + * @param speed_mode LEDC speed_mode, low-speed mode only + * @param channel LEDC channel index (0-7), select from ledc_channel_t + * + * @return None + */ +static inline void ledc_ll_channel_reset_timer_ovf_cnt(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel) +{ + hw->channel_group[speed_mode].channel[channel].conf0.ovf_cnt_rst = 1; +} + #ifdef __cplusplus } #endif diff --git a/components/hal/esp32s3/include/hal/ledc_ll.h b/components/hal/esp32s3/include/hal/ledc_ll.h index 1a689d6dee..f89a21e114 100644 --- a/components/hal/esp32s3/include/hal/ledc_ll.h +++ b/components/hal/esp32s3/include/hal/ledc_ll.h @@ -21,10 +21,13 @@ extern "C" { #define LEDC_LL_GET_HW() &LEDC +#define LEDC_LL_CHANNEL_SUPPORT_OVF_CNT 1 + #define LEDC_LL_DUTY_NUM_MAX (LEDC_DUTY_NUM_LSCH0_V) #define LEDC_LL_DUTY_CYCLE_MAX (LEDC_DUTY_CYCLE_LSCH0_V) #define LEDC_LL_DUTY_SCALE_MAX (LEDC_DUTY_SCALE_LSCH0_V) #define LEDC_LL_HPOINT_VAL_MAX (LEDC_HPOINT_LSCH0_V) +#define LEDC_LL_OVF_CNT_MAX (LEDC_OVF_NUM_LSCH0_V + 1) #define LEDC_LL_FRACTIONAL_BITS (8) #define LEDC_LL_FRACTIONAL_MAX ((1 << LEDC_LL_FRACTIONAL_BITS) - 1) @@ -589,6 +592,51 @@ static inline void ledc_ll_get_channel_timer(ledc_dev_t *hw, ledc_mode_t speed_m *timer_sel = (ledc_timer_t)(hw->channel_group[speed_mode].channel[channel_num].conf0.timer_sel); } +/** + * @brief Enable or disable the timer overflow counter for the specified channel + * + * @param hw Beginning address of the peripheral registers + * @param speed_mode LEDC speed_mode, low-speed mode only + * @param channel LEDC channel index (0-7), select from ledc_channel_t + * @param enable True to enable; false to disable + * + * @return None + */ +static inline void ledc_ll_channel_enable_timer_ovt_cnt(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel, bool enable) +{ + hw->channel_group[speed_mode].channel[channel].conf0.ovf_cnt_en = enable; +} + +/** + * @brief Set the maximum timer overflow count for the specified channel + * + * @param hw Beginning address of the peripheral registers + * @param speed_mode LEDC speed_mode, low-speed mode only + * @param channel LEDC channel index (0-7), select from ledc_channel_t + * @param max_ovf_cnt The maximum timer overflow count + * + * @return None + */ +static inline void ledc_ll_channel_set_maximum_timer_ovf_cnt(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t max_ovf_cnt) +{ + HAL_ASSERT(max_ovf_cnt > 0 && max_ovf_cnt <= LEDC_LL_OVF_CNT_MAX); + hw->channel_group[speed_mode].channel[channel].conf0.ovf_num = max_ovf_cnt - 1; +} + +/** + * @brief Reset the timer overflow counter for the specified channel + * + * @param hw Beginning address of the peripheral registers + * @param speed_mode LEDC speed_mode, low-speed mode only + * @param channel LEDC channel index (0-7), select from ledc_channel_t + * + * @return None + */ +static inline void ledc_ll_channel_reset_timer_ovf_cnt(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel) +{ + hw->channel_group[speed_mode].channel[channel].conf0.ovf_cnt_rst = 1; +} + #ifdef __cplusplus } #endif diff --git a/components/hal/include/hal/ledc_hal.h b/components/hal/include/hal/ledc_hal.h index 18ac920a2d..0ff3634659 100644 --- a/components/hal/include/hal/ledc_hal.h +++ b/components/hal/include/hal/ledc_hal.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2019-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2019-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -248,6 +248,19 @@ typedef struct { */ void ledc_hal_init(ledc_hal_context_t *hal, ledc_mode_t speed_mode); +#if LEDC_LL_CHANNEL_SUPPORT_OVF_CNT +/** + * @brief Configure the maximum timer overflow times for the LEDC channel + * + * @param hal Context of the HAL layer + * @param channel LEDC channel index, select from ledc_channel_t + * @param max_ovf_cnt The maximum timer overflow times. To disable the timer overflow count, set this parameter to 0. + * + * @return None + */ +void ledc_hal_channel_configure_maximum_timer_ovf_cnt(ledc_hal_context_t *hal, ledc_channel_t channel, uint32_t max_ovf_cnt); +#endif + /** * @brief Update channel configure when select low speed mode * diff --git a/components/hal/include/hal/ledc_types.h b/components/hal/include/hal/ledc_types.h index 9f6f006c28..116681c568 100644 --- a/components/hal/include/hal/ledc_types.h +++ b/components/hal/include/hal/ledc_types.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2019-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2019-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -139,6 +139,56 @@ typedef enum { LEDC_FADE_MAX, } ledc_fade_mode_t; +#if SOC_LEDC_SUPPORT_ETM +/** + * @brief LEDC channel related specific tasks that supported by the ETM module + */ +typedef enum { + LEDC_CHANNEL_ETM_TASK_FADE_SCALE_UPDATE, /*!< Update newly configured scale for the fade on the channel */ + LEDC_CHANNEL_ETM_TASK_SIG_OUT_DIS, /*!< Disable signal output on the channel */ + LEDC_CHANNEL_ETM_TASK_OVF_CNT_RST, /*!< Reset channel's timer overflow counter */ + LEDC_CHANNEL_ETM_TASK_FADE_RESTART, /* Restart the last fade on the channel, the replay will start from last configured duty + (note that, for a single fade, the duty may be configured to a new value in ISR, + so it may not be the initial value you configured before fade) */ + LEDC_CHANNEL_ETM_TASK_FADE_PAUSE, /*!< Pause fading on the channel */ + LEDC_CHANNEL_ETM_TASK_FADE_RESUME, /*!< Resume fading on the channel */ + LEDC_CHANNEL_ETM_TASK_MAX, +} ledc_channel_etm_task_type_t; + +/** + * @brief LEDC timer related specific tasks that supported by the ETM module + */ +typedef enum { + LEDC_TIMER_ETM_TASK_RST, /*!< Reset the timer + When timer is reset, a timer overflow equivalent signal is sent to the channel, so any newly configured parameter is able to get updated + This is not the case on C6/H2/P4/C5/H4/H21, on such targets, no timer overflow equivalent signal is sent to the channel, i.e. newly configured parameter is not able to get updated when this ETM task is triggered */ + LEDC_TIMER_ETM_TASK_RESUME, /*!< Resume the timer + Note that the ETM timer pause/resume task must be used in pair + Pause by ETM task and resume by calling `ledc_timer_resume` is not allowed, vice versa */ + LEDC_TIMER_ETM_TASK_PAUSE, /*!< Pause the timer */ + LEDC_TIMER_ETM_TASK_MAX, +} ledc_timer_etm_task_type_t; + +/** + * @brief LEDC channel related specific events that supported by the ETM module + */ +typedef enum { + LEDC_CHANNEL_ETM_EVENT_FADE_END, /*!< Channel fading ended */ + LEDC_CHANNEL_ETM_EVENT_REACH_MAX_OVF_CNT, /*!< Channel has reached the maximum timer overflow count + The maximum overflow count value can be set with `ledc_channel_configure_maximum_timer_ovf_cnt` */ + LEDC_CHANNEL_ETM_EVENT_MAX, +} ledc_channel_etm_event_type_t; + +/** + * @brief LEDC timer related specific events that supported by the ETM module + */ +typedef enum { + LEDC_TIMER_ETM_EVENT_OVF, /*!< Timer overflow happened */ + LEDC_TIMER_ETM_EVENT_MAX, +} ledc_timer_etm_event_type_t; + +#endif + #ifdef __cplusplus } #endif diff --git a/components/hal/ledc_hal.c b/components/hal/ledc_hal.c index a5a32394cf..7154fa52b1 100644 --- a/components/hal/ledc_hal.c +++ b/components/hal/ledc_hal.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2019-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2019-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -63,3 +63,16 @@ void ledc_hal_get_fade_param(ledc_hal_context_t *hal, ledc_channel_t channel_num ledc_ll_get_fade_param_range(hal->dev, hal->speed_mode, channel_num, range, dir, cycle, scale, step); } #endif + +#if LEDC_LL_CHANNEL_SUPPORT_OVF_CNT +void ledc_hal_channel_configure_maximum_timer_ovf_cnt(ledc_hal_context_t *hal, ledc_channel_t channel, uint32_t max_ovf_cnt) +{ + if (max_ovf_cnt == 0) { + ledc_ll_channel_enable_timer_ovt_cnt(hal->dev, hal->speed_mode, channel, false); + } else { + ledc_ll_channel_enable_timer_ovt_cnt(hal->dev, hal->speed_mode, channel, true); + ledc_ll_channel_set_maximum_timer_ovf_cnt(hal->dev, hal->speed_mode, channel, max_ovf_cnt); + ledc_ll_channel_reset_timer_ovf_cnt(hal->dev, hal->speed_mode, channel); + } +} +#endif diff --git a/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in index 9a9cb551b6..156c1415ec 100644 --- a/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in @@ -783,6 +783,10 @@ config SOC_LEDC_SUPPORT_SLEEP_RETENTION bool default y +config SOC_LEDC_SUPPORT_ETM + bool + default y + config SOC_MMU_PERIPH_NUM int default 1 diff --git a/components/soc/esp32c5/include/soc/soc_caps.h b/components/soc/esp32c5/include/soc/soc_caps.h index fbed2753cb..256729f244 100644 --- a/components/soc/esp32c5/include/soc/soc_caps.h +++ b/components/soc/esp32c5/include/soc/soc_caps.h @@ -315,6 +315,7 @@ #define SOC_LEDC_GAMMA_CURVE_FADE_RANGE_MAX (16) #define SOC_LEDC_FADE_PARAMS_BIT_WIDTH (10) #define SOC_LEDC_SUPPORT_SLEEP_RETENTION (1) +#define SOC_LEDC_SUPPORT_ETM (1) /*-------------------------- MMU CAPS ----------------------------------------*/ #define SOC_MMU_PERIPH_NUM (1U) diff --git a/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in index bfc74081c1..cdf6c31dc2 100644 --- a/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in @@ -707,6 +707,10 @@ config SOC_LEDC_SUPPORT_SLEEP_RETENTION bool default y +config SOC_LEDC_SUPPORT_ETM + bool + default y + config SOC_MMU_PAGE_SIZE_CONFIGURABLE bool default y diff --git a/components/soc/esp32c6/include/soc/soc_caps.h b/components/soc/esp32c6/include/soc/soc_caps.h index c79feb23d1..081322b1f5 100644 --- a/components/soc/esp32c6/include/soc/soc_caps.h +++ b/components/soc/esp32c6/include/soc/soc_caps.h @@ -291,6 +291,7 @@ #define SOC_LEDC_GAMMA_CURVE_FADE_RANGE_MAX (16) #define SOC_LEDC_FADE_PARAMS_BIT_WIDTH (10) #define SOC_LEDC_SUPPORT_SLEEP_RETENTION (1) +#define SOC_LEDC_SUPPORT_ETM (1) /*-------------------------- MMU CAPS ----------------------------------------*/ #define SOC_MMU_PAGE_SIZE_CONFIGURABLE (1) diff --git a/components/soc/esp32c61/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c61/include/soc/Kconfig.soc_caps.in index 2d30ff80ab..4a8ec5625d 100644 --- a/components/soc/esp32c61/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c61/include/soc/Kconfig.soc_caps.in @@ -643,6 +643,10 @@ config SOC_LEDC_SUPPORT_SLEEP_RETENTION bool default y +config SOC_LEDC_SUPPORT_ETM + bool + default y + config SOC_MMU_PAGE_SIZE_CONFIGURABLE bool default y diff --git a/components/soc/esp32c61/include/soc/soc_caps.h b/components/soc/esp32c61/include/soc/soc_caps.h index ccead5f87f..05f786336d 100644 --- a/components/soc/esp32c61/include/soc/soc_caps.h +++ b/components/soc/esp32c61/include/soc/soc_caps.h @@ -262,6 +262,7 @@ #define SOC_LEDC_GAMMA_CURVE_FADE_RANGE_MAX (16) #define SOC_LEDC_FADE_PARAMS_BIT_WIDTH (10) #define SOC_LEDC_SUPPORT_SLEEP_RETENTION (1) +#define SOC_LEDC_SUPPORT_ETM (1) /*-------------------------- MMU CAPS ----------------------------------------*/ #define SOC_MMU_PAGE_SIZE_CONFIGURABLE (1) diff --git a/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in b/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in index ae0d91158c..e30ea5ba77 100644 --- a/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in @@ -715,6 +715,10 @@ config SOC_LEDC_SUPPORT_SLEEP_RETENTION bool default y +config SOC_LEDC_SUPPORT_ETM + bool + default y + config SOC_MPU_CONFIGURABLE_REGIONS_SUPPORTED bool default n diff --git a/components/soc/esp32h2/include/soc/soc_caps.h b/components/soc/esp32h2/include/soc/soc_caps.h index e573342a61..ec20076b5b 100644 --- a/components/soc/esp32h2/include/soc/soc_caps.h +++ b/components/soc/esp32h2/include/soc/soc_caps.h @@ -310,6 +310,7 @@ #define SOC_LEDC_GAMMA_CURVE_FADE_RANGE_MAX (16) #define SOC_LEDC_FADE_PARAMS_BIT_WIDTH (10) #define SOC_LEDC_SUPPORT_SLEEP_RETENTION (1) +#define SOC_LEDC_SUPPORT_ETM (1) /*-------------------------- MPU CAPS ----------------------------------------*/ #define SOC_MPU_CONFIGURABLE_REGIONS_SUPPORTED 0 diff --git a/components/soc/esp32h21/include/soc/Kconfig.soc_caps.in b/components/soc/esp32h21/include/soc/Kconfig.soc_caps.in index 6bdcec69a7..db5ff05ecd 100644 --- a/components/soc/esp32h21/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32h21/include/soc/Kconfig.soc_caps.in @@ -511,6 +511,10 @@ config SOC_LEDC_SUPPORT_SLEEP_RETENTION bool default y +config SOC_LEDC_SUPPORT_ETM + bool + default y + config SOC_PCNT_SUPPORT_RUNTIME_THRES_UPDATE bool default y diff --git a/components/soc/esp32h21/include/soc/soc_caps.h b/components/soc/esp32h21/include/soc/soc_caps.h index 1475416a83..8c195f5b7f 100644 --- a/components/soc/esp32h21/include/soc/soc_caps.h +++ b/components/soc/esp32h21/include/soc/soc_caps.h @@ -287,6 +287,7 @@ #define SOC_LEDC_GAMMA_CURVE_FADE_RANGE_MAX (16) #define SOC_LEDC_FADE_PARAMS_BIT_WIDTH (10) #define SOC_LEDC_SUPPORT_SLEEP_RETENTION (1) +#define SOC_LEDC_SUPPORT_ETM (1) /*-------------------------- MPU CAPS ----------------------------------------*/ // #define SOC_MPU_CONFIGURABLE_REGIONS_SUPPORTED 0 diff --git a/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in index 1798d3c751..063959b089 100644 --- a/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in @@ -491,6 +491,10 @@ config SOC_LEDC_SUPPORT_SLEEP_RETENTION bool default y +config SOC_LEDC_SUPPORT_ETM + bool + default y + config SOC_MMU_PAGE_SIZE_CONFIGURABLE bool default y diff --git a/components/soc/esp32h4/include/soc/soc_caps.h b/components/soc/esp32h4/include/soc/soc_caps.h index e151884293..b711c3eb89 100644 --- a/components/soc/esp32h4/include/soc/soc_caps.h +++ b/components/soc/esp32h4/include/soc/soc_caps.h @@ -288,6 +288,7 @@ #define SOC_LEDC_SUPPORT_FADE_STOP (1) #define SOC_LEDC_FADE_PARAMS_BIT_WIDTH (10) #define SOC_LEDC_SUPPORT_SLEEP_RETENTION (1) +#define SOC_LEDC_SUPPORT_ETM (1) /*-------------------------- MMU CAPS ----------------------------------------*/ #define SOC_MMU_PAGE_SIZE_CONFIGURABLE (1) diff --git a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in index ccb8d58c87..9e80e3c042 100644 --- a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in @@ -1091,6 +1091,10 @@ config SOC_LEDC_SUPPORT_SLEEP_RETENTION bool default y +config SOC_LEDC_SUPPORT_ETM + bool + default y + config SOC_MMU_PERIPH_NUM int default 2 diff --git a/components/soc/esp32p4/include/soc/soc_caps.h b/components/soc/esp32p4/include/soc/soc_caps.h index 2a64a7ea71..1c13d7ca73 100644 --- a/components/soc/esp32p4/include/soc/soc_caps.h +++ b/components/soc/esp32p4/include/soc/soc_caps.h @@ -399,6 +399,7 @@ #define SOC_LEDC_SUPPORT_FADE_STOP (1) #define SOC_LEDC_FADE_PARAMS_BIT_WIDTH (10) #define SOC_LEDC_SUPPORT_SLEEP_RETENTION (1) +#define SOC_LEDC_SUPPORT_ETM (1) /*-------------------------- MMU CAPS ----------------------------------------*/ #define SOC_MMU_PERIPH_NUM (2U) diff --git a/docs/doxygen/Doxyfile b/docs/doxygen/Doxyfile index 885dbeb6aa..84bf5fbf10 100644 --- a/docs/doxygen/Doxyfile +++ b/docs/doxygen/Doxyfile @@ -107,6 +107,7 @@ INPUT = \ $(PROJECT_PATH)/components/esp_driver_gptimer/include/driver/gptimer_etm.h \ $(PROJECT_PATH)/components/esp_driver_gptimer/include/driver/gptimer_types.h \ $(PROJECT_PATH)/components/esp_driver_ledc/include/driver/ledc.h \ + $(PROJECT_PATH)/components/esp_driver_ledc/include/driver/ledc_etm.h \ $(PROJECT_PATH)/components/esp_driver_mcpwm/include/driver/mcpwm_cap.h \ $(PROJECT_PATH)/components/esp_driver_mcpwm/include/driver/mcpwm_cmpr.h \ $(PROJECT_PATH)/components/esp_driver_mcpwm/include/driver/mcpwm_etm.h \ diff --git a/docs/en/api-reference/peripherals/etm.rst b/docs/en/api-reference/peripherals/etm.rst index 89f16d411e..ec2b6973da 100644 --- a/docs/en/api-reference/peripherals/etm.rst +++ b/docs/en/api-reference/peripherals/etm.rst @@ -74,6 +74,7 @@ Other Peripheral Events :SOC_ANA_CMPR_SUPPORT_ETM: - Refer to :doc:`/api-reference/peripherals/ana_cmpr` for how to get the ETM event handle from analog comparator. :SOC_TEMPERATURE_SENSOR_SUPPORT_ETM: - Refer to :doc:`/api-reference/peripherals/temp_sensor` for how to get the ETM event handle from temperature sensor. :SOC_I2S_SUPPORTS_ETM: - Refer to :doc:`/api-reference/peripherals/i2s` for how to get the ETM event handle from I2S. + :SOC_LEDC_SUPPORT_ETM: - Refer to :doc:`/api-reference/peripherals/ledc` for how to get the ETM event handle from LEDC. .. _etm-task: @@ -101,6 +102,7 @@ Other Peripheral Tasks :SOC_TIMER_SUPPORT_ETM: - Refer to :ref:`gptimer-etm-event-and-task` for how to get the ETM task handle from GPTimer. :SOC_TEMPERATURE_SENSOR_SUPPORT_ETM: - Refer to :doc:`/api-reference/peripherals/temp_sensor` for how to get the ETM task handle from temperature sensor. :SOC_I2S_SUPPORTS_ETM: - Refer to :doc:`/api-reference/peripherals/i2s` for how to get the ETM task handle from I2S. + :SOC_LEDC_SUPPORT_ETM: - Refer to :doc:`/api-reference/peripherals/ledc` for how to get the ETM task handle from LEDC. .. _etm-channel-control: diff --git a/docs/en/api-reference/peripherals/ledc.rst b/docs/en/api-reference/peripherals/ledc.rst index d15a676fc3..1e3f5a198b 100644 --- a/docs/en/api-reference/peripherals/ledc.rst +++ b/docs/en/api-reference/peripherals/ledc.rst @@ -354,6 +354,21 @@ There are several individual timer-specific functions that can be used to change The first function is called "behind the scenes" by :cpp:func:`ledc_timer_config` to provide a startup of a timer after it is configured. +.. only:: SOC_LEDC_SUPPORT_ETM and SOC_ETM_SUPPORTED + + LEDC's ETM Events and Tasks + --------------------------- + + LEDC can generate various events that can be connected to the :doc:`ETM ` module. Timer's supported events are listed in :cpp:type:`ledc_timer_etm_event_type_t`, and channel's supported events are listed in :cpp:type:`ledc_channel_etm_event_type_t`. Users can create an ``ETM event`` handle by calling :cpp:func:`ledc_timer_new_etm_event` or :cpp:func:`ledc_channel_new_etm_event` respectively. + LEDC also supports some tasks that can be triggered by other events and executed automatically. Timer's supported tasks are listed in :cpp:type:`ledc_timer_etm_task_type_t`, and channel's supported tasks are listed in :cpp:type:`ledc_channel_etm_task_type_t`. Users can create an ``ETM task`` handle by calling :cpp:func:`ledc_timer_new_etm_task` or :cpp:func:`ledc_channel_new_etm_task` respectively. + + Some useful applications of ETM with LEDC are: + + * To generate a PWM signal with certain number of pulses + * To synchronize the PWM period with an external signal + * To start / stop the PWM signal output or a fading without CPU intervention + + For how to connect the LEDC events and tasks to the ETM channel, please refer to the :doc:`ETM ` documentation. Power Management ---------------- @@ -418,6 +433,7 @@ Application Example * :example:`peripherals/ledc/ledc_basic` demonstrates how to use the LEDC to generate a PWM signal in LOW SPEED mode. * :example:`peripherals/ledc/ledc_fade` demonstrates how to control the intensity of LEDs using the LEDC fade functionality. :SOC_LEDC_GAMMA_CURVE_FADE_SUPPORTED: * :example:`peripherals/ledc/ledc_gamma_curve_fade` demonstrates how to use the LEDC for color control of RGB LEDs with gamma correction. + :SOC_LEDC_SUPPORT_ETM and SOC_ETM_SUPPORTED: * :example:`peripherals/ledc/ledc_dimmer` demonstrates how to use the LEDC and ETM to generate TRIAC gate trigger pulses that are synchronized to the mains zero‑cross. API Reference @@ -425,3 +441,7 @@ API Reference .. include-build-file:: inc/ledc.inc .. include-build-file:: inc/ledc_types.inc + +.. only:: SOC_LEDC_SUPPORT_ETM and SOC_ETM_SUPPORTED + + .. include-build-file:: inc/ledc_etm.inc diff --git a/docs/zh_CN/api-reference/peripherals/etm.rst b/docs/zh_CN/api-reference/peripherals/etm.rst index 0f6127a356..80cda16d92 100644 --- a/docs/zh_CN/api-reference/peripherals/etm.rst +++ b/docs/zh_CN/api-reference/peripherals/etm.rst @@ -74,6 +74,7 @@ GPIO **边沿** 事件是最常见的事件类型,任何 GPIO 管脚均可触 :SOC_ANA_CMPR_SUPPORT_ETM: - 要了解如何从模拟比较器获取 ETM 事件句柄,请参阅 :doc:`/api-reference/peripherals/ana_cmpr`。 :SOC_TEMPERATURE_SENSOR_SUPPORT_ETM: - 要了解如何从温度传感器获取 ETM 事件句柄,请参阅 :doc:`/api-reference/peripherals/temp_sensor`。 :SOC_I2S_SUPPORTS_ETM: - 要了解如何从 I2S 获取 ETM 事件句柄,请参阅 :doc:`/api-reference/peripherals/i2s`。 + :SOC_LEDC_SUPPORT_ETM: - 要了解如何从 LEDC 获取 ETM 事件句柄,请参阅 :doc:`/api-reference/peripherals/ledc`。 .. _etm-task: @@ -101,6 +102,7 @@ GPIO 任务是最常见的任务类型。一个 GPIO 可以采取一个或多个 :SOC_TIMER_SUPPORT_ETM: - 要了解如何从 GPTimer 获取 ETM 任务句柄,请参阅 :ref:`gptimer-etm-event-and-task`。 :SOC_TEMPERATURE_SENSOR_SUPPORT_ETM: - 要了解如何从温度传感器获取 ETM 任务句柄,请参阅 :doc:`/api-reference/peripherals/temp_sensor`。 :SOC_I2S_SUPPORTS_ETM: - 要了解如何从 I2S 获取 ETM 任务句柄,请参阅 :doc:`/api-reference/peripherals/i2s`。 + :SOC_LEDC_SUPPORT_ETM: - 要了解如何从 LEDC 获取 ETM 任务句柄,请参阅 :doc:`/api-reference/peripherals/ledc`。 .. _etm-channel-control: diff --git a/docs/zh_CN/api-reference/peripherals/ledc.rst b/docs/zh_CN/api-reference/peripherals/ledc.rst index 5a2cb1d199..f77f3ff15b 100644 --- a/docs/zh_CN/api-reference/peripherals/ledc.rst +++ b/docs/zh_CN/api-reference/peripherals/ledc.rst @@ -354,6 +354,21 @@ LED PWM 控制器 API 有多种方式即时改变 PWM 频率: 第一个定时器复位函数在函数 :cpp:func:`ledc_timer_config` 内部完成所有定时器配置后会被调用一次。 +.. only:: SOC_LEDC_SUPPORT_ETM and SOC_ETM_SUPPORTED + + LEDC 的 ETM 事件和任务 + ---------------------- + + LEDC 可以生成多种事件,这些事件可以连接到 :doc:`ETM ` 模块。定时器支持的事件列在 :cpp:type:`ledc_timer_etm_event_type_t` 中,通道支持的事件列在 :cpp:type:`ledc_channel_etm_event_type_t` 中。用户可以分别通过调用 :cpp:func:`ledc_timer_new_etm_event` 或 :cpp:func:`ledc_channel_new_etm_event` 来创建 ``ETM event`` 句柄。 + LEDC 还支持一些可由其他事件触发并自动执行的任务。定时器支持的任务列在 :cpp:type:`ledc_timer_etm_task_type_t` 中,通道支持的任务列在 :cpp:type:`ledc_channel_etm_task_type_t` 中。用户可以分别通过调用 :cpp:func:`ledc_timer_new_etm_task` 或 :cpp:func:`ledc_channel_new_etm_task` 来创建 ``ETM task`` 句柄。 + + 一些使用 ETM 与 LEDC 结合的实用应用包括: + + * 生成一段特定脉冲数的 PWM 信号 + * 同步 PWM 周期与外部信号 + * 无需 CPU 干预即可开始 / 停止 PWM 信号输出或一次渐变 + + 关于如何将 LEDC 事件和任务连接到 ETM 通道,请参考 :doc:`ETM ` 文档。 电源管理 -------- @@ -418,6 +433,7 @@ LED PWM 控制器 API 会在设定的频率和占空比分辨率超过 LED PWM * :example:`peripherals/ledc/ledc_basic` 演示了如何使用 LEDC 生成低速模式的 PWM 信号。 * :example:`peripherals/ledc/ledc_fade` 演示了如何使用 LEDC 实现 LED 亮度的渐变控制。 :SOC_LEDC_GAMMA_CURVE_FADE_SUPPORTED: * :example:`peripherals/ledc/ledc_gamma_curve_fade` 演示了如何使用 LEDC 对 RGB LED 实现带伽马校正的颜色控制。 + :SOC_LEDC_SUPPORT_ETM and SOC_ETM_SUPPORTED: * :example:`peripherals/ledc/ledc_dimmer` 演示了如何使用 LEDC 和 ETM 生成与交流电零交叉同步的 TRIAC 门触发脉冲。 API 参考 @@ -425,3 +441,7 @@ API 参考 .. include-build-file:: inc/ledc.inc .. include-build-file:: inc/ledc_types.inc + +.. only:: SOC_LEDC_SUPPORT_ETM and SOC_ETM_SUPPORTED + + .. include-build-file:: inc/ledc_etm.inc diff --git a/examples/peripherals/.build-test-rules.yml b/examples/peripherals/.build-test-rules.yml index 4e2b89da40..8b667324ec 100644 --- a/examples/peripherals/.build-test-rules.yml +++ b/examples/peripherals/.build-test-rules.yml @@ -272,6 +272,12 @@ examples/peripherals/ledc: depends_components: - esp_driver_ledc +examples/peripherals/ledc/ledc_dimmer: + disable: + - if: SOC_ETM_SUPPORTED != 1 or SOC_LEDC_SUPPORT_ETM != 1 + depends_components: + - esp_driver_ledc + examples/peripherals/ledc/ledc_gamma_curve_fade: disable: - if: SOC_LEDC_SUPPORTED != 1 or SOC_LEDC_GAMMA_CURVE_FADE_SUPPORTED != 1 diff --git a/examples/peripherals/ledc/ledc_basic/main/ledc_basic_example_main.c b/examples/peripherals/ledc/ledc_basic/main/ledc_basic_example_main.c index 3ad8c473e2..2f17326aa7 100644 --- a/examples/peripherals/ledc/ledc_basic/main/ledc_basic_example_main.c +++ b/examples/peripherals/ledc/ledc_basic/main/ledc_basic_example_main.c @@ -49,7 +49,6 @@ static void example_ledc_init(void) .speed_mode = LEDC_MODE, .channel = LEDC_CHANNEL, .timer_sel = LEDC_TIMER, - .intr_type = LEDC_INTR_DISABLE, .gpio_num = LEDC_OUTPUT_IO, .duty = 0, // Set duty to 0% .hpoint = 0, diff --git a/examples/peripherals/ledc/ledc_dimmer/CMakeLists.txt b/examples/peripherals/ledc/ledc_dimmer/CMakeLists.txt new file mode 100644 index 0000000000..2198ff4716 --- /dev/null +++ b/examples/peripherals/ledc/ledc_dimmer/CMakeLists.txt @@ -0,0 +1,8 @@ +# The following lines of boilerplate have to be in your project's CMakeLists +# in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.22) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +# "Trim" the build. Include the minimal set of components, main, and anything it depends on. +idf_build_set_property(MINIMAL_BUILD ON) +project(ledc_dimmer) diff --git a/examples/peripherals/ledc/ledc_dimmer/README.md b/examples/peripherals/ledc/ledc_dimmer/README.md new file mode 100644 index 0000000000..2d94421fc8 --- /dev/null +++ b/examples/peripherals/ledc/ledc_dimmer/README.md @@ -0,0 +1,63 @@ +| Supported Targets | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H4 | ESP32-P4 | +| ----------------- | -------- | -------- | --------- | -------- | -------- | -------- | + +# LEDC Dimmer Example + +This example demonstrates how to generate TRIAC gate trigger pulses that are synchronized to the mains zero‑cross using LEDC and ETM. As a simplified demonstration, it simulates the 50 Hz zero‑cross AC mains detector input using a GPIO that toggles at 50 Hz, and uses ETM to reset the LEDC timer on each edge (every half-cycle) for synchronization. By shifting the LEDC `hpoint` (phase angle) after each reset, the gate pulse moves within the half‑cycle, achieving dimming. + +## How to use example + +### Hardware Required + +* A development board with any Espressif SoC that has ETM functionality (e.g., ESP32C61-DevKitC etc.) +* A USB cable for power supply and programming + +## Signals and pins + +| Signal | GPIO | +| --------------------------------------------------------------- | --------------------------------------------------------------------------- | +| Reference wave (50 Hz square from a AC mains detection circuit) | GPIO3 (configured as input/output in this demo to simulate the square wave) | +| Gate trigger pulse (LEDC output) | GPIO2 | + +Expected observation if connect an oscilloscope or logic analyzer: + +- A 50 Hz square wave on `GPIO3`. +- Short pulses on `GPIO2` that occur once each half‑cycle, moving left/right (earlier/later) every 2 seconds as the brightness ramps down and up. + +## Build and flash + +Build the project and flash it to the board, then run monitor tool to view serial output: + +```bash +idf.py build +idf.py -p PORT flash monitor +``` + +(Replace PORT with the name of the serial port to use.) + +(To exit the serial monitor, type ``Ctrl-]``.) + +See the [ESP‑IDF Getting Started Guide](https://idf.espressif.com/) for full steps to configure and use ESP-IDF to build projects. + +## Adapting to real mains dimming (advanced) + +If you want to control a real TRIAC load (lamp): + +1. Replace the simulated reference wave with a proper zero‑cross detector feeding an isolated input GPIO. + - Configure `REFERENCE_WAVE_IO` as input only, remove the toggling task, and ensure ETM still triggers on both edges. Or to normalize the AC mains to some analog signal, and use analog comparator to trigger a ETM event. +2. Drive the TRIAC gate through an opto‑triac from the LEDC output GPIO with proper current‑limit resistor. + +Here shows a simplified schematic for reference: + +![AC Lamp Dimmer with ESP32 and TRIAC](image/ac_lamp_dimmer_triac.png) + +And here is an actual timing diagrams (AC mains + dimmer output waveforms with phase angle): + +![Timing Diagram](image/timing_diagram.png) + +## Troubleshooting + +- Pulse timing not updating on C6/C5/H2/P4/H4/H21 → Check the notes in the example source file. For such targets, LEDC timer period should be shorter than the half-cycle of the mains, so that timer overflow could happen to update the duty parameters. +- Please make sure (hpoint + duty) is always less than (2 ** timer_resolution), otherwise, behavior is unexpected. + +For any technical queries, please open an [issue](https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you soon. diff --git a/examples/peripherals/ledc/ledc_dimmer/image/ac_lamp_dimmer_triac.png b/examples/peripherals/ledc/ledc_dimmer/image/ac_lamp_dimmer_triac.png new file mode 100644 index 0000000000..8a7220c98c Binary files /dev/null and b/examples/peripherals/ledc/ledc_dimmer/image/ac_lamp_dimmer_triac.png differ diff --git a/examples/peripherals/ledc/ledc_dimmer/image/timing_diagram.png b/examples/peripherals/ledc/ledc_dimmer/image/timing_diagram.png new file mode 100644 index 0000000000..7f4cbeb7e0 Binary files /dev/null and b/examples/peripherals/ledc/ledc_dimmer/image/timing_diagram.png differ diff --git a/examples/peripherals/ledc/ledc_dimmer/main/CMakeLists.txt b/examples/peripherals/ledc/ledc_dimmer/main/CMakeLists.txt new file mode 100644 index 0000000000..db62d4c5d8 --- /dev/null +++ b/examples/peripherals/ledc/ledc_dimmer/main/CMakeLists.txt @@ -0,0 +1,3 @@ +idf_component_register(SRCS "ledc_dimmer_example_main.c" + PRIV_REQUIRES esp_driver_ledc esp_driver_gpio + INCLUDE_DIRS ".") diff --git a/examples/peripherals/ledc/ledc_dimmer/main/ledc_dimmer_example_main.c b/examples/peripherals/ledc/ledc_dimmer/main/ledc_dimmer_example_main.c new file mode 100644 index 0000000000..aff2ab55fc --- /dev/null +++ b/examples/peripherals/ledc/ledc_dimmer/main/ledc_dimmer_example_main.c @@ -0,0 +1,145 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "esp_check.h" +#include "driver/ledc.h" +#include "driver/gpio.h" +#include "esp_etm.h" +#include "sdkconfig.h" + +#define REFERENCE_WAVE_IO (3) // Reference wave GPIO +#define GATE_TRIGGER_PULSE_IO (2) // Gate trigger pulse GPIO +#define LEDC_TIMER LEDC_TIMER_0 +#define LEDC_MODE LEDC_LOW_SPEED_MODE +#define LEDC_CHANNEL LEDC_CHANNEL_0 +#define LEDC_DUTY_RES LEDC_TIMER_13_BIT // Set duty resolution to 13 bits +#define LEDC_DUTY (400) // Set duty to 400 out of 8192 (13-bit) +#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32C5 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32P4 || CONFIG_IDF_TARGET_ESP32H4 || CONFIG_IDF_TARGET_ESP32H21 +// On such targets. due to hardware limitation, LEDC timer reset ETM task won't sync newly configured duty parameters. +// Therefore, the LEDC timer frequency should be higher than 100 Hz (2 * 50 Hz) to ensure a timer overflow happens before the timer reset to update the duty parameters. +#define LEDC_FREQUENCY (120) // Frequency in Hertz. Set frequency at 120 Hz +#define LEDC_HPOINT_INITIAL (1640) // Initial hpoint value (to ensure no pulse between timer overflow and timer reset) +#else +#define LEDC_FREQUENCY (80) // Frequency in Hertz. Set frequency at 80 Hz +#define LEDC_HPOINT_INITIAL (0) // Initial hpoint value +#endif + +// For C6/C5/H2/P4/H4/H21: +// 120Hz 8192-step PWM cycle in 100Hz -> (1640, 8192 - LEDC_DUTY) steps for a 84% ~ 21% dimming (this is the limitation due to the hardware) +// For other targets: +// 100Hz in a 80Hz 8192-step PWM cycle -> (0, 6554) steps for a 100% ~ 0% dimming +// Overall, we want to increase and decrease the brightness in 10 steps, so each step is: +#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32C5 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32P4 || CONFIG_IDF_TARGET_ESP32H4 || CONFIG_IDF_TARGET_ESP32H21 +#define LEDC_HPOINT_STEP (615) +#else +#define LEDC_HPOINT_STEP (655) +#endif + +// Simulate a signal comes from the 50Hz mains AC supply +// Use GPIO + vTaskDelay to output a 50Hz square wave as the reference signal +static void reference_wave_init(void) +{ + gpio_config_t io_conf = {}; + io_conf.mode = GPIO_MODE_INPUT_OUTPUT; + io_conf.pin_bit_mask = (1ULL << REFERENCE_WAVE_IO); + ESP_ERROR_CHECK(gpio_config(&io_conf)); +} + +static void reference_wave_task(void *arg) +{ + while (1) { + // Set the reference wave high + ESP_ERROR_CHECK(gpio_set_level(REFERENCE_WAVE_IO, 1)); + vTaskDelay(pdMS_TO_TICKS(10)); // High for 10ms + + // Set the reference wave low + ESP_ERROR_CHECK(gpio_set_level(REFERENCE_WAVE_IO, 0)); + vTaskDelay(pdMS_TO_TICKS(10)); // Low for 10ms + } +} + +// Initialize the gate trigger pulse signal using LEDC +static void gate_trigger_pulse_signal_init(void) +{ + ledc_timer_config_t ledc_timer = { + .speed_mode = LEDC_MODE, + .duty_resolution = LEDC_DUTY_RES, + .timer_num = LEDC_TIMER, + .freq_hz = LEDC_FREQUENCY, + .clk_cfg = LEDC_AUTO_CLK + }; + ESP_ERROR_CHECK(ledc_timer_config(&ledc_timer)); + + ledc_channel_config_t ledc_channel = { + .speed_mode = LEDC_MODE, + .channel = LEDC_CHANNEL, + .timer_sel = LEDC_TIMER, + .gpio_num = GATE_TRIGGER_PULSE_IO, + .duty = LEDC_DUTY, + .hpoint = LEDC_HPOINT_INITIAL + }; + ESP_ERROR_CHECK(ledc_channel_config(&ledc_channel)); +} + +void app_main(void) +{ + gate_trigger_pulse_signal_init(); + vTaskDelay(pdMS_TO_TICKS(50)); // Wait for the LEDC to run for at least one cycle + + reference_wave_init(); + xTaskCreate(reference_wave_task, "reference_wave_task", 2048, NULL, 5, NULL); + + // Connect reference wave GPIO toggle event to LEDC timer reset task, so that the timing frame of the gate trigger pulse + // can be synchronized to the reference wave signal + esp_etm_channel_config_t etm_config = {}; + esp_etm_channel_handle_t etm_channel = NULL; + ESP_ERROR_CHECK(esp_etm_new_channel(&etm_config, &etm_channel)); + + esp_etm_event_handle_t gpio_event = NULL; + gpio_etm_event_config_t gpio_event_config = { + .edge = GPIO_ETM_EVENT_EDGE_ANY, + }; + ESP_ERROR_CHECK(gpio_new_etm_event(&gpio_event_config, &gpio_event)); + ESP_ERROR_CHECK(gpio_etm_event_bind_gpio(gpio_event, REFERENCE_WAVE_IO)); + + esp_etm_task_handle_t ledc_task = NULL; + ledc_timer_etm_task_config_t ledc_task_config = { + .task_type = LEDC_TIMER_ETM_TASK_RST, + }; + ESP_ERROR_CHECK(ledc_timer_new_etm_task(LEDC_MODE, LEDC_TIMER, &ledc_task_config, &ledc_task)); + + ESP_ERROR_CHECK(esp_etm_channel_connect(etm_channel, gpio_event, ledc_task)); + + ESP_ERROR_CHECK(esp_etm_channel_enable(etm_channel)); + + int cnt = 0; + bool dimming = true; // controls the dimming direction + uint32_t hpoint = LEDC_HPOINT_INITIAL; + while (1) { + vTaskDelay(pdMS_TO_TICKS(2000)); + if (dimming) { + // Decrease brightness + if (cnt < 10) { + hpoint += LEDC_HPOINT_STEP; + cnt++; + } else if (cnt == 10) { + dimming = false; + } + } else { + // Increase brightness + if (cnt > 0) { + hpoint -= LEDC_HPOINT_STEP; + cnt--; + } else if (cnt == 0) { + dimming = true; + } + } + ESP_ERROR_CHECK(ledc_set_duty_with_hpoint(LEDC_MODE, LEDC_CHANNEL, LEDC_DUTY, hpoint)); + ESP_ERROR_CHECK(ledc_update_duty(LEDC_MODE, LEDC_CHANNEL)); + } +}