feat(ledc): add support for ESP32S31

This commit is contained in:
Song Ruo Jing
2026-04-03 15:35:01 +08:00
parent e79d9f2567
commit f9b0736c93
31 changed files with 4831 additions and 236 deletions
+1 -1
View File
@@ -391,7 +391,7 @@ esp_err_t ledc_isr_register(void (*fn)(void *), void *arg, int intr_alloc_flags,
esp_err_t ret;
LEDC_ARG_CHECK(fn, "fn");
portENTER_CRITICAL(&ledc_spinlock);
ret = esp_intr_alloc(ETS_LEDC_INTR_SOURCE, intr_alloc_flags, fn, arg, handle);
ret = esp_intr_alloc(ledc_periph_signal[0].irq_id, intr_alloc_flags, fn, arg, handle);
portEXIT_CRITICAL(&ledc_spinlock);
return ret;
}
@@ -1,2 +1,2 @@
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | --------- | -------- | -------- | -------- | -------- |
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S2 | ESP32-S3 | ESP32-S31 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | --------- | -------- | -------- | -------- | -------- | --------- |
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2021-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -153,13 +153,20 @@ TEST_CASE("LEDC output idle level test", "[ledc]")
ledc_timer_config_t ledc_time_config = create_default_timer_config();
TEST_ESP_OK(ledc_timer_config(&ledc_time_config));
TEST_ESP_OK(ledc_channel_config(&ledc_ch_config));
gpio_input_enable(PULSE_IO);
uint32_t current_level = LEDC.channel_group[test_speed_mode].channel[LEDC_CHANNEL_0].conf0.idle_lv;
uint32_t current_level = 0;
TEST_ESP_OK(ledc_stop(test_speed_mode, LEDC_CHANNEL_0, current_level));
vTaskDelay(1000 / portTICK_PERIOD_MS);
// check real output level over some period
for (int i = 0; i < 40; i++) {
TEST_ASSERT_EQUAL_INT32(current_level, gpio_get_level(PULSE_IO));
esp_rom_delay_us(50);
}
// flip the idle level
TEST_ESP_OK(ledc_stop(test_speed_mode, LEDC_CHANNEL_0, !current_level));
vTaskDelay(1000 / portTICK_PERIOD_MS);
TEST_ASSERT_EQUAL_INT32(!current_level, LEDC.channel_group[test_speed_mode].channel[LEDC_CHANNEL_0].conf0.idle_lv);
// check real output level over some period
gpio_input_enable(PULSE_IO);
for (int i = 0; i < 40; i++) {
TEST_ASSERT_EQUAL_INT32(!current_level, gpio_get_level(PULSE_IO));
esp_rom_delay_us(50);
@@ -75,6 +75,6 @@ def test_ledc_psram(dut: IdfDut) -> None:
indirect=True,
)
@idf_parametrize('target', ['supported_targets'], indirect=['target'])
@pytest.mark.temp_skip_ci(targets=['esp32s31'], reason='s31 bringup on this module is not done')
@pytest.mark.temp_skip_ci(targets=['esp32s31'], reason='TODO: IDFCI-10334 no runner yet')
def test_ledc_multi_device(case_tester) -> None: # type: ignore
case_tester.run_all_multi_dev_cases(reset=True)
@@ -14,6 +14,7 @@
#include "soc/ledc_struct.h"
#include "soc/ledc_reg.h"
#include "soc/dport_reg.h"
#include "hal/assert.h"
#define LEDC_LL_GET(attr) (LEDC_LL_ ## attr)
@@ -52,6 +53,10 @@
extern "C" {
#endif
typedef enum {
LEDC_LL_MEM_LP_MODE_SHUT_DOWN, // power down memory during low power stage
} ledc_ll_mem_lp_mode_t;
/**
* @brief Enable peripheral register clock
*
@@ -95,11 +100,45 @@ static inline void ledc_ll_reset_register(int group_id)
} while(0)
/**
* @brief Enable the power for LEDC memory block
* @brief Force power on the LEDC memory block, regardless of the outside PMU logic
*
* @param dev Peripheral instance address
*/
static inline void ledc_ll_enable_mem_power(bool enable)
static inline void ledc_ll_mem_force_power_on(ledc_dev_t *dev)
{
// No LEDC mem block on ESP32
// No LEDC memory block on ESP32
}
/**
* @brief Force the LEDC memory block into low power mode, regardless of the outside PMU logic
*
* @param dev Peripheral instance address
*/
static inline void ledc_ll_mem_force_low_power(ledc_dev_t *dev)
{
// No LEDC memory block on ESP32
}
/**
* @brief Power control the LEDC memory block by the outside PMU logic
*
* @param dev Peripheral instance address
*/
static inline void ledc_ll_mem_power_by_pmu(ledc_dev_t *dev)
{
// No LEDC memory block on ESP32
}
/**
* @brief Set low power mode for LEDC memory block
*
* @param dev Peripheral instance address
* @param mode LEDC memory low power mode in low power stage
*/
static inline void ledc_ll_mem_set_low_power_mode(ledc_dev_t *dev, ledc_ll_mem_lp_mode_t mode)
{
(void)dev;
HAL_ASSERT(mode == LEDC_LL_MEM_LP_MODE_SHUT_DOWN);
}
/**
@@ -50,6 +50,10 @@
extern "C" {
#endif
typedef enum {
LEDC_LL_MEM_LP_MODE_SHUT_DOWN, // power down memory during low power stage
} ledc_ll_mem_lp_mode_t;
/**
* @brief Enable peripheral register clock
*
@@ -89,11 +93,45 @@ static inline void ledc_ll_reset_register(int group_id)
} while(0)
/**
* @brief Enable the power for LEDC memory block
* @brief Force power on the LEDC memory block, regardless of the outside PMU logic
*
* @param dev Peripheral instance address
*/
static inline void ledc_ll_enable_mem_power(bool enable)
static inline void ledc_ll_mem_force_power_on(ledc_dev_t *dev)
{
// No LEDC mem block on C2
// No LEDC memory block on C2
}
/**
* @brief Force the LEDC memory block into low power mode, regardless of the outside PMU logic
*
* @param dev Peripheral instance address
*/
static inline void ledc_ll_mem_force_low_power(ledc_dev_t *dev)
{
// No LEDC memory block on C2
}
/**
* @brief Power control the LEDC memory block by the outside PMU logic
*
* @param dev Peripheral instance address
*/
static inline void ledc_ll_mem_power_by_pmu(ledc_dev_t *dev)
{
// No LEDC memory block on C2
}
/**
* @brief Set low power mode for LEDC memory block
*
* @param dev Peripheral instance address
* @param mode LEDC memory low power mode in low power stage
*/
static inline void ledc_ll_mem_set_low_power_mode(ledc_dev_t *dev, ledc_ll_mem_lp_mode_t mode)
{
(void)dev;
HAL_ASSERT(mode == LEDC_LL_MEM_LP_MODE_SHUT_DOWN);
}
/**
@@ -51,6 +51,10 @@
extern "C" {
#endif
typedef enum {
LEDC_LL_MEM_LP_MODE_SHUT_DOWN, // power down memory during low power stage
} ledc_ll_mem_lp_mode_t;
/**
* @brief Enable peripheral register clock
*
@@ -90,11 +94,45 @@ static inline void ledc_ll_reset_register(int group_id)
} while(0)
/**
* @brief Enable the power for LEDC memory block
* @brief Force power on the LEDC memory block, regardless of the outside PMU logic
*
* @param dev Peripheral instance address
*/
static inline void ledc_ll_enable_mem_power(bool enable)
static inline void ledc_ll_mem_force_power_on(ledc_dev_t *dev)
{
// No LEDC mem block on C3
// No LEDC memory block on C3
}
/**
* @brief Force the LEDC memory block into low power mode, regardless of the outside PMU logic
*
* @param dev Peripheral instance address
*/
static inline void ledc_ll_mem_force_low_power(ledc_dev_t *dev)
{
// No LEDC memory block on C3
}
/**
* @brief Power control the LEDC memory block by the outside PMU logic
*
* @param dev Peripheral instance address
*/
static inline void ledc_ll_mem_power_by_pmu(ledc_dev_t *dev)
{
// No LEDC memory block on C3
}
/**
* @brief Set low power mode for LEDC memory block
*
* @param dev Peripheral instance address
* @param mode LEDC memory low power mode in low power stage
*/
static inline void ledc_ll_mem_set_low_power_mode(ledc_dev_t *dev, ledc_ll_mem_lp_mode_t mode)
{
(void)dev;
HAL_ASSERT(mode == LEDC_LL_MEM_LP_MODE_SHUT_DOWN);
}
/**
@@ -134,6 +134,10 @@
extern "C" {
#endif
typedef enum {
LEDC_LL_MEM_LP_MODE_SHUT_DOWN, // power down memory during low power stage
} ledc_ll_mem_lp_mode_t;
/**
* @brief Enable peripheral register clock
*
@@ -159,13 +163,48 @@ static inline void ledc_ll_reset_register(int group_id)
}
/**
* @brief Enable the power for LEDC memory block
* @brief Force power on the LEDC memory block, regardless of the outside PMU logic
*
* Note. This function cannot overwrite the power control of the mem block in sleep mode
* @param dev Peripheral instance address
*/
static inline void ledc_ll_enable_mem_power(bool enable)
static inline void ledc_ll_mem_force_power_on(ledc_dev_t *dev)
{
PCR.ledc_pd_ctrl.ledc_mem_force_pd = !enable;
PCR.ledc_pd_ctrl.ledc_mem_force_pu = 1;
PCR.ledc_pd_ctrl.ledc_mem_force_pd = 0;
}
/**
* @brief Force the LEDC memory block into low power mode, regardless of the outside PMU logic
*
* @param dev Peripheral instance address
*/
static inline void ledc_ll_mem_force_low_power(ledc_dev_t *dev)
{
PCR.ledc_pd_ctrl.ledc_mem_force_pd = 1;
PCR.ledc_pd_ctrl.ledc_mem_force_pu = 0;
}
/**
* @brief Power control the LEDC memory block by the outside PMU logic
*
* @param dev Peripheral instance address
*/
static inline void ledc_ll_mem_power_by_pmu(ledc_dev_t *dev)
{
PCR.ledc_pd_ctrl.ledc_mem_force_pd = 0;
PCR.ledc_pd_ctrl.ledc_mem_force_pu = 0;
}
/**
* @brief Set low power mode for LEDC memory block
*
* @param dev Peripheral instance address
* @param mode LEDC memory low power mode in low power stage
*/
static inline void ledc_ll_mem_set_low_power_mode(ledc_dev_t *dev, ledc_ll_mem_lp_mode_t mode)
{
(void)dev;
HAL_ASSERT(mode == LEDC_LL_MEM_LP_MODE_SHUT_DOWN);
}
/**
@@ -138,6 +138,10 @@
extern "C" {
#endif
typedef enum {
LEDC_LL_MEM_LP_MODE_SHUT_DOWN, // power down memory during low power stage
} ledc_ll_mem_lp_mode_t;
/**
* @brief Enable peripheral register clock
*
@@ -163,13 +167,47 @@ static inline void ledc_ll_reset_register(int group_id)
}
/**
* @brief Enable the power for LEDC memory block
* @brief Force power on the LEDC memory block, regardless of the outside PMU logic
*
* @param dev Peripheral instance address
*/
static inline void ledc_ll_enable_mem_power(bool enable)
static inline void ledc_ll_mem_force_power_on(ledc_dev_t *dev)
{
// No LEDC memory block on C6
}
/**
* @brief Force the LEDC memory block into low power mode, regardless of the outside PMU logic
*
* @param dev Peripheral instance address
*/
static inline void ledc_ll_mem_force_low_power(ledc_dev_t *dev)
{
// No LEDC memory block on C6
}
/**
* @brief Power control the LEDC memory block by the outside PMU logic
*
* @param dev Peripheral instance address
*/
static inline void ledc_ll_mem_power_by_pmu(ledc_dev_t *dev)
{
// No LEDC memory block on C6
}
/**
* @brief Set low power mode for LEDC memory block
*
* @param dev Peripheral instance address
* @param mode LEDC memory low power mode in low power stage
*/
static inline void ledc_ll_mem_set_low_power_mode(ledc_dev_t *dev, ledc_ll_mem_lp_mode_t mode)
{
(void)dev;
HAL_ASSERT(mode == LEDC_LL_MEM_LP_MODE_SHUT_DOWN);
}
/**
* @brief Enable LEDC function clock
*
@@ -134,6 +134,10 @@
extern "C" {
#endif
typedef enum {
LEDC_LL_MEM_LP_MODE_SHUT_DOWN, // power down memory during low power stage
} ledc_ll_mem_lp_mode_t;
/**
* @brief Enable peripheral register clock
*
@@ -159,13 +163,48 @@ static inline void ledc_ll_reset_register(int group_id)
}
/**
* @brief Enable the power for LEDC memory block
* @brief Force power on the LEDC memory block, regardless of the outside PMU logic
*
* Note. This function cannot overwrite the power control of the mem block in sleep mode
* @param dev Peripheral instance address
*/
static inline void ledc_ll_enable_mem_power(bool enable)
static inline void ledc_ll_mem_force_power_on(ledc_dev_t *dev)
{
PCR.ledc_pd_ctrl.ledc_mem_force_pd = !enable;
PCR.ledc_pd_ctrl.ledc_mem_force_pu = 1;
PCR.ledc_pd_ctrl.ledc_mem_force_pd = 0;
}
/**
* @brief Force the LEDC memory block into low power mode, regardless of the outside PMU logic
*
* @param dev Peripheral instance address
*/
static inline void ledc_ll_mem_force_low_power(ledc_dev_t *dev)
{
PCR.ledc_pd_ctrl.ledc_mem_force_pd = 1;
PCR.ledc_pd_ctrl.ledc_mem_force_pu = 0;
}
/**
* @brief Power control the LEDC memory block by the outside PMU logic
*
* @param dev Peripheral instance address
*/
static inline void ledc_ll_mem_power_by_pmu(ledc_dev_t *dev)
{
PCR.ledc_pd_ctrl.ledc_mem_force_pd = 0;
PCR.ledc_pd_ctrl.ledc_mem_force_pu = 0;
}
/**
* @brief Set low power mode for LEDC memory block
*
* @param dev Peripheral instance address
* @param mode LEDC memory low power mode in low power stage
*/
static inline void ledc_ll_mem_set_low_power_mode(ledc_dev_t *dev, ledc_ll_mem_lp_mode_t mode)
{
(void)dev;
HAL_ASSERT(mode == LEDC_LL_MEM_LP_MODE_SHUT_DOWN);
}
/**
@@ -135,6 +135,10 @@
extern "C" {
#endif
typedef enum {
LEDC_LL_MEM_LP_MODE_SHUT_DOWN, // power down memory during low power stage
} ledc_ll_mem_lp_mode_t;
/**
* @brief Enable peripheral register clock
*
@@ -160,13 +164,47 @@ static inline void ledc_ll_reset_register(int group_id)
}
/**
* @brief Enable the power for LEDC memory block
* @brief Force power on the LEDC memory block, regardless of the outside PMU logic
*
* @param dev Peripheral instance address
*/
static inline void ledc_ll_enable_mem_power(bool enable)
static inline void ledc_ll_mem_force_power_on(ledc_dev_t *dev)
{
// No LEDC memory block on H2
}
/**
* @brief Force the LEDC memory block into low power mode, regardless of the outside PMU logic
*
* @param dev Peripheral instance address
*/
static inline void ledc_ll_mem_force_low_power(ledc_dev_t *dev)
{
// No LEDC memory block on H2
}
/**
* @brief Power control the LEDC memory block by the outside PMU logic
*
* @param dev Peripheral instance address
*/
static inline void ledc_ll_mem_power_by_pmu(ledc_dev_t *dev)
{
// No LEDC memory block on H2
}
/**
* @brief Set low power mode for LEDC memory block
*
* @param dev Peripheral instance address
* @param mode LEDC memory low power mode in low power stage
*/
static inline void ledc_ll_mem_set_low_power_mode(ledc_dev_t *dev, ledc_ll_mem_lp_mode_t mode)
{
(void)dev;
HAL_ASSERT(mode == LEDC_LL_MEM_LP_MODE_SHUT_DOWN);
}
/**
* @brief Enable LEDC function clock
*
@@ -135,6 +135,10 @@
extern "C" {
#endif
typedef enum {
LEDC_LL_MEM_LP_MODE_SHUT_DOWN, // power down memory during low power stage
} ledc_ll_mem_lp_mode_t;
/**
* @brief Enable peripheral register clock
*
@@ -160,11 +164,45 @@ static inline void ledc_ll_reset_register(int group_id)
}
/**
* @brief Enable the power for LEDC memory block
* @brief Force power on the LEDC memory block, regardless of the outside PMU logic
*
* @param dev Peripheral instance address
*/
static inline void ledc_ll_enable_mem_power(bool enable)
static inline void ledc_ll_mem_force_power_on(ledc_dev_t *dev)
{
// No LEDC memory block on H21
// No LEDC memory block on ESP32-H21
}
/**
* @brief Force the LEDC memory block into low power mode, regardless of the outside PMU logic
*
* @param dev Peripheral instance address
*/
static inline void ledc_ll_mem_force_low_power(ledc_dev_t *dev)
{
// No LEDC memory block on ESP32-H21
}
/**
* @brief Power control the LEDC memory block by the outside PMU logic
*
* @param dev Peripheral instance address
*/
static inline void ledc_ll_mem_power_by_pmu(ledc_dev_t *dev)
{
// No LEDC memory block on ESP32-H21
}
/**
* @brief Set low power mode for LEDC memory block
*
* @param dev Peripheral instance address
* @param mode LEDC memory low power mode in low power stage
*/
static inline void ledc_ll_mem_set_low_power_mode(ledc_dev_t *dev, ledc_ll_mem_lp_mode_t mode)
{
(void)dev;
HAL_ASSERT(mode == LEDC_LL_MEM_LP_MODE_SHUT_DOWN);
}
/**
@@ -134,6 +134,10 @@
extern "C" {
#endif
typedef enum {
LEDC_LL_MEM_LP_MODE_SHUT_DOWN, // power down memory during low power stage
} ledc_ll_mem_lp_mode_t;
/**
* @brief Enable peripheral register clock
*
@@ -159,11 +163,45 @@ static inline void ledc_ll_reset_register(int group_id)
}
/**
* @brief Enable the power for LEDC memory block
* @brief Force power on the LEDC memory block, regardless of the outside PMU logic
*
* @param dev Peripheral instance address
*/
static inline void ledc_ll_enable_mem_power(bool enable)
static inline void ledc_ll_mem_force_power_on(ledc_dev_t *dev)
{
// No LEDC memory block on H4
// No LEDC memory block on ESP32-H4
}
/**
* @brief Force the LEDC memory block into low power mode, regardless of the outside PMU logic
*
* @param dev Peripheral instance address
*/
static inline void ledc_ll_mem_force_low_power(ledc_dev_t *dev)
{
// No LEDC memory block on ESP32-H4
}
/**
* @brief Power control the LEDC memory block by the outside PMU logic
*
* @param dev Peripheral instance address
*/
static inline void ledc_ll_mem_power_by_pmu(ledc_dev_t *dev)
{
// No LEDC memory block on ESP32-H4
}
/**
* @brief Set low power mode for LEDC memory block
*
* @param dev Peripheral instance address
* @param mode LEDC memory low power mode in low power stage
*/
static inline void ledc_ll_mem_set_low_power_mode(ledc_dev_t *dev, ledc_ll_mem_lp_mode_t mode)
{
(void)dev;
HAL_ASSERT(mode == LEDC_LL_MEM_LP_MODE_SHUT_DOWN);
}
/**
@@ -134,6 +134,10 @@
extern "C" {
#endif
typedef enum {
LEDC_LL_MEM_LP_MODE_SHUT_DOWN, // power down memory during low power stage
} ledc_ll_mem_lp_mode_t;
/**
* @brief Enable peripheral register clock
*
@@ -173,13 +177,47 @@ static inline void ledc_ll_reset_register(int group_id)
} while(0)
/**
* @brief Enable the power for LEDC memory block
* @brief Force power on the LEDC memory block, regardless of the outside PMU logic
*
* @param dev Peripheral instance address
*/
static inline void ledc_ll_enable_mem_power(bool enable)
static inline void ledc_ll_mem_force_power_on(ledc_dev_t *dev)
{
// No register to control the power for LEDC memory block on P4
}
/**
* @brief Force the LEDC memory block into low power mode, regardless of the outside PMU logic
*
* @param dev Peripheral instance address
*/
static inline void ledc_ll_mem_force_low_power(ledc_dev_t *dev)
{
// No register to control the power for LEDC memory block on P4
}
/**
* @brief Power control the LEDC memory block by the outside PMU logic
*
* @param dev Peripheral instance address
*/
static inline void ledc_ll_mem_power_by_pmu(ledc_dev_t *dev)
{
// No register to control the power for LEDC memory block on P4
}
/**
* @brief Set low power mode for LEDC memory block
*
* @param dev Peripheral instance address
* @param mode LEDC memory low power mode in low power stage
*/
static inline void ledc_ll_mem_set_low_power_mode(ledc_dev_t *dev, ledc_ll_mem_lp_mode_t mode)
{
(void)dev;
HAL_ASSERT(mode == LEDC_LL_MEM_LP_MODE_SHUT_DOWN);
}
/**
* @brief Enable LEDC function clock
*
@@ -56,6 +56,10 @@
extern "C" {
#endif
typedef enum {
LEDC_LL_MEM_LP_MODE_SHUT_DOWN, // power down memory during low power stage
} ledc_ll_mem_lp_mode_t;
/**
* @brief Enable peripheral register clock
*
@@ -99,11 +103,45 @@ static inline void ledc_ll_reset_register(int group_id)
} while(0)
/**
* @brief Enable the power for LEDC memory block
* @brief Force power on the LEDC memory block, regardless of the outside PMU logic
*
* @param dev Peripheral instance address
*/
static inline void ledc_ll_enable_mem_power(bool enable)
static inline void ledc_ll_mem_force_power_on(ledc_dev_t *dev)
{
// No LEDC mem block on S2
// No LEDC memory block on S2
}
/**
* @brief Force the LEDC memory block into low power mode, regardless of the outside PMU logic
*
* @param dev Peripheral instance address
*/
static inline void ledc_ll_mem_force_low_power(ledc_dev_t *dev)
{
// No LEDC memory block on S2
}
/**
* @brief Power control the LEDC memory block by the outside PMU logic
*
* @param dev Peripheral instance address
*/
static inline void ledc_ll_mem_power_by_pmu(ledc_dev_t *dev)
{
// No LEDC memory block on S2
}
/**
* @brief Set low power mode for LEDC memory block
*
* @param dev Peripheral instance address
* @param mode LEDC memory low power mode in low power stage
*/
static inline void ledc_ll_mem_set_low_power_mode(ledc_dev_t *dev, ledc_ll_mem_lp_mode_t mode)
{
(void)dev;
HAL_ASSERT(mode == LEDC_LL_MEM_LP_MODE_SHUT_DOWN);
}
/**
@@ -51,6 +51,10 @@
extern "C" {
#endif
typedef enum {
LEDC_LL_MEM_LP_MODE_SHUT_DOWN, // power down memory during low power stage
} ledc_ll_mem_lp_mode_t;
/**
* @brief Enable peripheral register clock
*
@@ -90,11 +94,45 @@ static inline void ledc_ll_reset_register(int group_id)
} while(0)
/**
* @brief Enable the power for LEDC memory block
* @brief Force power on the LEDC memory block, regardless of the outside PMU logic
*
* @param dev Peripheral instance address
*/
static inline void ledc_ll_enable_mem_power(bool enable)
static inline void ledc_ll_mem_force_power_on(ledc_dev_t *dev)
{
// No LEDC mem block on S3
// No LEDC memory block on S3
}
/**
* @brief Force the LEDC memory block into low power mode, regardless of the outside PMU logic
*
* @param dev Peripheral instance address
*/
static inline void ledc_ll_mem_force_low_power(ledc_dev_t *dev)
{
// No LEDC memory block on S3
}
/**
* @brief Power control the LEDC memory block by the outside PMU logic
*
* @param dev Peripheral instance address
*/
static inline void ledc_ll_mem_power_by_pmu(ledc_dev_t *dev)
{
// No LEDC memory block on S3
}
/**
* @brief Set low power mode for LEDC memory block
*
* @param dev Peripheral instance address
* @param mode LEDC memory low power mode in low power stage
*/
static inline void ledc_ll_mem_set_low_power_mode(ledc_dev_t *dev, ledc_ll_mem_lp_mode_t mode)
{
(void)dev;
HAL_ASSERT(mode == LEDC_LL_MEM_LP_MODE_SHUT_DOWN);
}
/**
@@ -0,0 +1,929 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
// The LL layer for LEDC register operations.
// Note that most of the register operations in this layer are non-atomic operations.
#pragma once
#include <stddef.h>
#include <stdint.h>
#include "hal/assert.h"
#include "hal/ledc_types.h"
#include "soc/ledc_struct.h"
#include "soc/ledc_reg.h"
#include "soc/clk_tree_defs.h"
#include "soc/hp_sys_clkrst_struct.h"
#include "soc/hp_system_struct.h"
#include "soc/soc_caps.h"
#include "soc/soc_etm_source.h"
#define LEDC_LL_GET(attr) (LEDC_LL_ ## attr)
#define LEDC_LL_GET_HW(group_id) ((group_id == 0) ? &LEDC0 : (group_id == 1) ? &LEDC1 : NULL)
#define LEDC_LL_GROUP_NUM (2)
#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
/// Get the mask of the duty change end interrupt status register.
#define LEDC_LL_DUTY_CHANGE_END_INTR_MASK(speed_mode) (0xffUL << LEDC_DUTY_CHNG_END_CH0_INT_ENA_S)
#define LEDC_LL_EVENT_CHANNEL_DUTY_CHANGE_END(speed_mode, channel) BIT(LEDC_DUTY_CHNG_END_CH0_INT_ENA_S + (channel))
#define LEDC_LL_EVENT_CHANNEL_OVF_CNT(speed_mode, channel) BIT(LEDC_OVF_CNT_CH0_INT_ENA_S + (channel))
#define LEDC_LL_EVENT_CHANNEL_MASK(speed_mode, channel) (LEDC_LL_EVENT_CHANNEL_DUTY_CHANGE_END(speed_mode, channel) | LEDC_LL_EVENT_CHANNEL_OVF_CNT(speed_mode, channel))
// ETM: LEDC1 vs LEDC0 uses a fixed task/event index step and identical MMIO layout at +reg stride.
#define LEDC_LL_ETM_TASK_ID_GROUP_OFS (LEDC1_TASK_DUTY_SCALE_UPDATE_CH0 - LEDC0_TASK_DUTY_SCALE_UPDATE_CH0)
#define LEDC_LL_ETM_EVENT_ID_GROUP_OFS (LEDC1_EVT_DUTY_CHNG_END_CH0 - LEDC0_EVT_DUTY_CHNG_END_CH0)
#define LEDC_LL_ETM_REG_GROUP_OFS (DR_REG_LEDC1_BASE - DR_REG_LEDC0_BASE)
// 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] = LEDC0_TASK_DUTY_SCALE_UPDATE_CH0, \
[LEDC_CHANNEL_ETM_TASK_SIG_OUT_DIS] = LEDC0_TASK_SIG_OUT_DIS_CH0, \
[LEDC_CHANNEL_ETM_TASK_OVF_CNT_RST] = LEDC0_TASK_OVF_CNT_RST_CH0, \
[LEDC_CHANNEL_ETM_TASK_FADE_RESTART] = LEDC0_TASK_GAMMA_RESTART_CH0, \
[LEDC_CHANNEL_ETM_TASK_FADE_PAUSE] = LEDC0_TASK_GAMMA_PAUSE_CH0, \
[LEDC_CHANNEL_ETM_TASK_FADE_RESUME] = LEDC0_TASK_GAMMA_RESUME_CH0, \
}}[0][(task)] + (channel) + (uint32_t)(group) * LEDC_LL_ETM_TASK_ID_GROUP_OFS)
#define LEDC_LL_ETM_CHANNEL_TASK_EN_REG(group, task) \
((volatile uint32_t *)((uintptr_t)((volatile uint32_t *[1][LEDC_CHANNEL_ETM_TASK_MAX]){{ \
[LEDC_CHANNEL_ETM_TASK_FADE_SCALE_UPDATE] = (volatile uint32_t *)LEDC_EVT_TASK_EN0_REG(0), \
[LEDC_CHANNEL_ETM_TASK_SIG_OUT_DIS] = (volatile uint32_t *)LEDC_EVT_TASK_EN1_REG(0), \
[LEDC_CHANNEL_ETM_TASK_OVF_CNT_RST] = (volatile uint32_t *)LEDC_EVT_TASK_EN1_REG(0), \
[LEDC_CHANNEL_ETM_TASK_FADE_RESTART] = (volatile uint32_t *)LEDC_EVT_TASK_EN2_REG(0), \
[LEDC_CHANNEL_ETM_TASK_FADE_PAUSE] = (volatile uint32_t *)LEDC_EVT_TASK_EN2_REG(0), \
[LEDC_CHANNEL_ETM_TASK_FADE_RESUME] = (volatile uint32_t *)LEDC_EVT_TASK_EN2_REG(0), \
}}[0][(task)]) + (uintptr_t)(group) * LEDC_LL_ETM_REG_GROUP_OFS))
#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), \
}}[0][(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] = LEDC0_EVT_DUTY_CHNG_END_CH0, \
[LEDC_CHANNEL_ETM_EVENT_REACH_MAX_OVF_CNT] = LEDC0_EVT_OVF_CNT_PLS_CH0, \
}}[0][(event)] + (channel) + (uint32_t)(group) * LEDC_LL_ETM_EVENT_ID_GROUP_OFS)
#define LEDC_LL_ETM_CHANNEL_EVENT_EN_REG(group, event) \
((volatile uint32_t *)((uintptr_t)((volatile uint32_t *[1][LEDC_CHANNEL_ETM_EVENT_MAX]){{ \
[LEDC_CHANNEL_ETM_EVENT_FADE_END] = (volatile uint32_t *)LEDC_EVT_TASK_EN0_REG(0), \
[LEDC_CHANNEL_ETM_EVENT_REACH_MAX_OVF_CNT] = (volatile uint32_t *)LEDC_EVT_TASK_EN0_REG(0), \
}}[0][(event)]) + (uintptr_t)(group) * LEDC_LL_ETM_REG_GROUP_OFS))
#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), \
}}[0][(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] = LEDC0_TASK_TIMER0_RST, \
[LEDC_TIMER_ETM_TASK_RESUME] = LEDC0_TASK_TIMER0_RESUME, \
[LEDC_TIMER_ETM_TASK_PAUSE] = LEDC0_TASK_TIMER0_PAUSE, \
}}[0][(task)] + (timer) + (uint32_t)(group) * LEDC_LL_ETM_TASK_ID_GROUP_OFS)
#define LEDC_LL_ETM_TIMER_TASK_EN_REG(group, task) \
((volatile uint32_t *)((uintptr_t)((volatile uint32_t *[1][LEDC_TIMER_ETM_TASK_MAX]){{ \
[LEDC_TIMER_ETM_TASK_RST] = (volatile uint32_t *)LEDC_EVT_TASK_EN1_REG(0), \
[LEDC_TIMER_ETM_TASK_RESUME] = (volatile uint32_t *)LEDC_EVT_TASK_EN1_REG(0), \
[LEDC_TIMER_ETM_TASK_PAUSE] = (volatile uint32_t *)LEDC_EVT_TASK_EN1_REG(0), \
}}[0][(task)]) + (uintptr_t)(group) * LEDC_LL_ETM_REG_GROUP_OFS))
#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), \
}}[0][(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] = LEDC0_EVT_TIME_OVF_TIMER0, \
}}[0][(event)] + (timer) + (uint32_t)(group) * LEDC_LL_ETM_EVENT_ID_GROUP_OFS)
#define LEDC_LL_ETM_TIMER_EVENT_EN_REG(group, event) \
((volatile uint32_t *)((uintptr_t)((volatile uint32_t *[1][LEDC_TIMER_ETM_EVENT_MAX]){{ \
[LEDC_TIMER_ETM_EVENT_OVF] = (volatile uint32_t *)LEDC_EVT_TASK_EN0_REG(0), \
}}[0][(event)]) + (uintptr_t)(group) * LEDC_LL_ETM_REG_GROUP_OFS))
#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), \
}}[0][(event)] << (timer))
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
LEDC_LL_MEM_LP_MODE_DEEP_SLEEP, // memory will enter deep sleep during low power stage, keep memory data
LEDC_LL_MEM_LP_MODE_LIGHT_SLEEP, // memory will enter light sleep during low power stage, keep memory data
LEDC_LL_MEM_LP_MODE_SHUT_DOWN, // memory will be powered down during low power stage
LEDC_LL_MEM_LP_MODE_DISABLE, // disable the low power stage
} ledc_ll_mem_lp_mode_t;
/**
* @brief Enable peripheral register clock
*
* @param group_id LEDC group ID
* @param enable Enable/Disable
*/
static inline void ledc_ll_enable_bus_clock(int group_id, bool enable)
{
switch (group_id) {
case 0:
HP_SYS_CLKRST.ledc_ctrl0.reg_ledc0_apb_clk_en = enable;
break;
case 1:
HP_SYS_CLKRST.ledc_ctrl0.reg_ledc1_apb_clk_en = enable;
break;
default:
abort();
break;
}
}
/// use a macro to wrap the function, force the caller to use it in a critical section
/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance
#define ledc_ll_enable_bus_clock(...) do { \
(void)__DECLARE_RCC_ATOMIC_ENV; \
ledc_ll_enable_bus_clock(__VA_ARGS__); \
} while(0)
/**
* @brief Reset whole peripheral register to init value defined by HW design
*
* @param group_id LEDC group ID
*/
static inline void ledc_ll_reset_register(int group_id)
{
switch (group_id) {
case 0:
HP_SYS_CLKRST.ledc_ctrl0.reg_ledc0_rst_en = 1;
HP_SYS_CLKRST.ledc_ctrl0.reg_ledc0_rst_en = 0;
break;
case 1:
HP_SYS_CLKRST.ledc_ctrl0.reg_ledc1_rst_en = 1;
HP_SYS_CLKRST.ledc_ctrl0.reg_ledc1_rst_en = 0;
break;
default:
abort();
break;
}
}
/// use a macro to wrap the function, force the caller to use it in a critical section
/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance
#define ledc_ll_reset_register(...) do { \
(void)__DECLARE_RCC_ATOMIC_ENV; \
ledc_ll_reset_register(__VA_ARGS__); \
} while(0)
/**
* @brief Force power on the LEDC memory block, regardless of the outside PMU logic
*
* @param dev Peripheral instance address
*/
static inline void ledc_ll_mem_force_power_on(ledc_dev_t *dev)
{
if (dev == &LEDC0) {
HP_SYSTEM.sys_ledc0_mem_lp_ctrl.sys_ledc0_mem_force_ctrl = 1;
HP_SYSTEM.sys_ledc0_mem_lp_ctrl.sys_ledc0_mem_lp_en = 0;
} else if (dev == &LEDC1) {
HP_SYSTEM.sys_ledc1_mem_lp_ctrl.sys_ledc1_mem_force_ctrl = 1;
HP_SYSTEM.sys_ledc1_mem_lp_ctrl.sys_ledc1_mem_lp_en = 0;
} else {
abort();
}
}
/**
* @brief Force the LEDC memory block into low power mode, regardless of the outside PMU logic
*
* @param dev Peripheral instance address
*/
static inline void ledc_ll_mem_force_low_power(ledc_dev_t *dev)
{
if (dev == &LEDC0) {
HP_SYSTEM.sys_ledc0_mem_lp_ctrl.sys_ledc0_mem_force_ctrl = 1;
HP_SYSTEM.sys_ledc0_mem_lp_ctrl.sys_ledc0_mem_lp_en = 1;
} else if (dev == &LEDC1) {
HP_SYSTEM.sys_ledc1_mem_lp_ctrl.sys_ledc1_mem_force_ctrl = 1;
HP_SYSTEM.sys_ledc1_mem_lp_ctrl.sys_ledc1_mem_lp_en = 1;
} else {
abort();
}
}
/**
* @brief Power control the LEDC memory block by the outside PMU logic
*
* @param dev Peripheral instance address
*/
static inline void ledc_ll_mem_power_by_pmu(ledc_dev_t *dev)
{
if (dev == &LEDC0) {
HP_SYSTEM.sys_ledc0_mem_lp_ctrl.sys_ledc0_mem_force_ctrl = 0;
HP_SYSTEM.sys_ledc0_mem_lp_ctrl.sys_ledc0_mem_lp_en = 0;
} else if (dev == &LEDC1) {
HP_SYSTEM.sys_ledc1_mem_lp_ctrl.sys_ledc1_mem_force_ctrl = 0;
HP_SYSTEM.sys_ledc1_mem_lp_ctrl.sys_ledc1_mem_lp_en = 0;
} else {
abort();
}
}
/**
* @brief Set low power mode for LEDC memory block
*
* @param dev Peripheral instance address
* @param mode LEDC memory low power mode in low power stage
*/
static inline void ledc_ll_mem_set_low_power_mode(ledc_dev_t *dev, ledc_ll_mem_lp_mode_t mode)
{
if (dev == &LEDC0) {
HP_SYSTEM.sys_ledc0_mem_lp_ctrl.sys_ledc0_mem_lp_mode = mode;
} else if (dev == &LEDC1) {
HP_SYSTEM.sys_ledc1_mem_lp_ctrl.sys_ledc1_mem_lp_mode = mode;
} else {
abort();
}
}
/**
* @brief Enable LEDC function clock
*
* @param group_id LEDC group ID
* @param en True to enable, false to disable
*
* @return None
*/
static inline void ledc_ll_enable_clock(int group_id, bool en)
{
switch (group_id) {
case 0:
HP_SYS_CLKRST.ledc_ctrl0.reg_ledc0_clk_en = en;
break;
case 1:
HP_SYS_CLKRST.ledc_ctrl0.reg_ledc1_clk_en = en;
break;
default:
abort();
break;
}
}
/// use a macro to wrap the function, force the caller to use it in a critical section
/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance
#define ledc_ll_enable_clock(...) do { \
(void)__DECLARE_RCC_ATOMIC_ENV; \
ledc_ll_enable_clock(__VA_ARGS__); \
} while(0)
/**
* @brief Enable the power for LEDC channel
*
* @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-7), select from ledc_channel_t
* @param en True to enable, false to disable
*/
static inline void ledc_ll_enable_channel_power(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel_num, bool en)
{
if (en) {
hw->ch_power_up_conf.val |= BIT(speed_mode * SOC_LEDC_CHANNEL_NUM + channel_num);
} else {
hw->ch_power_up_conf.val &= ~BIT(speed_mode * SOC_LEDC_CHANNEL_NUM + channel_num);
}
}
/**
* @brief Enable the power for LEDC timer
*
* @param hw Beginning address of the peripheral registers
* @param speed_mode LEDC speed_mode, low-speed mode only
* @param timer_sel LEDC timer index (0-3), select from ledc_timer_t
* @param en True to enable, false to disable
*/
static inline void ledc_ll_enable_timer_power(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_timer_t timer_sel, bool en)
{
if (en) {
hw->timer_power_up_conf.val |= BIT(speed_mode * SOC_LEDC_TIMER_NUM + timer_sel);
} else {
hw->timer_power_up_conf.val &= ~BIT(speed_mode * SOC_LEDC_TIMER_NUM + timer_sel);
}
}
/**
* @brief Set LEDC low speed timer clock
*
* @param hw Beginning address of the peripheral registers
* @param slow_clk_sel LEDC low speed timer clock source
*
* @return None
*/
static inline void ledc_ll_set_slow_clk_sel(ledc_dev_t *hw, ledc_slow_clk_sel_t slow_clk_sel)
{
uint32_t clk_sel_val = 3;
switch (slow_clk_sel) {
case LEDC_SLOW_CLK_XTAL:
clk_sel_val = 0;
break;
case LEDC_SLOW_CLK_RC_FAST:
clk_sel_val = 1;
break;
case LEDC_SLOW_CLK_PLL_DIV:
clk_sel_val = 2;
break;
default:
abort();
break;
}
if (hw == &LEDC0) {
HP_SYS_CLKRST.ledc_ctrl0.reg_ledc0_clk_src_sel = clk_sel_val;
} else if (hw == &LEDC1) {
HP_SYS_CLKRST.ledc_ctrl0.reg_ledc1_clk_src_sel = clk_sel_val;
} else {
abort();
}
}
/// use a macro to wrap the function, force the caller to use it in a critical section
/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance
#define ledc_ll_set_slow_clk_sel(...) do { \
(void)__DECLARE_RCC_ATOMIC_ENV; \
ledc_ll_set_slow_clk_sel(__VA_ARGS__); \
} while(0)
/**
* @brief Get LEDC low speed timer clock
*
* @param hw Beginning address of the peripheral registers
* @param slow_clk_sel LEDC low speed timer clock source
*
* @return None
*/
static inline void ledc_ll_get_slow_clk_sel(ledc_dev_t *hw, ledc_slow_clk_sel_t *slow_clk_sel)
{
uint32_t clk_sel_val = 3;
if (hw == &LEDC0) {
clk_sel_val = HP_SYS_CLKRST.ledc_ctrl0.reg_ledc0_clk_src_sel;
} else if (hw == &LEDC1) {
clk_sel_val = HP_SYS_CLKRST.ledc_ctrl0.reg_ledc1_clk_src_sel;
} else {
abort();
}
switch (clk_sel_val) {
case 0:
*slow_clk_sel = LEDC_SLOW_CLK_XTAL;
break;
case 1:
*slow_clk_sel = LEDC_SLOW_CLK_RC_FAST;
break;
case 2:
*slow_clk_sel = LEDC_SLOW_CLK_PLL_DIV;
break;
default:
abort();
break;
}
}
/**
* @brief Update LEDC low speed timer
*
* @param hw Beginning address of the peripheral registers
* @param speed_mode LEDC speed_mode, low-speed mode only
* @param timer_sel LEDC timer index (0-3), select from ledc_timer_t
*
* @return None
*/
static inline void ledc_ll_ls_timer_update(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_timer_t timer_sel)
{
hw->timer_group[speed_mode].timer[timer_sel].conf.para_up = 1;
// Here, we don't wait for the bit gets cleared since it can take quite long depends on the pwm frequency
}
/**
* @brief Reset LEDC timer
*
* @param hw Beginning address of the peripheral registers
* @param speed_mode LEDC speed_mode, low-speed mode only
* @param timer_sel LEDC timer index (0-3), select from ledc_timer_t
*
* @return None
*/
static inline void ledc_ll_timer_rst(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_timer_t timer_sel)
{
hw->timer_group[speed_mode].timer[timer_sel].conf.rst = 1;
hw->timer_group[speed_mode].timer[timer_sel].conf.rst = 0;
}
/**
* @brief Pause LEDC timer
*
* @param hw Beginning address of the peripheral registers
* @param speed_mode LEDC speed_mode, low-speed mode only
* @param timer_sel LEDC timer index (0-3), select from ledc_timer_t
*
* @return None
*/
static inline void ledc_ll_timer_pause(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_timer_t timer_sel)
{
hw->timer_group[speed_mode].timer[timer_sel].conf.pause = 1;
}
/**
* @brief Resume LEDC timer
*
* @param hw Beginning address of the peripheral registers
* @param speed_mode LEDC speed_mode, low-speed mode only
* @param timer_sel LEDC timer index (0-3), select from ledc_timer_t
*
* @return None
*/
static inline void ledc_ll_timer_resume(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_timer_t timer_sel)
{
hw->timer_group[speed_mode].timer[timer_sel].conf.pause = 0;
}
/**
* @brief Set LEDC timer clock divider
*
* @param hw Beginning address of the peripheral registers
* @param speed_mode LEDC speed_mode, low-speed mode only
* @param timer_sel LEDC timer index (0-3), select from ledc_timer_t
* @param clock_divider Timer clock divide value, the timer clock is divided from the selected clock source
*
* @return None
*/
static inline void ledc_ll_set_clock_divider(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_timer_t timer_sel, uint32_t clock_divider)
{
hw->timer_group[speed_mode].timer[timer_sel].conf.clk_div = clock_divider;
}
/**
* @brief Get LEDC timer clock divider
*
* @param hw Beginning address of the peripheral registers
* @param speed_mode LEDC speed_mode, low-speed mode only
* @param timer_sel LEDC timer index (0-3), select from ledc_timer_t
* @param clock_divider Timer clock divide value, the timer clock is divided from the selected clock source
*
* @return None
*/
static inline void ledc_ll_get_clock_divider(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_timer_t timer_sel, uint32_t *clock_divider)
{
*clock_divider = hw->timer_group[speed_mode].timer[timer_sel].conf.clk_div;
}
/**
* @brief Get LEDC timer clock source
*
* @param hw Beginning address of the peripheral registers
* @param speed_mode LEDC speed_mode, low-speed mode only
* @param timer_sel LEDC timer index (0-3), select from ledc_timer_t
* @param clk_src Pointer to accept the timer clock source
*
* @return None
*/
static inline void ledc_ll_get_clock_source(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_timer_t timer_sel, ledc_clk_src_t *clk_src)
{
// The target has no timer-specific clock source option
*clk_src = LEDC_SCLK;
}
/**
* @brief Set LEDC duty resolution
*
* @param hw Beginning address of the peripheral registers
* @param speed_mode LEDC speed_mode, low-speed mode only
* @param timer_sel LEDC timer index (0-3), select from ledc_timer_t
* @param duty_resolution Resolution of duty setting in number of bits. The range of duty values is [0, (2**duty_resolution)]
*
* @return None
*/
static inline void ledc_ll_set_duty_resolution(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_timer_t timer_sel, uint32_t duty_resolution)
{
hw->timer_group[speed_mode].timer[timer_sel].conf.duty_res = duty_resolution;
}
/**
* @brief Get LEDC duty resolution
*
* @param hw Beginning address of the peripheral registers
* @param speed_mode LEDC speed_mode, low-speed mode only
* @param timer_sel LEDC timer index (0-3), select from ledc_timer_t
* @param duty_resolution Pointer to accept the resolution of duty setting in number of bits.
*
* @return None
*/
static inline void ledc_ll_get_duty_resolution(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_timer_t timer_sel, uint32_t *duty_resolution)
{
*duty_resolution = hw->timer_group[speed_mode].timer[timer_sel].conf.duty_res;
}
/**
* @brief Get LEDC max duty
*
* @param hw Beginning address of the peripheral registers
* @param speed_mode LEDC speed_mode, low-speed mode only
* @param timer_sel LEDC timer index (0-3), select from ledc_timer_t
* @param max_duty Pointer to accept the max duty
*
* @return None
*/
static inline void ledc_ll_get_max_duty(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_timer_t timer_sel, uint32_t *max_duty)
{
*max_duty = (1 << (hw->timer_group[speed_mode].timer[timer_sel].conf.duty_res));
}
/**
* @brief Update channel configure when select low 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-7), select from ledc_channel_t
*
* @return None
*/
static inline void ledc_ll_ls_channel_update(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel_num)
{
hw->channel_group[speed_mode].channel[channel_num].conf0.para_up = 1;
}
/**
* @brief Set LEDC hpoint value
*
* @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-7), select from ledc_channel_t
* @param hpoint_val LEDC hpoint value(max: 0xfffff)
*
* @return None
*/
static inline void ledc_ll_set_hpoint(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel_num, uint32_t hpoint_val)
{
hw->channel_group[speed_mode].channel[channel_num].hpoint.hpoint = hpoint_val;
}
/**
* @brief Get LEDC hpoint value
*
* @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-7), select from ledc_channel_t
* @param hpoint_val Pointer to accept the LEDC hpoint value(max: 0xfffff)
*
* @return None
*/
static inline void ledc_ll_get_hpoint(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel_num, uint32_t *hpoint_val)
{
*hpoint_val = hw->channel_group[speed_mode].channel[channel_num].hpoint.hpoint;
}
/**
* @brief Set LEDC the integer part of duty value
*
* @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-7), select from ledc_channel_t
* @param duty_val LEDC duty value, the range of duty setting is [0, (2**duty_resolution)]
*
* @return None
*/
static inline void ledc_ll_set_duty_int_part(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel_num, uint32_t duty_val)
{
hw->channel_group[speed_mode].channel[channel_num].duty_init.duty = duty_val << 4;
}
/**
* @brief Get LEDC duty value
*
* @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-7), select from ledc_channel_t
* @param duty_val Pointer to accept the LEDC duty value
*
* @return None
*/
static inline void ledc_ll_get_duty(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel_num, uint32_t *duty_val)
{
*duty_val = (hw->channel_group[speed_mode].channel[channel_num].duty_r.duty_r >> 4);
}
/**
* @brief Function to set fade parameters all-in-one
*
* @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-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
* @param scale The step scale
* @param step The number of increased or decreased times
*
* @return None
*/
static inline void ledc_ll_set_fade_param_range(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel_num, uint8_t range, uint32_t dir, uint32_t cycle, uint32_t scale, uint32_t step)
{
HAL_ASSERT(range < SOC_LEDC_GAMMA_CURVE_FADE_RANGE_MAX);
ledc_channel_gamma_fade_param_t range_param = {};
range_param.duty_inc = dir;
range_param.duty_cycle = cycle;
range_param.scale = scale;
range_param.duty_num = step;
if (hw == &LEDC0) {
LEDC0_GAMMA_RAM.channel[channel_num].entry[range].val = range_param.val;
} else if (hw == &LEDC1) {
LEDC1_GAMMA_RAM.channel[channel_num].entry[range].val = range_param.val;
} else {
abort();
}
}
/**
* @brief Set the total number of ranges in one fading
*
* @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-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
*/
static inline void ledc_ll_set_range_number(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel_num, uint32_t range_num)
{
hw->channel_gamma_conf_group[speed_mode].gamma_conf[channel_num].gamma_entry_num = range_num;
}
/**
* @brief Get the total number of ranges in one fading
*
* @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-7), select from ledc_channel_t
* @param range_num Pointer to accept fade range number
*
* @return None
*/
static inline void ledc_ll_get_range_number(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel_num, uint32_t *range_num)
{
*range_num = hw->channel_gamma_conf_group[speed_mode].gamma_conf[channel_num].gamma_entry_num;
}
/**
* @brief Get fade configurations in gamma_rd register
*
* @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-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
* @param scale Pointer to accept fade scale value
* @param step Pointer to accept fade step value
*
* @return None
*/
static inline void ledc_ll_get_fade_param_range(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel_num, uint8_t range, uint32_t *dir, uint32_t *cycle, uint32_t *scale, uint32_t *step)
{
ledc_channel_gamma_fade_param_t range_param = {
.val = (hw == &LEDC0) ? LEDC0_GAMMA_RAM.channel[channel_num].entry[range].val :
(hw == &LEDC1) ? LEDC1_GAMMA_RAM.channel[channel_num].entry[range].val : 0,
};
*dir = range_param.duty_inc;
*cycle = range_param.duty_cycle;
*scale = range_param.scale;
*step = range_param.duty_num;
}
/**
* @brief Set the output enable
*
* @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-7), select from ledc_channel_t
* @param sig_out_en The output enable status
*
* @return None
*/
__attribute__((always_inline))
static inline void ledc_ll_set_sig_out_en(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel_num, bool sig_out_en)
{
hw->channel_group[speed_mode].channel[channel_num].conf0.sig_out_en = sig_out_en;
}
/**
* @brief Set the duty start
*
* @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-7), select from ledc_channel_t
*
* @return None
*/
static inline void ledc_ll_set_duty_start(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel_num)
{
hw->channel_group[speed_mode].channel[channel_num].conf1.duty_start = 1;
}
/**
* @brief Set output idle level
*
* @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-7), select from ledc_channel_t
* @param idle_level The output idle level
*
* @return None
*/
__attribute__((always_inline))
static inline void ledc_ll_set_idle_level(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel_num, uint32_t idle_level)
{
hw->channel_group[speed_mode].channel[channel_num].conf0.idle_lv = idle_level & 0x1;
}
/**
* @brief Enable LEDC interrupt for specific event mask
*
* @param hw Beginning address of the peripheral registers
* @param mask Interrupt enable mask
* @param enable True to enable, False to disable
*/
__attribute__((always_inline))
static inline void ledc_ll_enable_interrupt(ledc_dev_t *hw, uint32_t mask, bool enable)
{
if (enable) {
hw->int_ena.val |= mask;
} else {
hw->int_ena.val &= ~mask;
}
}
/**
* @brief Get interrupt status.
*
* @param hw Beginning address of the peripheral registers
*
* @return Interrupt status.
*/
__attribute__((always_inline))
static inline uint32_t ledc_ll_get_intr_status(ledc_dev_t *hw)
{
return hw->int_st.val;
}
/**
* @brief Get the address of the interrupt status register.
*
* @param hw Beginning address of the peripheral registers
* @return Pointer to the interrupt status register.
*/
static inline volatile void* ledc_ll_get_intr_status_reg(ledc_dev_t *hw)
{
return (volatile void *)&hw->int_st;
}
/**
* @brief Clear interrupt status.
*
* @param hw Beginning address of the peripheral registers
* @param intr_mask Interrupt status mask to clear
*
* @return None
*/
__attribute__((always_inline))
static inline void ledc_ll_clear_intr_status(ledc_dev_t *hw, uint32_t intr_mask)
{
hw->int_clr.val = intr_mask;
}
/**
* @brief Set timer index of the specified channel
*
* @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-7), select from ledc_channel_t
* @param timer_sel LEDC timer index (0-3), select from ledc_timer_t
*
* @return None
*/
static inline void ledc_ll_bind_channel_timer(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel_num, ledc_timer_t timer_sel)
{
hw->channel_group[speed_mode].channel[channel_num].conf0.timer_sel = timer_sel;
}
/**
* @brief Get timer index of the specified channel
*
* @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-7), select from ledc_channel_t
* @param timer_sel Pointer to accept the LEDC timer index
*
* @return None
*/
static inline void ledc_ll_get_channel_timer(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel_num, ledc_timer_t *timer_sel)
{
*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-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
@@ -0,0 +1,284 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "hal/ledc_periph.h"
#include "soc/gpio_sig_map.h"
#include "soc/ledc_reg.h"
/*
Bunch of constants for every LEDC peripheral: GPIO signals
*/
const ledc_signal_conn_t ledc_periph_signal[2] = {
{
.irq_id = ETS_LEDC0_INTR_SOURCE,
.speed_mode = {
[0] = {
.sig_out_idx = {
LEDC0_LS_SIG_OUT_PAD_OUT0_IDX,
LEDC0_LS_SIG_OUT_PAD_OUT1_IDX,
LEDC0_LS_SIG_OUT_PAD_OUT2_IDX,
LEDC0_LS_SIG_OUT_PAD_OUT3_IDX,
LEDC0_LS_SIG_OUT_PAD_OUT4_IDX,
LEDC0_LS_SIG_OUT_PAD_OUT5_IDX,
LEDC0_LS_SIG_OUT_PAD_OUT6_IDX,
LEDC0_LS_SIG_OUT_PAD_OUT7_IDX,
}
},
},
},
{
.irq_id = ETS_LEDC1_INTR_SOURCE,
.speed_mode = {
[0] = {
.sig_out_idx = {
LEDC1_LS_SIG_OUT_PAD_OUT0_IDX,
LEDC1_LS_SIG_OUT_PAD_OUT1_IDX,
LEDC1_LS_SIG_OUT_PAD_OUT2_IDX,
LEDC1_LS_SIG_OUT_PAD_OUT3_IDX,
LEDC1_LS_SIG_OUT_PAD_OUT4_IDX,
LEDC1_LS_SIG_OUT_PAD_OUT5_IDX,
LEDC1_LS_SIG_OUT_PAD_OUT6_IDX,
LEDC1_LS_SIG_OUT_PAD_OUT7_IDX,
}
},
},
},
};
/**
* LEDC registers to be saved for sleep retention
*
* channel:
* LEDC_CHx_CONF0_REG, LEDC_CHx_HPOINT_REG, LEDC_CHx_DUTY_R_REG -> LEDC_CHx_DUTY_REG,
* LEDC_CHx_GAMMA_CONF_REG, LEDC_CHx_GAMMA_RANGEi_REG
*
* timer:
* LEDC_TIMERn_CONF_REG, LEDC_TIMERn_CMP_REG,
*
* common:
* LEDC_INT_ENA_REG,
* LEDC_EVT_TASK_EN0_REG, LEDC_EVT_TASK_EN1_REG, LEDC_EVT_TASK_EN2_REG,
* LEDC_CONF_REG,
* LEDC_CH_POWER_UP_CONF_REG, LEDC_TIMER_POWER_UP_CONF_REG
*
* Note 1: Gamma parameter registers are backuped and restored. But we won't start a fade automatically after wake-up.
* Instead, we will only start a PWM with a fixed duty cycle, the same value as before entering the sleep.
*
* Note 2: For timer/channel registers to get synced, update bits need to be set
*
* Note 3: Gamma RAM registers R/W relies both APB and function clock, therefore, retention requires the existence of function clock
*/
#define LEDC_COMMON_RETENTION_REGS_CNT 7
#define LEDC_COMMON_RETENTION_REGS_BASE(i) (DR_REG_LEDC_BASE(i) + 0xc8)
static const uint32_t ledc_common_regs_map[4] = {0x1c00001, 0x1c00, 0x0, 0x0};
// If a fade is in process, the DUTY_CHNG_END_CHx intr bit is enabled, however, we don't want it to be restored after wake-up (no fade after wake-up).
// Therefore, we can set it to 0 before backup the LEDC_INT_ENA_REG.
#define LEDC_COMMON_RETENTION_ENTRIES(i) { \
[0] = { .config = REGDMA_LINK_WRITE_INIT(REGDMA_LEDC_LINK(0x00), \
LEDC_INT_ENA_REG(i), 0, \
(LEDC_DUTY_CHNG_END_CH0_INT_ENA_M | LEDC_DUTY_CHNG_END_CH1_INT_ENA_M | LEDC_DUTY_CHNG_END_CH2_INT_ENA_M | LEDC_DUTY_CHNG_END_CH3_INT_ENA_M | LEDC_DUTY_CHNG_END_CH4_INT_ENA_M | LEDC_DUTY_CHNG_END_CH5_INT_ENA_M | LEDC_DUTY_CHNG_END_CH6_INT_ENA_M | LEDC_DUTY_CHNG_END_CH7_INT_ENA_M), 0, 1), \
.owner = LEDC_RETENTION_ENTRY }, \
[1] = { .config = REGDMA_LINK_ADDR_MAP_INIT(REGDMA_LEDC_LINK(0x01), \
LEDC_COMMON_RETENTION_REGS_BASE(i), LEDC_COMMON_RETENTION_REGS_BASE(i), \
LEDC_COMMON_RETENTION_REGS_CNT, 0, 0, \
ledc_common_regs_map[0], ledc_common_regs_map[1], \
ledc_common_regs_map[2], ledc_common_regs_map[3]), \
.owner = LEDC_RETENTION_ENTRY }, \
}
#define LEDC_TIMER_RETENTION_ENTRIES(i, timer) { \
[0] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_LEDC_LINK(0x00), \
LEDC_TIMER##timer##_CONF_REG(i), LEDC_TIMER##timer##_CONF_REG(i), \
1, 0, 0), \
.owner = LEDC_RETENTION_ENTRY }, \
[1] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_LEDC_LINK(0x01), \
LEDC_TIMER##timer##_CMP_REG(i), LEDC_TIMER##timer##_CMP_REG(i), \
1, 0, 0), \
.owner = LEDC_RETENTION_ENTRY }, \
[2] = { .config = REGDMA_LINK_WRITE_INIT(REGDMA_LEDC_LINK(0x02), \
LEDC_TIMER##timer##_CONF_REG(i), LEDC_TIMER##timer##_PARA_UP, \
LEDC_TIMER##timer##_PARA_UP_M, 1, 0), \
.owner = LEDC_RETENTION_ENTRY }, \
}
#define LEDC_CHANNEL_RETENTION_REGS_CNT 2
static const uint32_t ledc_channel_regs_map[4] = {0x3, 0x0, 0x0, 0x0};
static const uint32_t ledc_channel_gamma_regs_map[4] = {0xffff, 0x0, 0x0, 0x0};
#define LEDC_CHANNEL_RETENTION_ENTRIES(i, chan) { \
[0] = { .config = REGDMA_LINK_ADDR_MAP_INIT(REGDMA_LEDC_LINK(0x00), \
LEDC_CH##chan##_CONF0_REG(i), LEDC_CH##chan##_CONF0_REG(i), \
LEDC_CHANNEL_RETENTION_REGS_CNT, 0, 0, \
ledc_channel_regs_map[0], ledc_channel_regs_map[1], \
ledc_channel_regs_map[2], ledc_channel_regs_map[3]), \
.owner = LEDC_RETENTION_ENTRY }, \
[1] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_LEDC_LINK(0x01), \
LEDC_CH##chan##_DUTY_R_REG(i), LEDC_CH##chan##_DUTY_REG(i), \
1, 0, 0), \
.owner = LEDC_RETENTION_ENTRY }, \
[2] = { .config = REGDMA_LINK_WRITE_INIT(REGDMA_LEDC_LINK(0x02), \
LEDC_CH##chan##_CONF1_REG(i), LEDC_DUTY_START_CH##chan, \
LEDC_DUTY_START_CH##chan##_M, 1, 0), \
.owner = LEDC_RETENTION_ENTRY }, \
[3] = { .config = REGDMA_LINK_WRITE_INIT(REGDMA_LEDC_LINK(0x03), \
LEDC_CH##chan##_CONF0_REG(i), LEDC_PARA_UP_CH##chan, \
LEDC_PARA_UP_CH##chan##_M, 1, 0), \
.owner = LEDC_RETENTION_ENTRY }, \
[4] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_LEDC_LINK(0x04), \
LEDC_CH##chan##_GAMMA_CONF_REG(i), LEDC_CH##chan##_GAMMA_CONF_REG(i), \
1, 0, 0), \
.owner = LEDC_RETENTION_ENTRY }, \
[5] = { .config = REGDMA_LINK_ADDR_MAP_INIT(REGDMA_LEDC_LINK(0x05), \
LEDC_CH##chan##_GAMMA_RANGE0_REG(i), LEDC_CH##chan##_GAMMA_RANGE0_REG(i), \
SOC_LEDC_GAMMA_CURVE_FADE_RANGE_MAX, 0, 0, \
ledc_channel_gamma_regs_map[0], ledc_channel_gamma_regs_map[1], \
ledc_channel_gamma_regs_map[2], ledc_channel_gamma_regs_map[3]), \
.owner = LEDC_RETENTION_ENTRY }, \
}
static const regdma_entries_config_t ledc0_common_regdma_entries[] = LEDC_COMMON_RETENTION_ENTRIES(0);
static const regdma_entries_config_t ledc0_timer0_regdma_entries[] = LEDC_TIMER_RETENTION_ENTRIES(0, 0);
static const regdma_entries_config_t ledc0_timer1_regdma_entries[] = LEDC_TIMER_RETENTION_ENTRIES(0, 1);
static const regdma_entries_config_t ledc0_timer2_regdma_entries[] = LEDC_TIMER_RETENTION_ENTRIES(0, 2);
static const regdma_entries_config_t ledc0_timer3_regdma_entries[] = LEDC_TIMER_RETENTION_ENTRIES(0, 3);
static const regdma_entries_config_t ledc0_channel0_regdma_entries[] = LEDC_CHANNEL_RETENTION_ENTRIES(0, 0);
static const regdma_entries_config_t ledc0_channel1_regdma_entries[] = LEDC_CHANNEL_RETENTION_ENTRIES(0, 1);
static const regdma_entries_config_t ledc0_channel2_regdma_entries[] = LEDC_CHANNEL_RETENTION_ENTRIES(0, 2);
static const regdma_entries_config_t ledc0_channel3_regdma_entries[] = LEDC_CHANNEL_RETENTION_ENTRIES(0, 3);
static const regdma_entries_config_t ledc0_channel4_regdma_entries[] = LEDC_CHANNEL_RETENTION_ENTRIES(0, 4);
static const regdma_entries_config_t ledc0_channel5_regdma_entries[] = LEDC_CHANNEL_RETENTION_ENTRIES(0, 5);
static const regdma_entries_config_t ledc0_channel6_regdma_entries[] = LEDC_CHANNEL_RETENTION_ENTRIES(0, 6);
static const regdma_entries_config_t ledc0_channel7_regdma_entries[] = LEDC_CHANNEL_RETENTION_ENTRIES(0, 7);
static const regdma_entries_config_t ledc1_common_regdma_entries[] = LEDC_COMMON_RETENTION_ENTRIES(1);
static const regdma_entries_config_t ledc1_timer0_regdma_entries[] = LEDC_TIMER_RETENTION_ENTRIES(1, 0);
static const regdma_entries_config_t ledc1_timer1_regdma_entries[] = LEDC_TIMER_RETENTION_ENTRIES(1, 1);
static const regdma_entries_config_t ledc1_timer2_regdma_entries[] = LEDC_TIMER_RETENTION_ENTRIES(1, 2);
static const regdma_entries_config_t ledc1_timer3_regdma_entries[] = LEDC_TIMER_RETENTION_ENTRIES(1, 3);
static const regdma_entries_config_t ledc1_channel0_regdma_entries[] = LEDC_CHANNEL_RETENTION_ENTRIES(1, 0);
static const regdma_entries_config_t ledc1_channel1_regdma_entries[] = LEDC_CHANNEL_RETENTION_ENTRIES(1, 1);
static const regdma_entries_config_t ledc1_channel2_regdma_entries[] = LEDC_CHANNEL_RETENTION_ENTRIES(1, 2);
static const regdma_entries_config_t ledc1_channel3_regdma_entries[] = LEDC_CHANNEL_RETENTION_ENTRIES(1, 3);
static const regdma_entries_config_t ledc1_channel4_regdma_entries[] = LEDC_CHANNEL_RETENTION_ENTRIES(1, 4);
static const regdma_entries_config_t ledc1_channel5_regdma_entries[] = LEDC_CHANNEL_RETENTION_ENTRIES(1, 5);
static const regdma_entries_config_t ledc1_channel6_regdma_entries[] = LEDC_CHANNEL_RETENTION_ENTRIES(1, 6);
static const regdma_entries_config_t ledc1_channel7_regdma_entries[] = LEDC_CHANNEL_RETENTION_ENTRIES(1, 7);
const ledc_reg_retention_info_t ledc_reg_retention_info[2] = {
{
.common = {
.regdma_entry_array = ledc0_common_regdma_entries,
.array_size = ARRAY_SIZE(ledc0_common_regdma_entries),
},
.timer[0] = {
.regdma_entry_array = ledc0_timer0_regdma_entries,
.array_size = ARRAY_SIZE(ledc0_timer0_regdma_entries),
},
.timer[1] = {
.regdma_entry_array = ledc0_timer1_regdma_entries,
.array_size = ARRAY_SIZE(ledc0_timer1_regdma_entries),
},
.timer[2] = {
.regdma_entry_array = ledc0_timer2_regdma_entries,
.array_size = ARRAY_SIZE(ledc0_timer2_regdma_entries),
},
.timer[3] = {
.regdma_entry_array = ledc0_timer3_regdma_entries,
.array_size = ARRAY_SIZE(ledc0_timer3_regdma_entries),
},
.channel[0] = {
.regdma_entry_array = ledc0_channel0_regdma_entries,
.array_size = ARRAY_SIZE(ledc0_channel0_regdma_entries),
},
.channel[1] = {
.regdma_entry_array = ledc0_channel1_regdma_entries,
.array_size = ARRAY_SIZE(ledc0_channel1_regdma_entries),
},
.channel[2] = {
.regdma_entry_array = ledc0_channel2_regdma_entries,
.array_size = ARRAY_SIZE(ledc0_channel2_regdma_entries),
},
.channel[3] = {
.regdma_entry_array = ledc0_channel3_regdma_entries,
.array_size = ARRAY_SIZE(ledc0_channel3_regdma_entries),
},
.channel[4] = {
.regdma_entry_array = ledc0_channel4_regdma_entries,
.array_size = ARRAY_SIZE(ledc0_channel4_regdma_entries),
},
.channel[5] = {
.regdma_entry_array = ledc0_channel5_regdma_entries,
.array_size = ARRAY_SIZE(ledc0_channel5_regdma_entries),
},
.channel[6] = {
.regdma_entry_array = ledc0_channel6_regdma_entries,
.array_size = ARRAY_SIZE(ledc0_channel6_regdma_entries),
},
.channel[7] = {
.regdma_entry_array = ledc0_channel7_regdma_entries,
.array_size = ARRAY_SIZE(ledc0_channel7_regdma_entries),
},
.module_id = SLEEP_RETENTION_MODULE_LEDC0,
},
{
.common = {
.regdma_entry_array = ledc1_common_regdma_entries,
.array_size = ARRAY_SIZE(ledc1_common_regdma_entries),
},
.timer[0] = {
.regdma_entry_array = ledc1_timer0_regdma_entries,
.array_size = ARRAY_SIZE(ledc1_timer0_regdma_entries),
},
.timer[1] = {
.regdma_entry_array = ledc1_timer1_regdma_entries,
.array_size = ARRAY_SIZE(ledc1_timer1_regdma_entries),
},
.timer[2] = {
.regdma_entry_array = ledc1_timer2_regdma_entries,
.array_size = ARRAY_SIZE(ledc1_timer2_regdma_entries),
},
.timer[3] = {
.regdma_entry_array = ledc1_timer3_regdma_entries,
.array_size = ARRAY_SIZE(ledc1_timer3_regdma_entries),
},
.channel[0] = {
.regdma_entry_array = ledc1_channel0_regdma_entries,
.array_size = ARRAY_SIZE(ledc1_channel0_regdma_entries),
},
.channel[1] = {
.regdma_entry_array = ledc1_channel1_regdma_entries,
.array_size = ARRAY_SIZE(ledc1_channel1_regdma_entries),
},
.channel[2] = {
.regdma_entry_array = ledc1_channel2_regdma_entries,
.array_size = ARRAY_SIZE(ledc1_channel2_regdma_entries),
},
.channel[3] = {
.regdma_entry_array = ledc1_channel3_regdma_entries,
.array_size = ARRAY_SIZE(ledc1_channel3_regdma_entries),
},
.channel[4] = {
.regdma_entry_array = ledc1_channel4_regdma_entries,
.array_size = ARRAY_SIZE(ledc1_channel4_regdma_entries),
},
.channel[5] = {
.regdma_entry_array = ledc1_channel5_regdma_entries,
.array_size = ARRAY_SIZE(ledc1_channel5_regdma_entries),
},
.channel[6] = {
.regdma_entry_array = ledc1_channel6_regdma_entries,
.array_size = ARRAY_SIZE(ledc1_channel6_regdma_entries),
},
.channel[7] = {
.regdma_entry_array = ledc1_channel7_regdma_entries,
.array_size = ARRAY_SIZE(ledc1_channel7_regdma_entries),
},
.module_id = SLEEP_RETENTION_MODULE_LEDC1,
},
};
+2 -1
View File
@@ -13,7 +13,8 @@ void ledc_hal_init(ledc_hal_context_t *hal, int group_id)
{
//Get hardware instance.
hal->dev = LEDC_LL_GET_HW(group_id);
ledc_ll_enable_mem_power(true);
ledc_ll_mem_power_by_pmu(hal->dev);
ledc_ll_mem_set_low_power_mode(hal->dev, LEDC_LL_MEM_LP_MODE_SHUT_DOWN);
}
void ledc_hal_get_clk_cfg(ledc_hal_context_t *hal, ledc_mode_t speed_mode, ledc_timer_t timer_sel, ledc_clk_cfg_t *clk_cfg)
@@ -63,6 +63,10 @@ config SOC_SDM_SUPPORTED
bool
default y
config SOC_LEDC_SUPPORTED
bool
default y
config SOC_SYSTIMER_SUPPORTED
bool
default y
@@ -319,9 +323,49 @@ config SOC_ETM_SUPPORT_SLEEP_RETENTION
bool
default y
config SOC_LEDC_SUPPORT_PLL_DIV_CLOCK
bool
default y
config SOC_LEDC_SUPPORT_XTAL_CLOCK
bool
default y
config SOC_LEDC_TIMER_NUM
int
default 4
config SOC_LEDC_CHANNEL_NUM
int
default 6
default 8
config SOC_LEDC_TIMER_BIT_WIDTH
int
default 20
config SOC_LEDC_SUPPORT_FADE_STOP
bool
default y
config SOC_LEDC_GAMMA_CURVE_FADE_SUPPORTED
bool
default y
config SOC_LEDC_GAMMA_CURVE_FADE_RANGE_MAX
int
default 16
config SOC_LEDC_FADE_PARAMS_BIT_WIDTH
int
default 10
config SOC_LEDC_SUPPORT_SLEEP_RETENTION
bool
default y
config SOC_LEDC_SUPPORT_ETM
bool
default y
config SOC_MMU_PERIPH_NUM
int
@@ -226,6 +226,24 @@ typedef enum {
UART_SCLK_DEFAULT = SOC_MOD_CLK_XTAL, /*!< UART source clock default choice is XTAL in fpga env */
} soc_periph_uart_clk_src_legacy_t;
//////////////////////////////////////////////////LEDC/////////////////////////////////////////////////////////////////
/**
* @brief Array initializer for all supported clock sources of LEDC
*/
#define SOC_LEDC_CLKS {SOC_MOD_CLK_XTAL, SOC_MOD_CLK_PLL_F80M, SOC_MOD_CLK_RC_FAST}
#define SOC_LEDC_CLK_STRS {"LEDC_USE_XTAL_CLK", "LEDC_USE_PLL_DIV_CLK", "LEDC_USE_RC_FAST_CLK"}
/**
* @brief Type of LEDC clock source, reserved for the legacy LEDC driver
*/
typedef enum {
LEDC_AUTO_CLK = 0, /*!< LEDC source clock will be automatically selected based on the giving resolution and duty parameter when init the timer*/
LEDC_USE_PLL_DIV_CLK = SOC_MOD_CLK_PLL_F80M, /*!< Select PLL_F80M clock as the source clock */
LEDC_USE_RC_FAST_CLK = SOC_MOD_CLK_RC_FAST, /*!< Select RC_FAST as the source clock */
LEDC_USE_XTAL_CLK = SOC_MOD_CLK_XTAL, /*!< Select XTAL as the source clock */
} soc_periph_ledc_clk_src_legacy_t;
/////////////////////////////////////////////////SPI////////////////////////////////////////////////////////////////////
/**
+12 -3
View File
@@ -58,7 +58,7 @@
// #define SOC_I2S_SUPPORTED 1 // TODO: [ESP32S31] IDF-14771
#define SOC_SDM_SUPPORTED 1
// #define SOC_GPSPI_SUPPORTED 1 // TODO: [ESP32S31] IDF-14734
// #define SOC_LEDC_SUPPORTED 1 // TODO: [ESP32S31] IDF-14709
#define SOC_LEDC_SUPPORTED 1
// #define SOC_ISP_SUPPORTED 1 // TODO: [ESP32S31] IDF-14769
// #define SOC_I2C_SUPPORTED 1 // TODO: [ESP32S31] IDF-14726
#define SOC_SYSTIMER_SUPPORTED 1 // TODO: [ESP32S31] IDF-14693
@@ -205,8 +205,17 @@
#define SOC_ETM_SUPPORT_SLEEP_RETENTION 1
/*-------------------------- LEDC CAPS ---------------------------------------*/
// TODO: [ESP32S31] IDF-14709
#define SOC_LEDC_CHANNEL_NUM (6)
#define SOC_LEDC_SUPPORT_PLL_DIV_CLOCK (1)
#define SOC_LEDC_SUPPORT_XTAL_CLOCK (1)
#define SOC_LEDC_TIMER_NUM (4)
#define SOC_LEDC_CHANNEL_NUM (8)
#define SOC_LEDC_TIMER_BIT_WIDTH (20)
#define SOC_LEDC_SUPPORT_FADE_STOP (1)
#define SOC_LEDC_GAMMA_CURVE_FADE_SUPPORTED (1)
#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 (2U)
@@ -36,6 +36,7 @@ PROVIDE ( GPSPI2 = 0x2038F000 );
PROVIDE ( GPSPI3 = 0x20390000 );
PROVIDE ( USB_SERIAL_JTAG = 0x20391000 );
PROVIDE ( LEDC0 = 0x20392000 );
PROVIDE ( LEDC0_GAMMA_RAM = 0x20392400 );
PROVIDE ( SOC_ETM = 0x20393000 );
PROVIDE ( TWAIFD0 = 0x20394000 );
PROVIDE ( TWAIFD1 = 0x20395000 );
@@ -45,6 +46,7 @@ PROVIDE ( SYSTIMER = 0x20399000 );
PROVIDE ( ZERO_DET = 0x2039A000 );
PROVIDE ( CORDIC = 0x2039B000 );
PROVIDE ( LEDC1 = 0x2039C000 );
PROVIDE ( LEDC1_GAMMA_RAM = 0x2039C400 );
PROVIDE ( PCNT1 = 0x2039D000 );
PROVIDE ( SPIMEM0 = 0x20500000 );
PROVIDE ( SPIMEM1 = 0x20501000 );
File diff suppressed because it is too large Load Diff
@@ -1,5 +1,5 @@
/**
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*/
@@ -16,52 +16,52 @@ extern "C" {
*/
typedef union {
struct {
/** timer_sel_chn : R/W; bitpos: [1:0]; default: 0;
/** timer_sel : R/W; bitpos: [1:0]; default: 0;
* Configures which timer is channel n selected.
* 0: Select timer0
* 1: Select timer1
* 2: Select timer2
* 3: Select timer3
*/
uint32_t timer_sel_chn:2;
/** sig_out_en_chn : R/W; bitpos: [2]; default: 0;
uint32_t timer_sel:2;
/** sig_out_en : R/W; bitpos: [2]; default: 0;
* Configures whether or not to enable signal output on channel n.
* 0: Signal output disable
* 1: Signal output enable
*/
uint32_t sig_out_en_chn:1;
/** idle_lv_chn : R/W; bitpos: [3]; default: 0;
uint32_t sig_out_en:1;
/** idle_lv : R/W; bitpos: [3]; default: 0;
* Configures the output value when channel n is inactive. Valid only when
* LEDC_SIG_OUT_EN_CHn is 0.
* 0: Output level is low
* 1: Output level is high
*/
uint32_t idle_lv_chn:1;
/** para_up_chn : WT; bitpos: [4]; default: 0;
uint32_t idle_lv:1;
/** para_up : WT; bitpos: [4]; default: 0;
* Configures whether or not to update LEDC_HPOINT_CHn, LEDC_DUTY_START_CHn,
* LEDC_SIG_OUT_EN_CHn, LEDC_TIMER_SEL_CHn, LEDC_OVF_CNT_EN_CHn fields and duty cycle
* range configuration for channel n, and will be automatically cleared by hardware.
* 0: Invalid. No effect
* 1: Update
*/
uint32_t para_up_chn:1;
/** ovf_num_chn : R/W; bitpos: [14:5]; default: 0;
uint32_t para_up:1;
/** ovf_num : R/W; bitpos: [14:5]; default: 0;
* Configures the maximum times of overflow minus 1.The LEDC_OVF_CNT_CHn_INT interrupt
* will be triggered when channel n overflows for (LEDC_OVF_NUM_CHn + 1) times.
*/
uint32_t ovf_num_chn:10;
/** ovf_cnt_en_chn : R/W; bitpos: [15]; default: 0;
uint32_t ovf_num:10;
/** ovf_cnt_en : R/W; bitpos: [15]; default: 0;
* Configures whether or not to enable the ovf_cnt of channel n.
* 0: Disable
* 1: Enable
*/
uint32_t ovf_cnt_en_chn:1;
/** ovf_cnt_reset_chn : WT; bitpos: [16]; default: 0;
uint32_t ovf_cnt_en:1;
/** ovf_cnt_reset : WT; bitpos: [16]; default: 0;
* Configures whether or not to reset the ovf_cnt of channel n.
* 0: Invalid. No effect
* 1: Reset the ovf_cnt
*/
uint32_t ovf_cnt_reset_chn:1;
uint32_t ovf_cnt_reset:1;
uint32_t reserved_17:15;
};
uint32_t val;
@@ -72,11 +72,11 @@ typedef union {
*/
typedef union {
struct {
/** hpoint_chn : R/W; bitpos: [19:0]; default: 0;
/** hpoint : R/W; bitpos: [19:0]; default: 0;
* Configures high point of signal output on channel n. The output value changes to
* high when the selected timers has reached the value specified by this register.
*/
uint32_t hpoint_chn:20;
uint32_t hpoint:20;
uint32_t reserved_20:12;
};
uint32_t val;
@@ -87,10 +87,10 @@ typedef union {
*/
typedef union {
struct {
/** duty_chn : R/W; bitpos: [24:0]; default: 0;
/** duty : R/W; bitpos: [24:0]; default: 0;
* Configures the duty of signal output on channel n.
*/
uint32_t duty_chn:25;
uint32_t duty:25;
uint32_t reserved_25:7;
};
uint32_t val;
@@ -102,12 +102,12 @@ typedef union {
typedef union {
struct {
uint32_t reserved_0:31;
/** duty_start_chn : R/W/SC; bitpos: [31]; default: 0;
/** duty_start : R/W/SC; bitpos: [31]; default: 0;
* Configures whether the duty cycle fading configurations take effect.
* 0: Not take effect
* 1: Take effect
*/
uint32_t duty_start_chn:1;
uint32_t duty_start:1;
};
uint32_t val;
} ledc_chn_conf1_reg_t;
@@ -117,34 +117,34 @@ typedef union {
*/
typedef union {
struct {
/** timern_duty_res : R/W; bitpos: [4:0]; default: 0;
/** duty_res : R/W; bitpos: [4:0]; default: 0;
* Configures the bit width of the counter in timer n. Valid values are 1 to 20.
*/
uint32_t timern_duty_res:5;
/** clk_div_timern : R/W; bitpos: [22:5]; default: 0;
uint32_t duty_res:5;
/** clk_div : R/W; bitpos: [22:5]; default: 0;
* Configures the divisor for the divider in timer n.The least significant eight bits
* represent the fractional part.
*/
uint32_t clk_div_timern:18;
/** timern_pause : R/W; bitpos: [23]; default: 0;
uint32_t clk_div:18;
/** pause : R/W; bitpos: [23]; default: 0;
* Configures whether or not to pause the counter in timer n.
* 0: Normal
* 1: Pause
*/
uint32_t timern_pause:1;
/** timern_rst : R/W; bitpos: [24]; default: 1;
uint32_t pause:1;
/** rst : R/W; bitpos: [24]; default: 1;
* Configures whether or not to reset timer n. The counter will show 0 after reset.
* 0: Not reset
* 1: Reset
*/
uint32_t timern_rst:1;
uint32_t rst:1;
uint32_t reserved_25:1;
/** timern_para_up : WT; bitpos: [26]; default: 0;
/** para_up : WT; bitpos: [26]; default: 0;
* Configures whether or not to update LEDC_CLK_DIV_TIMERn and LEDC_TIMERn_DUTY_RES.
* 0: Invalid. No effect
* 1: Update
*/
uint32_t timern_para_up:1;
uint32_t para_up:1;
uint32_t reserved_27:5;
};
uint32_t val;
@@ -155,22 +155,22 @@ typedef union {
*/
typedef union {
struct {
/** chn_gamma_entry_num : R/W; bitpos: [4:0]; default: 0;
/** gamma_entry_num : R/W; bitpos: [4:0]; default: 0;
* Configures the number of duty cycle fading rages for LEDC chn.
*/
uint32_t chn_gamma_entry_num:5;
/** chn_gamma_pause : WT; bitpos: [5]; default: 0;
uint32_t gamma_entry_num:5;
/** gamma_pause : WT; bitpos: [5]; default: 0;
* Configures whether or not to pause duty cycle fading of LEDC chn.
* 0: Invalid. No effect
* 1: Pause
*/
uint32_t chn_gamma_pause:1;
/** chn_gamma_resume : WT; bitpos: [6]; default: 0;
uint32_t gamma_pause:1;
/** gamma_resume : WT; bitpos: [6]; default: 0;
* Configures whether or nor to resume duty cycle fading of LEDC chn.
* 0: Invalid. No effect
* 1: Resume
*/
uint32_t chn_gamma_resume:1;
uint32_t gamma_resume:1;
uint32_t reserved_7:25;
};
uint32_t val;
@@ -741,10 +741,10 @@ typedef union {
*/
typedef union {
struct {
/** timern_cmp : R/W; bitpos: [19:0]; default: 0;
/** cmp : R/W; bitpos: [19:0]; default: 0;
* Configures the comparison value for LEDC timern.
*/
uint32_t timern_cmp:20;
uint32_t cmp:20;
uint32_t reserved_20:12;
};
uint32_t val;
@@ -986,10 +986,10 @@ typedef union {
*/
typedef union {
struct {
/** duty_chn_r : RO; bitpos: [24:0]; default: 0;
/** duty_r : RO; bitpos: [24:0]; default: 0;
* Represents the current duty of output signal on channel n.
*/
uint32_t duty_chn_r:25;
uint32_t duty_r:25;
uint32_t reserved_25:7;
};
uint32_t val;
@@ -1000,10 +1000,10 @@ typedef union {
*/
typedef union {
struct {
/** timern_cnt : RO; bitpos: [19:0]; default: 0;
/** cnt : RO; bitpos: [19:0]; default: 0;
* Represents the current counter value of timer n.
*/
uint32_t timern_cnt:20;
uint32_t cnt:20;
uint32_t reserved_20:12;
};
uint32_t val;
@@ -1014,10 +1014,10 @@ typedef union {
*/
typedef union {
struct {
/** timern_cnt_cap : RO; bitpos: [19:0]; default: 0;
/** cnt_cap : RO; bitpos: [19:0]; default: 0;
* Represents the captured LEDC timern count value.
*/
uint32_t timern_cnt_cap:20;
uint32_t cnt_cap:20;
uint32_t reserved_20:12;
};
uint32_t val;
@@ -1442,67 +1442,54 @@ typedef union {
} ledc_date_reg_t;
typedef struct {
volatile ledc_chn_conf0_reg_t conf0;
volatile ledc_chn_hpoint_reg_t hpoint;
volatile ledc_chn_duty_reg_t duty_init;
volatile ledc_chn_conf1_reg_t conf1;
volatile ledc_chn_duty_r_reg_t duty_r;
} ledc_chn_reg_t;
typedef struct {
volatile ledc_chn_reg_t channel[8];
} ledc_ch_group_reg_t;
typedef struct {
volatile ledc_timern_conf_reg_t conf;
volatile ledc_timern_value_reg_t value;
} ledc_timern_reg_t;
typedef struct {
volatile ledc_timern_reg_t timer[4];
} ledc_timer_group_reg_t;
typedef struct {
volatile ledc_chn_gamma_conf_reg_t gamma_conf[8];
} ledc_ch_gamma_conf_group_reg_t;
typedef struct {
volatile ledc_timern_cmp_reg_t cmp[4];
} ledc_timer_cmp_group_reg_t;
typedef struct {
volatile ledc_timern_cnt_cap_reg_t cnt_cap[4];
} ledc_timer_cnt_cap_group_reg_t;
typedef struct ledc_dev_t {
volatile ledc_chn_conf0_reg_t ch0_conf0;
volatile ledc_chn_hpoint_reg_t ch0_hpoint;
volatile ledc_chn_duty_reg_t ch0_duty;
volatile ledc_chn_conf1_reg_t ch0_conf1;
volatile ledc_chn_duty_r_reg_t ch0_duty_r;
volatile ledc_chn_conf0_reg_t ch1_conf0;
volatile ledc_chn_hpoint_reg_t ch1_hpoint;
volatile ledc_chn_duty_reg_t ch1_duty;
volatile ledc_chn_conf1_reg_t ch1_conf1;
volatile ledc_chn_duty_r_reg_t ch1_duty_r;
volatile ledc_chn_conf0_reg_t ch2_conf0;
volatile ledc_chn_hpoint_reg_t ch2_hpoint;
volatile ledc_chn_duty_reg_t ch2_duty;
volatile ledc_chn_conf1_reg_t ch2_conf1;
volatile ledc_chn_duty_r_reg_t ch2_duty_r;
volatile ledc_chn_conf0_reg_t ch3_conf0;
volatile ledc_chn_hpoint_reg_t ch3_hpoint;
volatile ledc_chn_duty_reg_t ch3_duty;
volatile ledc_chn_conf1_reg_t ch3_conf1;
volatile ledc_chn_duty_r_reg_t ch3_duty_r;
volatile ledc_chn_conf0_reg_t ch4_conf0;
volatile ledc_chn_hpoint_reg_t ch4_hpoint;
volatile ledc_chn_duty_reg_t ch4_duty;
volatile ledc_chn_conf1_reg_t ch4_conf1;
volatile ledc_chn_duty_r_reg_t ch4_duty_r;
volatile ledc_chn_conf0_reg_t ch5_conf0;
volatile ledc_chn_hpoint_reg_t ch5_hpoint;
volatile ledc_chn_duty_reg_t ch5_duty;
volatile ledc_chn_conf1_reg_t ch5_conf1;
volatile ledc_chn_duty_r_reg_t ch5_duty_r;
volatile ledc_chn_conf0_reg_t ch6_conf0;
volatile ledc_chn_hpoint_reg_t ch6_hpoint;
volatile ledc_chn_duty_reg_t ch6_duty;
volatile ledc_chn_conf1_reg_t ch6_conf1;
volatile ledc_chn_duty_r_reg_t ch6_duty_r;
volatile ledc_chn_conf0_reg_t ch7_conf0;
volatile ledc_chn_hpoint_reg_t ch7_hpoint;
volatile ledc_chn_duty_reg_t ch7_duty;
volatile ledc_chn_conf1_reg_t ch7_conf1;
volatile ledc_chn_duty_r_reg_t ch7_duty_r;
volatile ledc_timern_conf_reg_t timer0_conf;
volatile ledc_timern_value_reg_t timer0_value;
volatile ledc_timern_conf_reg_t timer1_conf;
volatile ledc_timern_value_reg_t timer1_value;
volatile ledc_timern_conf_reg_t timer2_conf;
volatile ledc_timern_value_reg_t timer2_value;
volatile ledc_timern_conf_reg_t timer3_conf;
volatile ledc_timern_value_reg_t timer3_value;
volatile ledc_ch_group_reg_t channel_group[1];
volatile ledc_timer_group_reg_t timer_group[1];
volatile ledc_int_raw_reg_t int_raw;
volatile ledc_int_st_reg_t int_st;
volatile ledc_int_ena_reg_t int_ena;
volatile ledc_int_clr_reg_t int_clr;
uint32_t reserved_0d0[12];
volatile ledc_chn_gamma_conf_reg_t chn_gamma_conf[8];
volatile ledc_ch_gamma_conf_group_reg_t channel_gamma_conf_group[1];
volatile ledc_evt_task_en0_reg_t evt_task_en0;
volatile ledc_evt_task_en1_reg_t evt_task_en1;
volatile ledc_evt_task_en2_reg_t evt_task_en2;
uint32_t reserved_12c[5];
volatile ledc_timern_cmp_reg_t timern_cmp[4];
volatile ledc_timern_cnt_cap_reg_t timern_cnt_cap[4];
volatile ledc_timer_cmp_group_reg_t timer_cmp_group[1];
volatile ledc_timer_cnt_cap_group_reg_t timer_cnt_cap_group[1];
uint32_t reserved_160[4];
volatile ledc_conf_reg_t conf;
volatile ledc_ch_power_up_conf_reg_t ch_power_up_conf;
@@ -1511,8 +1498,37 @@ typedef struct ledc_dev_t {
} ledc_dev_t;
/**
* Gamma fade param group ram type
*/
typedef union {
struct {
uint32_t duty_inc :1;
uint32_t duty_cycle :10;
uint32_t scale :10;
uint32_t duty_num :10;
uint32_t reserved :1;
};
uint32_t val;
} ledc_channel_gamma_fade_param_t;
typedef struct {
volatile ledc_channel_gamma_fade_param_t entry[16];
} ledc_gamma_channel_t;
typedef struct {
volatile ledc_gamma_channel_t channel[8];
} ledc_gamma_ram_t;
extern ledc_dev_t LEDC0;
extern ledc_dev_t LEDC1;
extern ledc_gamma_ram_t LEDC0_GAMMA_RAM;
extern ledc_gamma_ram_t LEDC1_GAMMA_RAM;
#ifndef __cplusplus
_Static_assert(sizeof(ledc_dev_t) == 0x180, "Invalid size of ledc_dev_t structure");
_Static_assert(sizeof(ledc_gamma_ram_t) == 0x200, "Invalid size of ledc_gamma_ram_t structure");
#endif
#ifdef __cplusplus
+2 -4
View File
@@ -1,8 +1,6 @@
LED Control (LEDC)
==================
{IDF_TARGET_LEDC_MAX_FADE_RANGE_NUM: default="1", esp32c6="16", esp32h2="16", esp32p4="16", esp32c5="16", esp32c61="16", esp32h21="16"}
:link_to_translation:`zh_CN:[中文]`
Introduction
@@ -169,7 +167,7 @@ The source clock can also limit the PWM frequency. The higher the source clock f
- 48 MHz
- Dynamic Frequency Scaling compatible
.. only:: esp32c6 or esp32c61 or esp32p4
.. only:: esp32c6 or esp32c61 or esp32p4 or esp32s31
.. list-table:: Characteristics of {IDF_TARGET_NAME} LEDC source clocks
:widths: 15 15 30
@@ -314,7 +312,7 @@ The LEDC hardware provides the means to gradually transition from one duty cycle
.. only:: SOC_LEDC_GAMMA_CURVE_FADE_SUPPORTED
On {IDF_TARGET_NAME}, the hardware additionally allows to perform up to {IDF_TARGET_LEDC_MAX_FADE_RANGE_NUM} consecutive linear fades without CPU intervention. This feature can be useful if you want to do a fade with gamma correction.
On {IDF_TARGET_NAME}, the hardware additionally allows to perform consecutive linear fades without CPU intervention. This feature can be useful if you want to do a fade with gamma correction.
The luminance perceived by human eyes does not have a linear relationship with the PWM duty cycle. In order to make human feel the LED is dimming or lighting linearly, the change in duty cycle should be non-linear, which is the so-called gamma correction. The LED controller can simulate a gamma curve fading by piecewise linear approximation. :cpp:func:`ledc_fill_multi_fade_param_list` is a function that can help to construct the parameters for the piecewise linear fades. First, you need to allocate a memory block for saving the fade parameters, then by providing start/end PWM duty cycle values, gamma correction function, and the total number of desired linear segments to the helper function, it will fill the calculation results into the allocated space. You can also construct the array of :cpp:type:`ledc_fade_param_config_t` manually. Once the fade parameter structs are prepared, a consecutive fading can be configured by passing the pointer to the prepared :cpp:type:`ledc_fade_param_config_t` list and the total number of fade ranges to :cpp:func:`ledc_set_multi_fade`.
@@ -1,8 +1,6 @@
LED PWM 控制器
==============
{IDF_TARGET_LEDC_MAX_FADE_RANGE_NUM: default="1", esp32c6="16", esp32h2="16", esp32p4="16", esp32c5="16", esp32c61="16", esp32h21="16"}
:link_to_translation:`en:[English]`
概述
@@ -169,7 +167,7 @@ LED PWM 控制器可在无需 CPU 干预的情况下自动改变占空比,实
- 48 MHz
- 支持动态调频 (DFS) 功能
.. only:: esp32c6 or esp32c61 or esp32p4
.. only:: esp32c6 or esp32c61 or esp32p4 or esp32s31
.. list-table:: {IDF_TARGET_NAME} LEDC 时钟源特性
:widths: 10 10 30
@@ -314,7 +312,7 @@ LED PWM 控制器硬件可逐渐改变占空比的数值。要使用此功能,
.. only:: SOC_LEDC_GAMMA_CURVE_FADE_SUPPORTED
{IDF_TARGET_NAME} 的硬件额外支持多达 {IDF_TARGET_LEDC_MAX_FADE_RANGE_NUM} 次,无需 CPU 介入的连续渐变。此功能可以更加有效便捷得实现一个带伽马校正的渐变。
{IDF_TARGET_NAME} 的硬件额外支持无需 CPU 介入的连续渐变。此功能可以更加有效便捷得实现一个带伽马校正的渐变。
众所周知,人眼所感知的亮度与 PWM 占空比并非成线性关系。为了能使人感观上认为一盏灯明暗的变化是线性的,我们对其 PWM 信号的占空比控制必须为非线性的,俗称伽马校正。LED PWM 控制器可以通过多段线型拟合来模仿伽马曲线渐变。 你需要自己在应用程序中分配一段用以保存渐变参数的内存块,并提供开始和结束的占空比,伽马校正公式,以及期望的线性渐变段数信息,:cpp:func:`ledc_fill_multi_fade_param_list` 就能快速生成所有分段线性渐变的参数。或者你也可以自己直接构造一个 :cpp:type:`ledc_fade_param_config_t` 的数组。在获得所有渐变参数后,通过将 :cpp:type:`ledc_fade_param_config_t` 数组的指针和渐变区间数传入 :cpp:func:`ledc_set_multi_fade`,一次连续渐变的配置就完成了。
@@ -1,5 +1,5 @@
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | --------- | -------- | -------- | -------- | -------- |
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S2 | ESP32-S3 | ESP32-S31 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | --------- | -------- | -------- | -------- | -------- | --------- |
# _LEDC Basic Example_
@@ -1,5 +1,5 @@
| Supported Targets | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 |
| ----------------- | -------- | -------- | --------- | -------- | --------- | -------- | -------- |
| Supported Targets | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S31 |
| ----------------- | -------- | -------- | --------- | -------- | --------- | -------- | -------- | --------- |
# LEDC Dimmer Example
@@ -1,5 +1,5 @@
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | --------- | -------- | -------- | -------- | -------- |
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S2 | ESP32-S3 | ESP32-S31 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | --------- | -------- | -------- | -------- | -------- | --------- |
# _LEDC Fade Example_
@@ -1,5 +1,5 @@
| Supported Targets | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H21 | ESP32-P4 |
| ----------------- | -------- | -------- | --------- | -------- | --------- | -------- |
| Supported Targets | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H21 | ESP32-P4 | ESP32-S31 |
| ----------------- | -------- | -------- | --------- | -------- | --------- | -------- | --------- |
# _LEDC Gamma Curve Fade Example_