ledc: Provide support for esp32c2 and esp32h2

LEDC examples, unit test, and programming guide are all updated.
This commit is contained in:
songruojing 2022-02-09 12:50:19 +08:00 committed by BOT
parent 11abb67e65
commit 534346f4bb
36 changed files with 2940 additions and 1615 deletions

View File

@ -15,8 +15,21 @@
extern "C" {
#endif
#define LEDC_APB_CLK_HZ (APB_CLK_FREQ)
#define LEDC_REF_CLK_HZ (REF_CLK_FREQ)
#if SOC_LEDC_SUPPORT_APB_CLOCK
/**
* @brief Frequency of one of the LEDC peripheral clock sources, APB_CLK
* @note This macro should have no use in your application, we keep it here only for backward compatible
*/
#define LEDC_APB_CLK_HZ _Pragma ("GCC warning \"'LEDC_APB_CLK_HZ' macro is deprecated\"") (APB_CLK_FREQ)
#endif
#if SOC_LEDC_SUPPORT_REF_TICK
/**
* @brief Frequency of one of the LEDC peripheral clock sources, REF_TICK
* @note This macro should have no use in your application, we keep it here only for backward compatible
*/
#define LEDC_REF_CLK_HZ _Pragma ("GCC warning \"'LEDC_REF_CLK_HZ' macro is deprecated\"") (REF_CLK_FREQ)
#endif
#define LEDC_ERR_DUTY (0xFFFFFFFF)
#define LEDC_ERR_VAL (-1)
@ -48,9 +61,13 @@ typedef struct {
};
ledc_timer_t timer_num; /*!< The timer source of channel (0 - 3) */
uint32_t freq_hz; /*!< LEDC timer frequency (Hz) */
ledc_clk_cfg_t clk_cfg; /*!< Configure LEDC source clock.
For low speed channels and high speed channels, you can specify the source clock using LEDC_USE_REF_TICK, LEDC_USE_APB_CLK or LEDC_AUTO_CLK.
For low speed channels, you can also specify the source clock using LEDC_USE_RTC8M_CLK, in this case, all low speed channel's source clock must be RTC8M_CLK*/
ledc_clk_cfg_t clk_cfg; /*!< Configure LEDC source clock from ledc_clk_cfg_t.
Note that LEDC_USE_RTC8M_CLK and LEDC_USE_XTAL_CLK are
non-timer-specific clock sources. You can not have one LEDC timer uses
RTC8M_CLK as the clock source and have another LEDC timer uses XTAL_CLK
as its clock source. All chips except esp32 and esp32s2 do not have
timer-specific clock sources, which means clock source for all timers
must be the same one. */
} ledc_timer_config_t;
typedef intr_handle_t ledc_isr_handle_t;

View File

@ -60,15 +60,9 @@ static ledc_isr_handle_t s_ledc_fade_isr_handle = NULL;
static portMUX_TYPE ledc_spinlock = portMUX_INITIALIZER_UNLOCKED;
#define LEDC_VAL_NO_CHANGE (-1)
#define LEDC_STEP_NUM_MAX (1023)
#define LEDC_DUTY_NUM_MAX LEDC_LL_DUTY_NUM_MAX // Maximum steps per hardware fade
#define LEDC_DUTY_DECIMAL_BIT_NUM (4)
#define LEDC_TIMER_DIV_NUM_MAX (0x3FFFF)
#define LEDC_DUTY_NUM_MAX (LEDC_DUTY_NUM_LSCH0_V)
#define LEDC_DUTY_CYCLE_MAX (LEDC_DUTY_CYCLE_LSCH0_V)
#define LEDC_DUTY_SCALE_MAX (LEDC_DUTY_SCALE_LSCH0_V)
#define LEDC_HPOINT_VAL_MAX (LEDC_HPOINT_LSCH1_V)
#define DELAY_CLK8M_CLK_SWITCH (5)
#define SLOW_CLK_CYC_CALIBRATE (13)
#define LEDC_FADE_TOO_SLOW_STR "LEDC FADE TOO SLOW"
#define LEDC_FADE_TOO_FAST_STR "LEDC FADE TOO FAST"
#define DIM(array) (sizeof(array)/sizeof(*array))
@ -100,7 +94,12 @@ static bool ledc_slow_clk_calibrate(void)
{
if (periph_rtc_dig_clk8m_enable()) {
s_ledc_slow_clk_8M = periph_rtc_dig_clk8m_get_freq();
#if CONFIG_IDF_TARGET_ESP32H2
/* Workaround: Calibration cannot be done for CLK8M on H2, we just use its theoretic frequency */
ESP_LOGD(LEDC_TAG, "Calibration cannot be performed, approximate CLK8M_CLK : %d Hz", s_ledc_slow_clk_8M);
#else
ESP_LOGD(LEDC_TAG, "Calibrate CLK8M_CLK : %d Hz", s_ledc_slow_clk_8M);
#endif
return true;
}
ESP_LOGE(LEDC_TAG, "Calibrate CLK8M_CLK failed");
@ -110,13 +109,19 @@ static bool ledc_slow_clk_calibrate(void)
static uint32_t ledc_get_src_clk_freq(ledc_clk_cfg_t clk_cfg)
{
uint32_t src_clk_freq = 0;
if (clk_cfg == LEDC_USE_APB_CLK) {
src_clk_freq = LEDC_APB_CLK_HZ;
} else if (clk_cfg == LEDC_USE_RTC8M_CLK) {
if (clk_cfg == LEDC_USE_RTC8M_CLK) {
src_clk_freq = s_ledc_slow_clk_8M;
#if SOC_LEDC_SUPPORT_APB_CLOCK
} else if (clk_cfg == LEDC_USE_APB_CLK) {
src_clk_freq = esp_clk_apb_freq();
#endif
#if SOC_LEDC_SUPPORT_PLL_DIV_CLOCK
} else if (clk_cfg == LEDC_USE_PLL_DIV_CLK) {
src_clk_freq = LEDC_LL_PLL_DIV_CLK_FREQ;
#endif
#if SOC_LEDC_SUPPORT_REF_TICK
} else if (clk_cfg == LEDC_USE_REF_TICK) {
src_clk_freq = LEDC_REF_CLK_HZ;
src_clk_freq = REF_CLK_FREQ;
#endif
#if SOC_LEDC_SUPPORT_XTAL_CLOCK
} else if (clk_cfg == LEDC_USE_XTAL_CLK) {
@ -132,9 +137,16 @@ static uint32_t ledc_get_glb_clk_freq(ledc_slow_clk_sel_t clk_cfg)
uint32_t src_clk_freq = 0;
switch (clk_cfg) {
#if SOC_LEDC_SUPPORT_APB_CLOCK
case LEDC_SLOW_CLK_APB:
src_clk_freq = LEDC_APB_CLK_HZ;
src_clk_freq = esp_clk_apb_freq();
break;
#endif
#if SOC_LEDC_SUPPORT_PLL_DIV_CLOCK
case LEDC_SLOW_CLK_PLL_DIV:
src_clk_freq = LEDC_LL_PLL_DIV_CLK_FREQ;
break;
#endif
case LEDC_SLOW_CLK_RTC8M:
src_clk_freq = s_ledc_slow_clk_8M;
break;
@ -338,7 +350,7 @@ static inline uint32_t ledc_auto_global_clk_divisor(int freq_hz, uint32_t precis
for (i = 0; i < DIM(glb_clks); i++) {
/* Before calculating the divisor, we need to have the RTC frequency.
* If it hasn't been mesured yet, try calibrating it now. */
* If it hasn't been measured yet, try calibrating it now. */
if (glb_clks[i] == LEDC_SLOW_CLK_RTC8M && s_ledc_slow_clk_8M == 0 && !ledc_slow_clk_calibrate()) {
ESP_LOGD(LEDC_TAG, "Unable to retrieve RTC clock frequency, skipping it\n");
continue;
@ -385,7 +397,7 @@ static inline uint32_t ledc_auto_timer_specific_clk_divisor(ledc_mode_t speed_mo
* to test APB. */
if (speed_mode == LEDC_HIGH_SPEED_MODE && i == DIM(specific_clks)) {
/* No divider was found yet, try with APB! */
div_param = ledc_calculate_divisor(LEDC_APB_CLK_HZ, freq_hz, precision);
div_param = ledc_calculate_divisor(esp_clk_apb_freq(), freq_hz, precision);
if (!LEDC_IS_DIV_INVALID(div_param)) {
*clk_source = LEDC_APB_CLK;
@ -429,13 +441,19 @@ static uint32_t ledc_auto_clk_divisor(ledc_mode_t speed_mode, int freq_hz, uint3
static ledc_slow_clk_sel_t ledc_clk_cfg_to_global_clk(const ledc_clk_cfg_t clk_cfg)
{
/* Initialization required for preventing a compiler warning */
ledc_slow_clk_sel_t glb_clk = LEDC_SLOW_CLK_APB;
ledc_slow_clk_sel_t glb_clk;
switch (clk_cfg) {
#if SOC_LEDC_SUPPORT_APB_CLOCK
case LEDC_USE_APB_CLK:
glb_clk = LEDC_SLOW_CLK_APB;
break;
#endif
#if SOC_LEDC_SUPPORT_PLL_DIV_CLOCK
case LEDC_USE_PLL_DIV_CLK:
glb_clk = LEDC_SLOW_CLK_PLL_DIV;
break;
#endif
case LEDC_USE_RTC8M_CLK:
glb_clk = LEDC_SLOW_CLK_RTC8M;
break;
@ -450,7 +468,7 @@ static ledc_slow_clk_sel_t ledc_clk_cfg_to_global_clk(const ledc_clk_cfg_t clk_c
default:
/* We should not get here, REF_TICK is NOT a global clock,
* it is a timer-specific clock. */
assert(false);
abort();
}
return glb_clk;
@ -468,8 +486,8 @@ static esp_err_t ledc_set_timer_div(ledc_mode_t speed_mode, ledc_timer_t timer_n
/* This variable represents the timer's mux value. It will be overwritten
* if a timer-specific clock is used. */
ledc_clk_src_t timer_clk_src = LEDC_SCLK;
/* Store the global clock. */
ledc_slow_clk_sel_t glb_clk = LEDC_SLOW_CLK_APB;
/* Store the global clock */
ledc_slow_clk_sel_t glb_clk;
uint32_t src_clk_freq = 0;
if (clk_cfg == LEDC_AUTO_CLK) {
@ -482,7 +500,7 @@ static esp_err_t ledc_set_timer_div(ledc_mode_t speed_mode, ledc_timer_t timer_n
ESP_RETURN_ON_FALSE((speed_mode == LEDC_LOW_SPEED_MODE), ESP_ERR_INVALID_ARG, LEDC_TAG, "RTC clock can only be used in low speed mode");
/* Before calculating the divisor, we need to have the RTC frequency.
* If it hasn't been mesured yet, try calibrating it now. */
* If it hasn't been measured yet, try calibrating it now. */
if(s_ledc_slow_clk_8M == 0 && ledc_slow_clk_calibrate() == false) {
goto error;
}
@ -522,19 +540,26 @@ static esp_err_t ledc_set_timer_div(ledc_mode_t speed_mode, ledc_timer_t timer_n
/* The following block configures the global clock.
* Thus, in theory, this only makes sense when the source clock is LEDC_SCLK
* and in LOW_SPEED_MODE (as FAST_SPEED_MODE doesn't present any global clock)
* and in LOW_SPEED_MODE (as HIGH_SPEED_MODE doesn't present any global clock)
*
* However, in practice, on modules that support high-speed mode, no matter
* whether the source clock is a timer-specific one (e.g. REF_TICK) or not,
* the global clock MUST be configured when in low speed mode.
* When using high-speed mode, this is not necessary.
* However, in practice, when the source clock is a timer-specific one (e.g.
* REF_TICK) and in LOW_SPEED_MODE, the global clock MUST be set to a
* specific one (APB_CLK). Therefore, in such case, the global clock also
* needs to be configured. In high-speed mode, this is not necessary.
*/
#if SOC_LEDC_SUPPORT_HS_MODE
if (speed_mode == LEDC_LOW_SPEED_MODE) {
#else
if (timer_clk_src == LEDC_SCLK) {
if (timer_clk_src == LEDC_SCLK) {
ESP_LOGD(LEDC_TAG, "In slow speed mode, using clock %d", glb_clk);
} else {
#if SOC_LEDC_SUPPORT_APB_CLOCK
glb_clk = LEDC_SLOW_CLK_APB;
#elif SOC_LEDC_SUPPORT_PLL_DIV_CLOCK
/* Currently, code shouldn't reach here. timer_clk_src != LEDC_SCLK should only happen on esp32 and esp32s2, and
* PLL_DIV starts to replace APB as one of the global clock sources for some new chips. This is for future potential. */
glb_clk = LEDC_SLOW_CLK_PLL_DIV;
#endif
ESP_LOGD(LEDC_TAG, "In slow speed mode, using clock %d", glb_clk);
}
portENTER_CRITICAL(&ledc_spinlock);
ledc_hal_set_slow_clk_sel(&(p_ledc_obj[speed_mode]->ledc_hal), glb_clk);
portEXIT_CRITICAL(&ledc_spinlock);
@ -683,9 +708,9 @@ esp_err_t ledc_set_fade(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t
LEDC_ARG_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "speed_mode");
LEDC_ARG_CHECK(channel < LEDC_CHANNEL_MAX, "channel");
LEDC_ARG_CHECK(fade_direction < LEDC_DUTY_DIR_MAX, "fade_direction");
LEDC_ARG_CHECK(step_num <= LEDC_DUTY_NUM_MAX, "step_num");
LEDC_ARG_CHECK(duty_cyle_num <= LEDC_DUTY_CYCLE_MAX, "duty_cycle_num");
LEDC_ARG_CHECK(duty_scale <= LEDC_DUTY_SCALE_MAX, "duty_scale");
LEDC_ARG_CHECK(step_num <= LEDC_LL_DUTY_NUM_MAX, "step_num");
LEDC_ARG_CHECK(duty_cyle_num <= LEDC_LL_DUTY_CYCLE_MAX, "duty_cycle_num");
LEDC_ARG_CHECK(duty_scale <= LEDC_LL_DUTY_SCALE_MAX, "duty_scale");
LEDC_CHECK(p_ledc_obj[speed_mode] != NULL, LEDC_NOT_INIT, ESP_ERR_INVALID_STATE);
_ledc_fade_hw_acquire(speed_mode, channel);
portENTER_CRITICAL(&ledc_spinlock);
@ -707,7 +732,7 @@ esp_err_t ledc_set_duty_with_hpoint(ledc_mode_t speed_mode, ledc_channel_t chann
{
LEDC_ARG_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "speed_mode");
LEDC_ARG_CHECK(channel < LEDC_CHANNEL_MAX, "channel");
LEDC_ARG_CHECK(hpoint <= LEDC_HPOINT_VAL_MAX, "hpoint");
LEDC_ARG_CHECK(hpoint <= LEDC_LL_HPOINT_VAL_MAX, "hpoint");
LEDC_CHECK(p_ledc_obj[speed_mode] != NULL, LEDC_NOT_INIT, ESP_ERR_INVALID_STATE);
/* The channel configuration should not be changed before the fade operation is done. */
_ledc_fade_hw_acquire(speed_mode, channel);
@ -773,7 +798,7 @@ esp_err_t ledc_set_freq(ledc_mode_t speed_mode, ledc_timer_t timer_num, uint32_t
LEDC_ARG_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "speed_mode");
LEDC_ARG_CHECK(timer_num < LEDC_TIMER_MAX, "timer_num");
LEDC_CHECK(p_ledc_obj[speed_mode] != NULL, LEDC_NOT_INIT, ESP_ERR_INVALID_STATE);
ledc_clk_cfg_t clk_cfg = LEDC_USE_APB_CLK;
ledc_clk_cfg_t clk_cfg = LEDC_AUTO_CLK;
uint32_t duty_resolution = 0;
ledc_hal_get_clk_cfg(&(p_ledc_obj[speed_mode]->ledc_hal), timer_num, &clk_cfg);
ledc_hal_get_duty_resolution(&(p_ledc_obj[speed_mode]->ledc_hal), timer_num, &duty_resolution);
@ -788,13 +813,17 @@ uint32_t ledc_get_freq(ledc_mode_t speed_mode, ledc_timer_t timer_num)
portENTER_CRITICAL(&ledc_spinlock);
uint32_t clock_divider = 0;
uint32_t duty_resolution = 0;
ledc_clk_cfg_t clk_cfg = LEDC_USE_APB_CLK;
ledc_clk_cfg_t clk_cfg = LEDC_AUTO_CLK;
ledc_hal_get_clock_divider(&(p_ledc_obj[speed_mode]->ledc_hal), timer_num, &clock_divider);
ledc_hal_get_duty_resolution(&(p_ledc_obj[speed_mode]->ledc_hal), timer_num, &duty_resolution);
ledc_hal_get_clk_cfg(&(p_ledc_obj[speed_mode]->ledc_hal), timer_num, &clk_cfg);
uint32_t precision = (0x1 << duty_resolution);
uint32_t src_clk_freq = ledc_get_src_clk_freq(clk_cfg);
portEXIT_CRITICAL(&ledc_spinlock);
if (clock_divider == 0) {
ESP_LOGW(LEDC_TAG, "LEDC timer not configured, call ledc_timer_config to set timer frequency");
return 0;
}
return ((uint64_t) src_clk_freq << 8) / precision / clock_divider;
}
@ -864,7 +893,7 @@ void IRAM_ATTR ledc_fade_isr(void *arg)
(duty_cur - duty_tar) : (duty_tar - duty_cur);
if (delta > scale) {
next_duty = duty_cur;
step = (delta / scale > LEDC_STEP_NUM_MAX) ? LEDC_STEP_NUM_MAX : (delta / scale);
step = (delta / scale > LEDC_DUTY_NUM_MAX) ? LEDC_DUTY_NUM_MAX : (delta / scale);
cycle = s_ledc_fade_rec[speed_mode][channel]->cycle_num;
} else {
next_duty = duty_tar;
@ -990,12 +1019,12 @@ static esp_err_t _ledc_set_fade_with_step(ledc_mode_t speed_mode, ledc_channel_t
if (duty_cur > target_duty) {
s_ledc_fade_rec[speed_mode][channel]->direction = LEDC_DUTY_DIR_DECREASE;
step_num = (duty_cur - target_duty) / scale;
step_num = step_num > LEDC_STEP_NUM_MAX ? LEDC_STEP_NUM_MAX : step_num;
step_num = step_num > LEDC_DUTY_NUM_MAX ? LEDC_DUTY_NUM_MAX : step_num;
} else {
s_ledc_fade_rec[speed_mode][channel]->direction = LEDC_DUTY_DIR_INCREASE;
dir = LEDC_DUTY_DIR_INCREASE;
step_num = (target_duty - duty_cur) / scale;
step_num = step_num > LEDC_STEP_NUM_MAX ? LEDC_STEP_NUM_MAX : step_num;
step_num = step_num > LEDC_DUTY_NUM_MAX ? LEDC_DUTY_NUM_MAX : step_num;
}
}
@ -1036,16 +1065,16 @@ static esp_err_t _ledc_set_fade_with_time(ledc_mode_t speed_mode, ledc_channel_t
if (total_cycles > duty_delta) {
scale = 1;
cycle_num = total_cycles / duty_delta;
if (cycle_num > LEDC_DUTY_NUM_MAX) {
if (cycle_num > LEDC_LL_DUTY_NUM_MAX) {
ESP_LOGW(LEDC_TAG, LEDC_FADE_TOO_SLOW_STR);
cycle_num = LEDC_DUTY_NUM_MAX;
cycle_num = LEDC_LL_DUTY_NUM_MAX;
}
} else {
cycle_num = 1;
scale = duty_delta / total_cycles;
if (scale > LEDC_DUTY_SCALE_MAX) {
if (scale > LEDC_LL_DUTY_SCALE_MAX) {
ESP_LOGW(LEDC_TAG, LEDC_FADE_TOO_FAST_STR);
scale = LEDC_DUTY_SCALE_MAX;
scale = LEDC_LL_DUTY_SCALE_MAX;
}
}
return _ledc_set_fade_with_step(speed_mode, channel, target_duty, scale, cycle_num);
@ -1092,8 +1121,8 @@ esp_err_t ledc_set_fade_with_step(ledc_mode_t speed_mode, ledc_channel_t channel
{
LEDC_ARG_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "speed_mode");
LEDC_ARG_CHECK(channel < LEDC_CHANNEL_MAX, "channel");
LEDC_ARG_CHECK((scale > 0) && (scale <= LEDC_DUTY_SCALE_MAX), "fade scale");
LEDC_ARG_CHECK((cycle_num > 0) && (cycle_num <= LEDC_DUTY_CYCLE_MAX), "cycle_num");
LEDC_ARG_CHECK((scale > 0) && (scale <= LEDC_LL_DUTY_SCALE_MAX), "fade scale");
LEDC_ARG_CHECK((cycle_num > 0) && (cycle_num <= LEDC_LL_DUTY_CYCLE_MAX), "cycle_num");
LEDC_ARG_CHECK(target_duty <= ledc_get_max_duty(speed_mode, channel), "target_duty");
LEDC_CHECK(p_ledc_obj[speed_mode] != NULL, LEDC_NOT_INIT, ESP_ERR_INVALID_STATE);
LEDC_CHECK(ledc_fade_channel_init_check(speed_mode, channel) == ESP_OK, LEDC_FADE_INIT_ERROR_STR, ESP_FAIL);
@ -1207,7 +1236,7 @@ esp_err_t ledc_set_duty_and_update(ledc_mode_t speed_mode, ledc_channel_t channe
LEDC_ARG_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "speed_mode");
LEDC_ARG_CHECK(channel < LEDC_CHANNEL_MAX, "channel");
LEDC_ARG_CHECK(duty <= ledc_get_max_duty(speed_mode, channel), "target_duty");
LEDC_ARG_CHECK(hpoint <= LEDC_HPOINT_VAL_MAX, "hpoint");
LEDC_ARG_CHECK(hpoint <= LEDC_LL_HPOINT_VAL_MAX, "hpoint");
LEDC_CHECK(p_ledc_obj[speed_mode] != NULL, LEDC_NOT_INIT, ESP_ERR_INVALID_STATE);
LEDC_CHECK(ledc_fade_channel_init_check(speed_mode, channel) == ESP_OK, LEDC_FADE_INIT_ERROR_STR, ESP_FAIL);
_ledc_fade_hw_acquire(speed_mode, channel);
@ -1242,8 +1271,8 @@ esp_err_t ledc_set_fade_step_and_start(ledc_mode_t speed_mode, ledc_channel_t ch
LEDC_ARG_CHECK(fade_mode < LEDC_FADE_MAX, "fade_mode");
LEDC_CHECK(p_ledc_obj[speed_mode] != NULL, LEDC_NOT_INIT, ESP_ERR_INVALID_STATE);
LEDC_CHECK(ledc_fade_channel_init_check(speed_mode, channel) == ESP_OK, LEDC_FADE_INIT_ERROR_STR, ESP_FAIL);
LEDC_ARG_CHECK((scale > 0) && (scale <= LEDC_DUTY_SCALE_MAX), "fade scale");
LEDC_ARG_CHECK((cycle_num > 0) && (cycle_num <= LEDC_DUTY_CYCLE_MAX), "cycle_num");
LEDC_ARG_CHECK((scale > 0) && (scale <= LEDC_LL_DUTY_SCALE_MAX), "fade scale");
LEDC_ARG_CHECK((cycle_num > 0) && (cycle_num <= LEDC_LL_DUTY_CYCLE_MAX), "cycle_num");
LEDC_ARG_CHECK(target_duty <= ledc_get_max_duty(speed_mode, channel), "target_duty");
_ledc_op_lock_acquire(speed_mode, channel);
_ledc_fade_hw_acquire(speed_mode, channel);

View File

@ -24,6 +24,7 @@
#include "soc/io_mux_reg.h"
#include "esp_system.h"
#include "driver/ledc.h"
#include "hal/ledc_ll.h"
#include "driver/gpio.h"
#define PULSE_IO 18
@ -38,6 +39,12 @@
#define SPEED_MODE_LIST {LEDC_LOW_SPEED_MODE}
#endif
#if SOC_LEDC_SUPPORT_APB_CLOCK
#define TEST_DEFAULT_CLK_CFG LEDC_USE_APB_CLK
#elif SOC_LEDC_SUPPORT_PLL_DIV_CLOCK
#define TEST_DEFAULT_CLK_CFG LEDC_USE_PLL_DIV_CLK
#endif
static ledc_channel_config_t initialize_channel_config(void)
{
ledc_channel_config_t config;
@ -60,7 +67,7 @@ static ledc_timer_config_t create_default_timer_config(void)
ledc_time_config.duty_resolution = LEDC_TIMER_13_BIT;
ledc_time_config.timer_num = LEDC_TIMER_0;
ledc_time_config.freq_hz = TEST_PWM_FREQ;
ledc_time_config.clk_cfg = LEDC_USE_APB_CLK;
ledc_time_config.clk_cfg = TEST_DEFAULT_CLK_CFG;
return ledc_time_config;
}
@ -178,7 +185,7 @@ TEST_CASE("LEDC timer config basic parameter test", "[ledc]")
TEST_ESP_OK(ledc_timer_config(&ledc_time_config));
}
TEST_CASE("LEDC error log channel and timer config", "[ledc]")
TEST_CASE("LEDC output idle level test", "[ledc]")
{
const ledc_mode_t test_speed_mode = TEST_SPEED_MODE;
ledc_channel_config_t ledc_ch_config = initialize_channel_config();
@ -390,7 +397,7 @@ TEST_CASE("LEDC fade stop test", "[ledc]")
}
#endif // SOC_LEDC_SUPPORT_FADE_STOP
#if SOC_PCNT_SUPPORTED
#if SOC_PCNT_SUPPORTED // Note. C3, C2, H2 do not have PCNT peripheral, the following test cases cannot be tested
#include "driver/pulse_cnt.h"
@ -487,7 +494,29 @@ TEST_CASE("LEDC set and get frequency", "[ledc][timeout=60][ignore]")
tear_testbench();
}
TEST_CASE("LEDC timer set", "[ledc]")
static void timer_set_clk_src_and_freq_test(ledc_mode_t speed_mode, ledc_clk_cfg_t clk_src, uint32_t duty_res,
uint32_t freq_hz)
{
ledc_timer_config_t ledc_time_config = {
.speed_mode = speed_mode,
.duty_resolution = duty_res,
.timer_num = LEDC_TIMER_0,
.freq_hz = freq_hz,
.clk_cfg = clk_src,
};
TEST_ESP_OK(ledc_timer_config(&ledc_time_config));
vTaskDelay(100 / portTICK_PERIOD_MS);
if (clk_src == LEDC_USE_RTC8M_CLK) {
// RTC8M_CLK freq is get from calibration, it is reasonable that divider calculation does a rounding
TEST_ASSERT_UINT32_WITHIN(5, ledc_get_freq(speed_mode, LEDC_TIMER_0), freq_hz);
} else {
TEST_ASSERT_EQUAL_INT32(ledc_get_freq(speed_mode, LEDC_TIMER_0), freq_hz);
}
int count = wave_count(1000);
TEST_ASSERT_UINT32_WITHIN(10, count, freq_hz);
}
TEST_CASE("LEDC timer select specific clock source", "[ledc]")
{
setup_testbench();
const ledc_mode_t test_speed_mode = TEST_SPEED_MODE;
@ -502,44 +531,32 @@ TEST_CASE("LEDC timer set", "[ledc]")
};
TEST_ESP_OK(ledc_channel_config(&ledc_ch_config));
ledc_timer_config_t ledc_time_config = {
.speed_mode = test_speed_mode,
.duty_resolution = 13,
.timer_num = LEDC_TIMER_0,
.freq_hz = 5000,
.clk_cfg = LEDC_USE_APB_CLK,
};
TEST_ESP_OK(ledc_timer_config(&ledc_time_config));
uint32_t freq_get;
int count;
#if SOC_LEDC_SUPPORT_REF_TICK
//set timer 0 as 250Hz, use REF_TICK
TEST_ESP_OK(ledc_timer_set(test_speed_mode, LEDC_TIMER_0, 1000, 10, LEDC_REF_TICK));
TEST_ESP_OK(ledc_timer_rst(test_speed_mode, LEDC_TIMER_0));
TEST_ASSERT_EQUAL_INT32(ledc_get_freq(test_speed_mode, LEDC_TIMER_0), 250);
freq_get = ledc_get_freq(test_speed_mode, LEDC_TIMER_0);
count = wave_count(1000);
TEST_ASSERT_UINT32_WITHIN(10, count, freq_get);
if (test_speed_mode == LEDC_LOW_SPEED_MODE) {
printf("Check LEDC_USE_RTC8M_CLK for a 100Hz signal\n");
timer_set_clk_src_and_freq_test(test_speed_mode, LEDC_USE_RTC8M_CLK, 10, 100);
#if SOC_LEDC_SUPPORT_XTAL_CLOCK
printf("Check LEDC_USE_XTAL_CLK for a 400Hz signal\n");
timer_set_clk_src_and_freq_test(test_speed_mode, LEDC_USE_XTAL_CLK, 13, 400);
#endif
}
#if SOC_LEDC_SUPPORT_REF_TICK
printf("Check LEDC_USE_REF_TICK for a 250Hz signal\n");
timer_set_clk_src_and_freq_test(test_speed_mode, LEDC_USE_REF_TICK, 10, 250);
#endif
#if SOC_LEDC_SUPPORT_APB_CLOCK
printf("Check LEDC_USE_APB_CLK for a 500Hz signal\n");
timer_set_clk_src_and_freq_test(test_speed_mode, LEDC_USE_APB_CLK, 13, 500);
#endif
#if SOC_LEDC_SUPPORT_PLL_DIV_CLOCK
printf("Check LEDC_USE_PLL_DIV_CLK for a 500Hz signal\n");
timer_set_clk_src_and_freq_test(test_speed_mode, LEDC_USE_PLL_DIV_CLK, 13, 500);
#endif
//set timer 0 as 500Hz, use APB_CLK
TEST_ESP_OK(ledc_timer_set(test_speed_mode, LEDC_TIMER_0, 5000, 13, LEDC_APB_CLK));
TEST_ESP_OK(ledc_timer_rst(test_speed_mode, LEDC_TIMER_0));
TEST_ASSERT_EQUAL_INT32(ledc_get_freq(test_speed_mode, LEDC_TIMER_0), 500);
freq_get = ledc_get_freq(test_speed_mode, LEDC_TIMER_0);
count = wave_count(1000);
TEST_ASSERT_UINT32_WITHIN(50, count, freq_get);
printf("Bind channel 0 to timer 0\n");
TEST_ESP_OK(ledc_bind_channel_timer(test_speed_mode, LEDC_CHANNEL_0, LEDC_TIMER_0));
vTaskDelay(1000 / portTICK_PERIOD_MS);
TEST_ASSERT_EQUAL_INT32(ledc_get_freq(test_speed_mode, LEDC_TIMER_0), 500);
uint32_t current_level = LEDC.channel_group[test_speed_mode].channel[LEDC_CHANNEL_0].conf0.idle_lv;
TEST_ESP_OK(ledc_stop(test_speed_mode, LEDC_CHANNEL_0, !current_level));
vTaskDelay(1000 / portTICK_PERIOD_MS);
TEST_ASSERT_EQUAL_INT32( LEDC.channel_group[test_speed_mode].channel[LEDC_CHANNEL_0].conf0.idle_lv, !current_level);
tear_testbench();
}
@ -564,10 +581,11 @@ TEST_CASE("LEDC timer pause and resume", "[ledc]")
.duty_resolution = LEDC_TIMER_13_BIT,
.timer_num = LEDC_TIMER_0,
.freq_hz = 5000,
.clk_cfg = LEDC_USE_APB_CLK,
.clk_cfg = TEST_DEFAULT_CLK_CFG,
};
TEST_ESP_OK(ledc_timer_config(&ledc_time_config));
vTaskDelay(10 / portTICK_PERIOD_MS);
count = wave_count(1000);
TEST_ASSERT_INT16_WITHIN(5, count, 5000);

View File

@ -9,8 +9,6 @@
#include "esp_check.h"
#include "sdkconfig.h"
#define DELAY_RTC_CLK_SWITCH 5
static portMUX_TYPE periph_spinlock = portMUX_INITIALIZER_UNLOCKED;
static uint8_t s_periph_ref_counts = 0;
@ -28,15 +26,13 @@ bool periph_rtc_dig_clk8m_enable(void)
portENTER_CRITICAL(&periph_spinlock);
if (s_periph_ref_counts == 0) {
rtc_dig_clk8m_enable();
#if CONFIG_IDF_TARGET_ESP32H2
s_rtc_clk_freq = rtc_clk_freq_cal(rtc_clk_cal(RTC_CAL_RC32K, 100));
#else
#if !CONFIG_IDF_TARGET_ESP32H2
s_rtc_clk_freq = rtc_clk_freq_cal(rtc_clk_cal(RTC_CAL_8MD256, 100));
#endif
if (s_rtc_clk_freq == 0) {
portEXIT_CRITICAL(&periph_spinlock);
return false;
}
#endif
}
s_periph_ref_counts++;
portEXIT_CRITICAL(&periph_spinlock);
@ -45,7 +41,12 @@ bool periph_rtc_dig_clk8m_enable(void)
uint32_t periph_rtc_dig_clk8m_get_freq(void)
{
#if CONFIG_IDF_TARGET_ESP32H2
/* Workaround: H2 doesn't have 8MD256 clk, so calibration cannot be done, we just return its theoretic frequency */
return RTC_FAST_CLK_FREQ_APPROX;
#else
return s_rtc_clk_freq * 256;
#endif
}
void periph_rtc_dig_clk8m_disable(void)

View File

@ -13,7 +13,12 @@
#include "soc/ledc_periph.h"
#include "soc/ledc_struct.h"
#define LEDC_LL_GET_HW() &LEDC
#define LEDC_LL_GET_HW() &LEDC
#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_FRACTIONAL_BITS (8)
#define LEDC_LL_FRACTIONAL_MAX ((1 << LEDC_LL_FRACTIONAL_BITS) - 1)
@ -25,7 +30,7 @@
{\
{ \
.clk = LEDC_REF_TICK, \
.freq = LEDC_REF_CLK_HZ, \
.freq = REF_CLK_FREQ, \
} \
}
@ -153,6 +158,9 @@ static inline void ledc_ll_get_clock_divider(ledc_dev_t *hw, ledc_mode_t speed_m
* @param timer_sel LEDC timer index (0-3), select from ledc_timer_t
* @param clk_src Timer clock source
*
* @note REF_TICK can only be used when hw->conf.slow_clk_sel is set to 1 (through ledc_ll_set_slow_clk_sel()).
* This is ensured in the LEDC driver layer.
*
* @return None
*/
static inline void ledc_ll_set_clock_source(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_timer_t timer_sel, ledc_clk_src_t clk_src){

View File

@ -11,19 +11,26 @@
#include "hal/ledc_types.h"
#include "soc/ledc_periph.h"
#include "hal/assert.h"
#ifdef __cplusplus
extern "C" {
#endif
#define LEDC_LL_GET_HW() &LEDC
#define LEDC_LL_GET_HW() &LEDC
#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_FRACTIONAL_BITS (8)
#define LEDC_LL_FRACTIONAL_MAX ((1 << LEDC_LL_FRACTIONAL_BITS) - 1)
#define LEDC_LL_GLOBAL_CLOCKS { \
LEDC_SLOW_CLK_APB, \
LEDC_SLOW_CLK_PLL_DIV, \
LEDC_SLOW_CLK_XTAL, \
LEDC_SLOW_CLK_RTC8M, \
}
#define LEDC_LL_PLL_DIV_CLK_FREQ (60 * 1000000) // PLL_60M_CLK: 60MHz
/**
@ -37,7 +44,7 @@ extern "C" {
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 = 0;
if (slow_clk_sel == LEDC_SLOW_CLK_APB) {
if (slow_clk_sel == LEDC_SLOW_CLK_PLL_DIV) {
clk_sel_val = 1;
} else if (slow_clk_sel == LEDC_SLOW_CLK_RTC8M) {
clk_sel_val = 2;
@ -59,11 +66,13 @@ static inline void ledc_ll_get_slow_clk_sel(ledc_dev_t *hw, ledc_slow_clk_sel_t
{
uint32_t clk_sel_val = hw->conf.apb_clk_sel;
if (clk_sel_val == 1) {
*slow_clk_sel = LEDC_SLOW_CLK_APB;
*slow_clk_sel = LEDC_SLOW_CLK_PLL_DIV;
} else if (clk_sel_val == 2) {
*slow_clk_sel = LEDC_SLOW_CLK_RTC8M;
} else if (clk_sel_val == 3) {
*slow_clk_sel = LEDC_SLOW_CLK_XTAL;
} else {
abort();
}
}
@ -78,7 +87,7 @@ static inline void ledc_ll_get_slow_clk_sel(ledc_dev_t *hw, ledc_slow_clk_sel_t
*/
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.low_speed_update = 1;
hw->timer_group[speed_mode].timer[timer_sel].conf.para_up = 1;
}
/**
@ -136,7 +145,7 @@ static inline void ledc_ll_timer_resume(ledc_dev_t *hw, ledc_mode_t speed_mode,
*/
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.clock_divider = clock_divider;
hw->timer_group[speed_mode].timer[timer_sel].conf.clk_div = clock_divider;
}
/**
@ -151,7 +160,7 @@ static inline void ledc_ll_set_clock_divider(ledc_dev_t *hw, ledc_mode_t speed_m
*/
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.clock_divider;
*clock_divider = hw->timer_group[speed_mode].timer[timer_sel].conf.clk_div;
}
/**
@ -166,7 +175,7 @@ static inline void ledc_ll_get_clock_divider(ledc_dev_t *hw, ledc_mode_t speed_m
*/
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)
{
*clk_src = LEDC_APB_CLK;
*clk_src = LEDC_SCLK;
}
/**
@ -181,7 +190,7 @@ static inline void ledc_ll_get_clock_source(ledc_dev_t *hw, ledc_mode_t speed_mo
*/
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_resolution = duty_resolution;
hw->timer_group[speed_mode].timer[timer_sel].conf.duty_res = duty_resolution;
}
/**
@ -196,7 +205,7 @@ static inline void ledc_ll_set_duty_resolution(ledc_dev_t *hw, ledc_mode_t speed
*/
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_resolution;
*duty_resolution = hw->timer_group[speed_mode].timer[timer_sel].conf.duty_res;
}
/**
@ -210,7 +219,7 @@ static inline void ledc_ll_get_duty_resolution(ledc_dev_t *hw, ledc_mode_t speed
*/
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.low_speed_update = 1;
hw->channel_group[speed_mode].channel[channel_num].conf0.para_up = 1;
}
/**
@ -226,7 +235,7 @@ static inline void ledc_ll_ls_channel_update(ledc_dev_t *hw, ledc_mode_t speed_m
static inline void ledc_ll_get_max_duty(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel_num, uint32_t *max_duty)
{
uint32_t timer_sel = hw->channel_group[speed_mode].channel[channel_num].conf0.timer_sel;
*max_duty = (1 << (LEDC.timer_group[speed_mode].timer[timer_sel].conf.duty_resolution));
*max_duty = (1 << (LEDC.timer_group[speed_mode].timer[timer_sel].conf.duty_res));
}
/**
@ -286,7 +295,7 @@ static inline void ledc_ll_set_duty_int_part(ledc_dev_t *hw, ledc_mode_t speed_m
*/
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_rd.duty_read >> 4);
*duty_val = (hw->channel_group[speed_mode].channel[channel_num].duty_rd.duty_r >> 4);
}
/**
@ -422,7 +431,7 @@ static inline void ledc_ll_set_idle_level(ledc_dev_t *hw, ledc_mode_t speed_mode
static inline void ledc_ll_set_fade_end_intr(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel_num, bool fade_end_intr_en)
{
uint32_t value = hw->int_ena.val;
uint32_t int_en_base = LEDC_DUTY_CHNG_END_LSCH0_INT_ENA_S;
uint32_t int_en_base = LEDC_DUTY_CHNG_END_CH0_INT_ENA_S;
hw->int_ena.val = fade_end_intr_en ? (value | BIT(int_en_base + channel_num)) : (value & (~(BIT(int_en_base + channel_num))));
}
@ -439,7 +448,7 @@ static inline void ledc_ll_set_fade_end_intr(ledc_dev_t *hw, ledc_mode_t speed_m
static inline void ledc_ll_get_fade_end_intr_status(ledc_dev_t *hw, ledc_mode_t speed_mode, uint32_t *intr_status)
{
uint32_t value = hw->int_st.val;
uint32_t int_en_base = LEDC_DUTY_CHNG_END_LSCH0_INT_ENA_S;
uint32_t int_en_base = LEDC_DUTY_CHNG_END_CH0_INT_ENA_S;
*intr_status = (value >> int_en_base) & 0xff;
}
@ -454,7 +463,7 @@ static inline void ledc_ll_get_fade_end_intr_status(ledc_dev_t *hw, ledc_mode_t
*/
static inline void ledc_ll_clear_fade_end_intr_status(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel_num)
{
uint32_t int_en_base = LEDC_DUTY_CHNG_END_LSCH0_INT_ENA_S;
uint32_t int_en_base = LEDC_DUTY_CHNG_END_CH0_INT_ENA_S;
hw->int_clr.val = BIT(int_en_base + channel_num);
}

View File

@ -12,12 +12,18 @@
#include "hal/ledc_types.h"
#include "soc/ledc_periph.h"
#include "soc/ledc_struct.h"
#include "hal/assert.h"
#ifdef __cplusplus
extern "C" {
#endif
#define LEDC_LL_GET_HW() &LEDC
#define LEDC_LL_GET_HW() &LEDC
#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_FRACTIONAL_BITS (8)
#define LEDC_LL_FRACTIONAL_MAX ((1 << LEDC_LL_FRACTIONAL_BITS) - 1)
#define LEDC_LL_GLOBAL_CLOCKS { \
@ -64,6 +70,8 @@ static inline void ledc_ll_get_slow_clk_sel(ledc_dev_t *hw, ledc_slow_clk_sel_t
*slow_clk_sel = LEDC_SLOW_CLK_RTC8M;
} else if (clk_sel_val == 3) {
*slow_clk_sel = LEDC_SLOW_CLK_XTAL;
} else {
abort();
}
}

View File

@ -12,12 +12,18 @@
#include "hal/ledc_types.h"
#include "soc/ledc_periph.h"
#include "soc/ledc_struct.h"
#include "hal/assert.h"
#ifdef __cplusplus
extern "C" {
#endif
#define LEDC_LL_GET_HW() &LEDC
#define LEDC_LL_GET_HW() &LEDC
#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_FRACTIONAL_BITS (8)
#define LEDC_LL_FRACTIONAL_MAX ((1 << LEDC_LL_FRACTIONAL_BITS) - 1)
#define LEDC_LL_GLOBAL_CLOCKS { \
@ -64,6 +70,8 @@ static inline void ledc_ll_get_slow_clk_sel(ledc_dev_t *hw, ledc_slow_clk_sel_t
*slow_clk_sel = LEDC_SLOW_CLK_RTC8M;
} else if (clk_sel_val == 3) {
*slow_clk_sel = LEDC_SLOW_CLK_XTAL;
} else {
abort();
}
}

View File

@ -12,12 +12,18 @@
#include "hal/ledc_types.h"
#include "soc/ledc_periph.h"
#include "soc/ledc_struct.h"
#include "hal/assert.h"
#ifdef __cplusplus
extern "C" {
#endif
#define LEDC_LL_GET_HW() &LEDC
#define LEDC_LL_GET_HW() &LEDC
#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_FRACTIONAL_BITS (8)
#define LEDC_LL_FRACTIONAL_MAX ((1 << LEDC_LL_FRACTIONAL_BITS) - 1)
#define LEDC_LL_GLOBAL_CLOCKS { \
@ -29,7 +35,7 @@ extern "C" {
{\
{ \
.clk = LEDC_REF_TICK, \
.freq = LEDC_REF_CLK_HZ, \
.freq = REF_CLK_FREQ, \
} \
}
@ -71,6 +77,8 @@ static inline void ledc_ll_get_slow_clk_sel(ledc_dev_t *hw, ledc_slow_clk_sel_t
*slow_clk_sel = LEDC_SLOW_CLK_RTC8M;
} else if (clk_sel_val == 3) {
*slow_clk_sel = LEDC_SLOW_CLK_XTAL;
} else {
abort();
}
}
@ -163,13 +171,14 @@ static inline void ledc_ll_get_clock_divider(ledc_dev_t *hw, ledc_mode_t speed_m
* @param timer_sel LEDC timer index (0-3), select from ledc_timer_t
* @param clk_src Timer clock source
*
* @note REF_TICK can only be used when hw->conf.apb_clk_sel is set to 1 (through ledc_ll_set_slow_clk_sel()).
* This is ensured in the LEDC driver layer.
*
* @return None
*/
static inline void ledc_ll_set_clock_source(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_timer_t timer_sel, ledc_clk_src_t clk_src){
if (clk_src == LEDC_REF_TICK) {
//REF_TICK can only be used when APB is selected.
hw->timer_group[speed_mode].timer[timer_sel].conf.tick_sel = 1;
hw->conf.apb_clk_sel = 1;
} else {
hw->timer_group[speed_mode].timer[timer_sel].conf.tick_sel = 0;
}

View File

@ -12,12 +12,18 @@
#include "hal/ledc_types.h"
#include "soc/ledc_periph.h"
#include "soc/ledc_struct.h"
#include "hal/assert.h"
#ifdef __cplusplus
extern "C" {
#endif
#define LEDC_LL_GET_HW() &LEDC
#define LEDC_LL_GET_HW() &LEDC
#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_FRACTIONAL_BITS (8)
#define LEDC_LL_FRACTIONAL_MAX ((1 << LEDC_LL_FRACTIONAL_BITS) - 1)
#define LEDC_LL_GLOBAL_CLOCKS { \
@ -64,6 +70,8 @@ static inline void ledc_ll_get_slow_clk_sel(ledc_dev_t *hw, ledc_slow_clk_sel_t
*slow_clk_sel = LEDC_SLOW_CLK_RTC8M;
} else if (clk_sel_val == 3) {
*slow_clk_sel = LEDC_SLOW_CLK_XTAL;
} else {
abort();
}
}

View File

@ -1,16 +1,8 @@
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*
* SPDX-FileCopyrightText: 2019-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/*******************************************************************************
* NOTICE
@ -376,13 +368,3 @@ void ledc_hal_clear_fade_end_intr_status(ledc_hal_context_t *hal, ledc_channel_t
* @return None
*/
void ledc_hal_get_clk_cfg(ledc_hal_context_t *hal, ledc_timer_t timer_sel, ledc_clk_cfg_t *clk_cfg);
/**
* @brief Config low speed timer clock source with clock config
*s
* @param hal Context of the HAL layer
* @param clk_cfg clock config
*
* @return None
*/
void ledc_hal_set_slow_clk(ledc_hal_context_t *hal, ledc_clk_cfg_t clk_cfg);

View File

@ -36,7 +36,12 @@ typedef enum {
typedef enum {
LEDC_SLOW_CLK_RTC8M = 0, /*!< LEDC low speed timer clock source is 8MHz RTC clock*/
#if SOC_LEDC_SUPPORT_APB_CLOCK
LEDC_SLOW_CLK_APB, /*!< LEDC low speed timer clock source is 80MHz APB clock*/
#endif
#if SOC_LEDC_SUPPORT_PLL_DIV_CLOCK
LEDC_SLOW_CLK_PLL_DIV, /*!< LEDC low speed timer clock source is a PLL_DIV clock*/
#endif
#if SOC_LEDC_SUPPORT_XTAL_CLOCK
LEDC_SLOW_CLK_XTAL, /*!< LEDC low speed timer clock source XTAL clock*/
#endif
@ -49,8 +54,13 @@ typedef enum {
* here.
*/
typedef enum {
LEDC_AUTO_CLK = 0, /*!< The driver will automatically select the source clock(REF_TICK or APB) based on the giving resolution and duty parameter when init the timer*/
LEDC_AUTO_CLK = 0, /*!< The driver will automatically select the source clock based on the giving resolution and duty parameter when init the timer*/
#if SOC_LEDC_SUPPORT_APB_CLOCK
LEDC_USE_APB_CLK, /*!< LEDC timer select APB clock as source clock*/
#endif
#if SOC_LEDC_SUPPORT_PLL_DIV_CLOCK
LEDC_USE_PLL_DIV_CLK, /*!< LEDC timer select the PLL_DIV clock available to LEDC peripheral as source clock*/
#endif
LEDC_USE_RTC8M_CLK, /*!< LEDC timer select RTC8M_CLK as source clock. Only for low speed channels and this parameter must be the same for all low speed channels*/
#if SOC_LEDC_SUPPORT_REF_TICK
LEDC_USE_REF_TICK, /*!< LEDC timer select REF_TICK clock as source clock*/
@ -67,8 +77,12 @@ typedef enum {
#if SOC_LEDC_SUPPORT_REF_TICK
LEDC_REF_TICK = LEDC_USE_REF_TICK, /*!< LEDC timer clock divided from reference tick (1Mhz) */
#endif
#if SOC_LEDC_SUPPORT_APB_CLOCK
LEDC_APB_CLK = LEDC_USE_APB_CLK, /*!< LEDC timer clock divided from APB clock (80Mhz) */
LEDC_SCLK = LEDC_USE_APB_CLK /*!< Selecting this value for LEDC_TICK_SEL_TIMER let the hardware take its source clock from LEDC_APB_CLK_SEL */
LEDC_SCLK = LEDC_USE_APB_CLK, /*!< Selecting this value for LEDC_TICK_SEL_TIMER let the hardware take its source clock from LEDC_APB_CLK_SEL */
#elif SOC_LEDC_SUPPORT_PLL_DIV_CLOCK
LEDC_SCLK = LEDC_USE_PLL_DIV_CLK, /*!< Selecting this value for LEDC_TICK_SEL_TIMER let the hardware take its source clock from LEDC_CLK_SEL */
#endif
} ledc_clk_src_t;
typedef enum {

View File

@ -9,6 +9,7 @@
#include "esp_attr.h"
#include "hal/ledc_hal.h"
#include "soc/soc_caps.h"
#include "hal/assert.h"
void ledc_hal_init(ledc_hal_context_t *hal, ledc_mode_t speed_mode)
{
@ -19,11 +20,18 @@ void ledc_hal_init(ledc_hal_context_t *hal, ledc_mode_t speed_mode)
static inline ledc_clk_cfg_t ledc_hal_get_slow_clock_helper(ledc_hal_context_t *hal)
{
ledc_slow_clk_sel_t slow_clk = LEDC_SLOW_CLK_APB;
ledc_slow_clk_sel_t slow_clk;
ledc_hal_get_slow_clk_sel(hal, &slow_clk);
switch (slow_clk) {
#if SOC_LEDC_SUPPORT_APB_CLOCK
case LEDC_SLOW_CLK_APB:
return LEDC_USE_APB_CLK;
#endif
#if SOC_LEDC_SUPPORT_PLL_DIV_CLOCK
case LEDC_SLOW_CLK_PLL_DIV:
return LEDC_USE_PLL_DIV_CLK;
#endif
case LEDC_SLOW_CLK_RTC8M:
return LEDC_USE_RTC8M_CLK;
#if SOC_LEDC_SUPPORT_XTAL_CLOCK
@ -31,18 +39,20 @@ static inline ledc_clk_cfg_t ledc_hal_get_slow_clock_helper(ledc_hal_context_t *
return LEDC_USE_XTAL_CLK;
#endif
default:
return LEDC_USE_APB_CLK;
// Should never reach here
HAL_ASSERT(false && "invalid slow clock source");
return LEDC_AUTO_CLK;
}
}
void ledc_hal_get_clk_cfg(ledc_hal_context_t *hal, ledc_timer_t timer_sel, ledc_clk_cfg_t *clk_cfg)
{
/* Use the following variable to retrieve the clock source used by the LEDC
* hardware controler. */
* hardware controller. */
ledc_clk_src_t clk_src;
/* Clock configuration to return to the driver. */
ledc_clk_cfg_t driver_clk = LEDC_USE_APB_CLK;
ledc_clk_cfg_t driver_clk = LEDC_AUTO_CLK;
/* Get the timer-specific mux value. */
ledc_hal_get_clock_source(hal, timer_sel, &clk_src);
@ -51,39 +61,24 @@ void ledc_hal_get_clk_cfg(ledc_hal_context_t *hal, ledc_timer_t timer_sel, ledc_
driver_clk = LEDC_USE_REF_TICK;
} else
#endif
/* If the timer-specific mux is not set to REF_TICK, it either means that:
* - The controler is in fast mode, and thus using APB clock (driver_clk
* variable's default value)
* - The controler is in slow mode and so, using a global clock,
* so we have to retrieve that clock here.
*/
if (hal->speed_mode == LEDC_LOW_SPEED_MODE) {
/* If the source clock used by LEDC hardware is not REF_TICKS, it is
* necessary to retrieve the global clock source used. */
driver_clk = ledc_hal_get_slow_clock_helper(hal);
{
/* If the timer-specific mux is not set to REF_TICK, it either means that:
* - The controler is in fast mode, and thus using APB clock (driver_clk
* variable's default value)
* - The controler is in slow mode and so, using a global clock,
* so we have to retrieve that clock here.
*/
if (hal->speed_mode == LEDC_LOW_SPEED_MODE) {
/* If the source clock used by LEDC hardware is not REF_TICK, it is
* necessary to retrieve the global clock source used. */
driver_clk = ledc_hal_get_slow_clock_helper(hal);
}
#if SOC_LEDC_SUPPORT_HS_MODE
else {
driver_clk = LEDC_USE_APB_CLK;
}
#endif
}
*clk_cfg = driver_clk;
}
void ledc_hal_set_slow_clk(ledc_hal_context_t *hal, ledc_clk_cfg_t clk_cfg)
{
// For low speed channels, if RTC_8MCLK is used as the source clock, the `slow_clk_sel` register should be cleared, otherwise it should be set.
ledc_slow_clk_sel_t slow_clk_sel;
switch (clk_cfg) {
case LEDC_USE_RTC8M_CLK:
slow_clk_sel = LEDC_SLOW_CLK_RTC8M;
break;
#if SOC_LEDC_SUPPORT_XTAL_CLOCK
case LEDC_USE_XTAL_CLK:
slow_clk_sel = LEDC_SLOW_CLK_XTAL;
break;
#endif
default:
slow_clk_sel = LEDC_SLOW_CLK_APB;
break;
}
ledc_hal_set_slow_clk_sel(hal, slow_clk_sel);
}

View File

@ -307,6 +307,10 @@ config SOC_LEDC_HAS_TIMER_SPECIFIC_MUX
bool
default y
config SOC_LEDC_SUPPORT_APB_CLOCK
bool
default y
config SOC_LEDC_SUPPORT_REF_TICK
bool
default y

View File

@ -198,10 +198,11 @@
/*-------------------------- LEDC CAPS ---------------------------------------*/
#define SOC_LEDC_HAS_TIMER_SPECIFIC_MUX (1)
#define SOC_LEDC_SUPPORT_REF_TICK (1)
#define SOC_LEDC_SUPPORT_HS_MODE (1)
#define SOC_LEDC_CHANNEL_NUM (8)
#define SOC_LEDC_TIMER_BIT_WIDE_NUM (20)
#define SOC_LEDC_SUPPORT_APB_CLOCK (1)
#define SOC_LEDC_SUPPORT_REF_TICK (1)
#define SOC_LEDC_SUPPORT_HS_MODE (1)
#define SOC_LEDC_CHANNEL_NUM (8)
#define SOC_LEDC_TIMER_BIT_WIDE_NUM (20)
/*-------------------------- MCPWM CAPS --------------------------------------*/
#define SOC_MCPWM_GROUPS (2) ///< 2 MCPWM groups on the chip (i.e., the number of independent MCPWM peripherals)

View File

@ -227,6 +227,10 @@ config SOC_I2C_SUPPORT_RTC
bool
default y
config SOC_LEDC_SUPPORT_PLL_DIV_CLOCK
bool
default y
config SOC_LEDC_SUPPORT_XTAL_CLOCK
bool
default y

File diff suppressed because it is too large Load Diff

View File

@ -1,209 +1,596 @@
/*
* SPDX-FileCopyrightText: 2017-2022 Espressif Systems (Shanghai) CO LTD
/**
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef _SOC_LEDC_STRUCT_H_
#define _SOC_LEDC_STRUCT_H_
#pragma once
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef volatile struct ledc_dev_s {
/** Group: Configuration Register */
/** Type of chn_conf0 register
* Configuration register 0 for channel n
*/
typedef union {
struct {
struct {
union {
struct {
uint32_t timer_sel : 2; /*This field is used to select one of timers for channel $n.; ; 0: select timer0; 1: select timer1; 2: select timer2; 3: select timer3*/
uint32_t sig_out_en : 1; /*Set this bit to enable signal output on channel $n.*/
uint32_t idle_lv : 1; /*This bit is used to control the output value when channel $n is inactive (when LEDC_SIG_OUT_EN_CH$n is 0).*/
uint32_t low_speed_update : 1; /*This bit is used to update LEDC_HPOINT_CH$n, LEDC_DUTY_START_CH$n, LEDC_SIG_OUT_EN_CH$n, LEDC_TIMER_SEL_CH$n, LEDC_DUTY_NUM_CH$n, LEDC_DUTY_CYCLE_CH$n, LEDC_DUTY_SCALE_CH$n, LEDC_DUTY_INC_CH$n, and LEDC_OVF_CNT_EN_CH$n fields for channel $n, and will be automatically cleared by hardware.*/
uint32_t ovf_num : 10; /*This register is used to configure the maximum times of overflow minus 1.; ; The LEDC_OVF_CNT_CH$n_INT interrupt will be triggered when channel $n overflows for (LEDC_OVF_NUM_CH$n + 1) times.*/
uint32_t ovf_cnt_en : 1; /*This bit is used to enable the ovf_cnt of channel $n.*/
uint32_t ovf_cnt_rst : 1; /*Set this bit to reset the ovf_cnt of channel $n.*/
uint32_t reserved17 : 15; /*Reserved*/
};
uint32_t val;
} conf0;
union {
struct {
uint32_t hpoint : 14; /*The output value changes to high when the selected timers has reached the value specified by this register.*/
uint32_t reserved14 : 18; /*Reserved*/
};
uint32_t val;
} hpoint;
union {
struct {
uint32_t duty : 19; /*This register is used to change the output duty by controlling the Lpoint.; ; The output value turns to low when the selected timers has reached the Lpoint.*/
uint32_t reserved19 : 13; /*Reserved*/
};
uint32_t val;
} duty;
union {
struct {
uint32_t duty_scale : 10; /*This register is used to configure the changing step scale of duty on channel $n.*/
uint32_t duty_cycle : 10; /*The duty will change every LEDC_DUTY_CYCLE_CH$n on channel $n.*/
uint32_t duty_num : 10; /*This register is used to control the number of times the duty cycle will be changed.*/
uint32_t duty_inc : 1; /*This register is used to increase or decrease the duty of output signal on channel $n. 1: Increase; 0: Decrease.*/
uint32_t duty_start : 1; /*Other configured fields in LEDC_CH$n_CONF1_REG will start to take effect when this bit is set to 1.*/
};
uint32_t val;
} conf1;
union {
struct {
uint32_t duty_read : 19; /*This register stores the current duty of output signal on channel $n.*/
uint32_t reserved19 : 13; /*Reserved*/
};
uint32_t val;
} duty_rd;
} channel[6];
} channel_group[1];
uint32_t reserved_78;
uint32_t reserved_7c;
uint32_t reserved_80;
uint32_t reserved_84;
uint32_t reserved_88;
uint32_t reserved_8c;
uint32_t reserved_90;
uint32_t reserved_94;
uint32_t reserved_98;
uint32_t reserved_9c;
/** timer_sel : R/W; bitpos: [1:0]; default: 0;
* This field is used to select one of timers for channel n.
*
* 0: select timer0; 1: select timer1; 2: select timer2; 3: select timer3
*/
uint32_t timer_sel:2;
/** sig_out_en : R/W; bitpos: [2]; default: 0;
* Set this bit to enable signal output on channel n.
*/
uint32_t sig_out_en:1;
/** idle_lv : R/W; bitpos: [3]; default: 0;
* This bit is used to control the output value when channel n is inactive (when
* LEDC_SIG_OUT_EN_CHn is 0).
*/
uint32_t idle_lv:1;
/** para_up : WT; bitpos: [4]; default: 0;
* This bit is used to update LEDC_HPOINT_CHn, LEDC_DUTY_START_CHn,
* LEDC_SIG_OUT_EN_CHn, LEDC_TIMER_SEL_CHn, LEDC_DUTY_NUM_CHn, LEDC_DUTY_CYCLE_CHn,
* LEDC_DUTY_SCALE_CHn, LEDC_DUTY_INC_CHn, and LEDC_OVF_CNT_EN_CHn fields for channel
* n, and will be automatically cleared by hardware.
*/
uint32_t para_up:1;
/** ovf_num : R/W; bitpos: [14:5]; default: 0;
* This register is used to configure 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:10;
/** ovf_cnt_en : R/W; bitpos: [15]; default: 0;
* This bit is used to enable the ovf_cnt of channel n.
*/
uint32_t ovf_cnt_en:1;
/** ovf_cnt_reset : WT; bitpos: [16]; default: 0;
* Set this bit to reset the ovf_cnt of channel n.
*/
uint32_t ovf_cnt_reset:1;
uint32_t reserved_17:15;
};
uint32_t val;
} ledc_chn_conf0_reg_t;
/** Type of chn_conf1 register
* Configuration register 1 for channel n
*/
typedef union {
struct {
struct {
union {
struct {
uint32_t duty_resolution : 4; /*This register is used to control the range of the counter in timer $x.*/
uint32_t clock_divider : 18; /*This register is used to configure the divisor for the divider in timer $x.; ; The least significant eight bits represent the fractional part.*/
uint32_t pause : 1; /*This bit is used to suspend the counter in timer $x.*/
uint32_t rst : 1; /*This bit is used to reset timer $x. The counter will show 0 after reset.*/
uint32_t reserved24 : 1; /*Reserved*/
uint32_t low_speed_update : 1; /*Set this bit to update LEDC_CLK_DIV_TIMER$x and LEDC_TIMER$x_DUTY_RES.*/
uint32_t reserved26 : 6; /*Reserved*/
};
uint32_t val;
} conf;
union {
struct {
uint32_t timer_cnt : 14; /*This register stores the current counter value of timer $x.*/
uint32_t reserved14 : 18; /*Reserved*/
};
uint32_t val;
} value;
} timer[4];
} timer_group[1];
union {
struct {
uint32_t lstimer0_ovf : 1; /*Triggered when the timer$x has reached its maximum counter value.*/
uint32_t lstimer1_ovf : 1; /*Triggered when the timer$x has reached its maximum counter value.*/
uint32_t lstimer2_ovf : 1; /*Triggered when the timer$x has reached its maximum counter value.*/
uint32_t lstimer3_ovf : 1; /*Triggered when the timer$x has reached its maximum counter value.*/
uint32_t duty_chng_end_ch0 : 1; /*Interrupt raw bit for channel $n. Triggered when the gradual change of duty has finished.*/
uint32_t duty_chng_end_ch1 : 1; /*Interrupt raw bit for channel $n. Triggered when the gradual change of duty has finished.*/
uint32_t duty_chng_end_ch2 : 1; /*Interrupt raw bit for channel $n. Triggered when the gradual change of duty has finished.*/
uint32_t duty_chng_end_ch3 : 1; /*Interrupt raw bit for channel $n. Triggered when the gradual change of duty has finished.*/
uint32_t duty_chng_end_ch4 : 1; /*Interrupt raw bit for channel $n. Triggered when the gradual change of duty has finished.*/
uint32_t duty_chng_end_ch5 : 1; /*Interrupt raw bit for channel $n. Triggered when the gradual change of duty has finished.*/
uint32_t ovf_cnt_ch0 : 1; /*Interrupt raw bit for channel $n. Triggered when the ovf_cnt has reached the value specified by LEDC_OVF_NUM_CH$n.*/
uint32_t ovf_cnt_ch1 : 1; /*Interrupt raw bit for channel $n. Triggered when the ovf_cnt has reached the value specified by LEDC_OVF_NUM_CH$n.*/
uint32_t ovf_cnt_ch2 : 1; /*Interrupt raw bit for channel $n. Triggered when the ovf_cnt has reached the value specified by LEDC_OVF_NUM_CH$n.*/
uint32_t ovf_cnt_ch3 : 1; /*Interrupt raw bit for channel $n. Triggered when the ovf_cnt has reached the value specified by LEDC_OVF_NUM_CH$n.*/
uint32_t ovf_cnt_ch4 : 1; /*Interrupt raw bit for channel $n. Triggered when the ovf_cnt has reached the value specified by LEDC_OVF_NUM_CH$n.*/
uint32_t ovf_cnt_ch5 : 1; /*Interrupt raw bit for channel $n. Triggered when the ovf_cnt has reached the value specified by LEDC_OVF_NUM_CH$n.*/
uint32_t reserved16 : 16; /*Reserved*/
};
uint32_t val;
} int_raw;
union {
struct {
uint32_t lstimer0_ovf : 1; /*This is the masked interrupt status bit for the LEDC_TIMER$x_OVF_INT interrupt when LEDC_TIMER$x_OVF_INT_ENA is set to 1.*/
uint32_t lstimer1_ovf : 1; /*This is the masked interrupt status bit for the LEDC_TIMER$x_OVF_INT interrupt when LEDC_TIMER$x_OVF_INT_ENA is set to 1.*/
uint32_t lstimer2_ovf : 1; /*This is the masked interrupt status bit for the LEDC_TIMER$x_OVF_INT interrupt when LEDC_TIMER$x_OVF_INT_ENA is set to 1.*/
uint32_t lstimer3_ovf : 1; /*This is the masked interrupt status bit for the LEDC_TIMER$x_OVF_INT interrupt when LEDC_TIMER$x_OVF_INT_ENA is set to 1.*/
uint32_t duty_chng_end_ch0 : 1; /*This is the masked interrupt status bit for the LEDC_DUTY_CHNG_END_CH$n_INT interrupt when LEDC_DUTY_CHNG_END_CH$n_INT_ENAIS set to 1.*/
uint32_t duty_chng_end_ch1 : 1; /*This is the masked interrupt status bit for the LEDC_DUTY_CHNG_END_CH$n_INT interrupt when LEDC_DUTY_CHNG_END_CH$n_INT_ENAIS set to 1.*/
uint32_t duty_chng_end_ch2 : 1; /*This is the masked interrupt status bit for the LEDC_DUTY_CHNG_END_CH$n_INT interrupt when LEDC_DUTY_CHNG_END_CH$n_INT_ENAIS set to 1.*/
uint32_t duty_chng_end_ch3 : 1; /*This is the masked interrupt status bit for the LEDC_DUTY_CHNG_END_CH$n_INT interrupt when LEDC_DUTY_CHNG_END_CH$n_INT_ENAIS set to 1.*/
uint32_t duty_chng_end_ch4 : 1; /*This is the masked interrupt status bit for the LEDC_DUTY_CHNG_END_CH$n_INT interrupt when LEDC_DUTY_CHNG_END_CH$n_INT_ENAIS set to 1.*/
uint32_t duty_chng_end_ch5 : 1; /*This is the masked interrupt status bit for the LEDC_DUTY_CHNG_END_CH$n_INT interrupt when LEDC_DUTY_CHNG_END_CH$n_INT_ENAIS set to 1.*/
uint32_t ovf_cnt_ch0 : 1; /*This is the masked interrupt status bit for the LEDC_OVF_CNT_CH$n_INT interrupt when LEDC_OVF_CNT_CH$n_INT_ENA is set to 1.*/
uint32_t ovf_cnt_ch1 : 1; /*This is the masked interrupt status bit for the LEDC_OVF_CNT_CH$n_INT interrupt when LEDC_OVF_CNT_CH$n_INT_ENA is set to 1.*/
uint32_t ovf_cnt_ch2 : 1; /*This is the masked interrupt status bit for the LEDC_OVF_CNT_CH$n_INT interrupt when LEDC_OVF_CNT_CH$n_INT_ENA is set to 1.*/
uint32_t ovf_cnt_ch3 : 1; /*This is the masked interrupt status bit for the LEDC_OVF_CNT_CH$n_INT interrupt when LEDC_OVF_CNT_CH$n_INT_ENA is set to 1.*/
uint32_t ovf_cnt_ch4 : 1; /*This is the masked interrupt status bit for the LEDC_OVF_CNT_CH$n_INT interrupt when LEDC_OVF_CNT_CH$n_INT_ENA is set to 1.*/
uint32_t ovf_cnt_ch5 : 1; /*This is the masked interrupt status bit for the LEDC_OVF_CNT_CH$n_INT interrupt when LEDC_OVF_CNT_CH$n_INT_ENA is set to 1.*/
uint32_t reserved16 : 16; /*Reserved*/
};
uint32_t val;
} int_st;
union {
struct {
uint32_t lstimer0_ovf : 1; /*The interrupt enable bit for the LEDC_TIMER$x_OVF_INT interrupt.*/
uint32_t lstimer1_ovf : 1; /*The interrupt enable bit for the LEDC_TIMER$x_OVF_INT interrupt.*/
uint32_t lstimer2_ovf : 1; /*The interrupt enable bit for the LEDC_TIMER$x_OVF_INT interrupt.*/
uint32_t lstimer3_ovf : 1; /*The interrupt enable bit for the LEDC_TIMER$x_OVF_INT interrupt.*/
uint32_t duty_chng_end_ch0 : 1; /*The interrupt enable bit for the LEDC_DUTY_CHNG_END_CH$n_INT interrupt.*/
uint32_t duty_chng_end_ch1 : 1; /*The interrupt enable bit for the LEDC_DUTY_CHNG_END_CH$n_INT interrupt.*/
uint32_t duty_chng_end_ch2 : 1; /*The interrupt enable bit for the LEDC_DUTY_CHNG_END_CH$n_INT interrupt.*/
uint32_t duty_chng_end_ch3 : 1; /*The interrupt enable bit for the LEDC_DUTY_CHNG_END_CH$n_INT interrupt.*/
uint32_t duty_chng_end_ch4 : 1; /*The interrupt enable bit for the LEDC_DUTY_CHNG_END_CH$n_INT interrupt.*/
uint32_t duty_chng_end_ch5 : 1; /*The interrupt enable bit for the LEDC_DUTY_CHNG_END_CH$n_INT interrupt.*/
uint32_t ovf_cnt_ch0 : 1; /*The interrupt enable bit for the LEDC_OVF_CNT_CH$n_INT interrupt.*/
uint32_t ovf_cnt_ch1 : 1; /*The interrupt enable bit for the LEDC_OVF_CNT_CH$n_INT interrupt.*/
uint32_t ovf_cnt_ch2 : 1; /*The interrupt enable bit for the LEDC_OVF_CNT_CH$n_INT interrupt.*/
uint32_t ovf_cnt_ch3 : 1; /*The interrupt enable bit for the LEDC_OVF_CNT_CH$n_INT interrupt.*/
uint32_t ovf_cnt_ch4 : 1; /*The interrupt enable bit for the LEDC_OVF_CNT_CH$n_INT interrupt.*/
uint32_t ovf_cnt_ch5 : 1; /*The interrupt enable bit for the LEDC_OVF_CNT_CH$n_INT interrupt.*/
uint32_t reserved16 : 16; /*Reserved*/
};
uint32_t val;
} int_ena;
union {
struct {
uint32_t lstimer0_ovf : 1; /*Set this bit to clear the LEDC_TIMER$x_OVF_INT interrupt.*/
uint32_t lstimer1_ovf : 1; /*Set this bit to clear the LEDC_TIMER$x_OVF_INT interrupt.*/
uint32_t lstimer2_ovf : 1; /*Set this bit to clear the LEDC_TIMER$x_OVF_INT interrupt.*/
uint32_t lstimer3_ovf : 1; /*Set this bit to clear the LEDC_TIMER$x_OVF_INT interrupt.*/
uint32_t duty_chng_end_ch0 : 1; /*Set this bit to clear the LEDC_DUTY_CHNG_END_CH$n_INT interrupt.*/
uint32_t duty_chng_end_ch1 : 1; /*Set this bit to clear the LEDC_DUTY_CHNG_END_CH$n_INT interrupt.*/
uint32_t duty_chng_end_ch2 : 1; /*Set this bit to clear the LEDC_DUTY_CHNG_END_CH$n_INT interrupt.*/
uint32_t duty_chng_end_ch3 : 1; /*Set this bit to clear the LEDC_DUTY_CHNG_END_CH$n_INT interrupt.*/
uint32_t duty_chng_end_ch4 : 1; /*Set this bit to clear the LEDC_DUTY_CHNG_END_CH$n_INT interrupt.*/
uint32_t duty_chng_end_ch5 : 1; /*Set this bit to clear the LEDC_DUTY_CHNG_END_CH$n_INT interrupt.*/
uint32_t ovf_cnt_ch0 : 1; /*Set this bit to clear the LEDC_OVF_CNT_CH$n_INT interrupt.*/
uint32_t ovf_cnt_ch1 : 1; /*Set this bit to clear the LEDC_OVF_CNT_CH$n_INT interrupt.*/
uint32_t ovf_cnt_ch2 : 1; /*Set this bit to clear the LEDC_OVF_CNT_CH$n_INT interrupt.*/
uint32_t ovf_cnt_ch3 : 1; /*Set this bit to clear the LEDC_OVF_CNT_CH$n_INT interrupt.*/
uint32_t ovf_cnt_ch4 : 1; /*Set this bit to clear the LEDC_OVF_CNT_CH$n_INT interrupt.*/
uint32_t ovf_cnt_ch5 : 1; /*Set this bit to clear the LEDC_OVF_CNT_CH$n_INT interrupt.*/
uint32_t reserved16 : 16; /*Reserved*/
};
uint32_t val;
} int_clr;
union {
struct {
uint32_t apb_clk_sel : 2; /*This bit is used to select clock source for the 4 timers .; ; 2'd1: APB_CLK 2'd2: RTC8M_CLK 2'd3: XTAL_CLK*/
uint32_t reserved2 : 29; /*Reserved*/
uint32_t clk_en : 1; /*This bit is used to control clock.; ; 1'b1: Force clock on for register. 1'h0: Support clock only when application writes registers.*/
};
uint32_t val;
} conf;
uint32_t reserved_d4;
uint32_t reserved_d8;
uint32_t reserved_dc;
uint32_t reserved_e0;
uint32_t reserved_e4;
uint32_t reserved_e8;
uint32_t reserved_ec;
uint32_t reserved_f0;
uint32_t reserved_f4;
uint32_t reserved_f8;
uint32_t date;
/** duty_scale : R/W; bitpos: [9:0]; default: 0;
* This register is used to configure the changing step scale of duty on channel n.
*/
uint32_t duty_scale:10;
/** duty_cycle : R/W; bitpos: [19:10]; default: 0;
* The duty will change every LEDC_DUTY_CYCLE_CHn on channel n.
*/
uint32_t duty_cycle:10;
/** duty_num : R/W; bitpos: [29:20]; default: 0;
* This register is used to control the number of times the duty cycle will be changed.
*/
uint32_t duty_num:10;
/** duty_inc : R/W; bitpos: [30]; default: 1;
* This register is used to increase or decrease the duty of output signal on channel
* n. 1: Increase; 0: Decrease.
*/
uint32_t duty_inc:1;
/** duty_start : R/W/SC; bitpos: [31]; default: 0;
* Other configured fields in LEDC_CHn_CONF1_REG will start to take effect when this
* bit is set to 1.
*/
uint32_t duty_start:1;
};
uint32_t val;
} ledc_chn_conf1_reg_t;
/** Type of conf register
* Global ledc configuration register
*/
typedef union {
struct {
/** apb_clk_sel : R/W; bitpos: [1:0]; default: 0;
* This bit is used to select clock source for the 4 timers .
*
* 2'd1: APB_CLK 2'd2: RTC8M_CLK 2'd3: XTAL_CLK
*/
uint32_t apb_clk_sel:2;
uint32_t reserved_2:29;
/** clk_en : R/W; bitpos: [31]; default: 0;
* This bit is used to control clock.
*
* 1'b1: Force clock on for register. 1'h0: Support clock only when application writes
* registers.
*/
uint32_t clk_en:1;
};
uint32_t val;
} ledc_conf_reg_t;
/** Group: Hpoint Register */
/** Type of chn_hpoint register
* High point register for channel n
*/
typedef union {
struct {
/** hpoint : R/W; bitpos: [13:0]; default: 0;
* The output value changes to high when the selected timers has reached the value
* specified by this register.
*/
uint32_t hpoint:14;
uint32_t reserved_14:18;
};
uint32_t val;
} ledc_chn_hpoint_reg_t;
/** Group: Duty Cycle Register */
/** Type of chn_duty register
* Initial duty cycle for channel n
*/
typedef union {
struct {
/** duty : R/W; bitpos: [18:0]; default: 0;
* This register is used to change the output duty by controlling the Lpoint.
*
* The output value turns to low when the selected timers has reached the Lpoint.
*/
uint32_t duty:19;
uint32_t reserved_19:13;
};
uint32_t val;
} ledc_chn_duty_reg_t;
/** Type of chn_duty_r register
* Current duty cycle for channel n
*/
typedef union {
struct {
/** duty_r : RO; bitpos: [18:0]; default: 0;
* This register stores the current duty of output signal on channel n.
*/
uint32_t duty_r:19;
uint32_t reserved_19:13;
};
uint32_t val;
} ledc_chn_duty_r_reg_t;
/** Group: Timer Register */
/** Type of timerx_conf register
* Timer x configuration
*/
typedef union {
struct {
/** duty_res : R/W; bitpos: [3:0]; default: 0;
* This register is used to control the range of the counter in timer x.
*/
uint32_t duty_res:4;
/** clk_div : R/W; bitpos: [21:4]; default: 0;
* This register is used to configure the divisor for the divider in timer x.
*
* The least significant eight bits represent the fractional part.
*/
uint32_t clk_div:18;
/** pause : R/W; bitpos: [22]; default: 0;
* This bit is used to suspend the counter in timer x.
*/
uint32_t pause:1;
/** rst : R/W; bitpos: [23]; default: 1;
* This bit is used to reset timer x. The counter will show 0 after reset.
*/
uint32_t rst:1;
uint32_t reserved_24:1;
/** para_up : WT; bitpos: [25]; default: 0;
* Set this bit to update LEDC_CLK_DIV_TIMERx and LEDC_TIMERx_DUTY_RES.
*/
uint32_t para_up:1;
uint32_t reserved_26:6;
};
uint32_t val;
} ledc_timerx_conf_reg_t;
/** Type of timerx_value register
* Timer x current counter value
*/
typedef union {
struct {
/** timer_cnt : RO; bitpos: [13:0]; default: 0;
* This register stores the current counter value of timer x.
*/
uint32_t timer_cnt:14;
uint32_t reserved_14:18;
};
uint32_t val;
} ledc_timerx_value_reg_t;
/** Group: Interrupt Register */
/** Type of int_raw register
* Raw interrupt status
*/
typedef union {
struct {
/** timer0_ovf_int_raw : R/WTC/SS; bitpos: [0]; default: 0;
* Triggered when the timer0 has reached its maximum counter value.
*/
uint32_t timer0_ovf_int_raw:1;
/** timer1_ovf_int_raw : R/WTC/SS; bitpos: [1]; default: 0;
* Triggered when the timer1 has reached its maximum counter value.
*/
uint32_t timer1_ovf_int_raw:1;
/** timer2_ovf_int_raw : R/WTC/SS; bitpos: [2]; default: 0;
* Triggered when the timer2 has reached its maximum counter value.
*/
uint32_t timer2_ovf_int_raw:1;
/** timer3_ovf_int_raw : R/WTC/SS; bitpos: [3]; default: 0;
* Triggered when the timer3 has reached its maximum counter value.
*/
uint32_t timer3_ovf_int_raw:1;
/** duty_chng_end_ch0_int_raw : R/WTC/SS; bitpos: [4]; default: 0;
* Interrupt raw bit for channel 0. Triggered when the gradual change of duty has
* finished.
*/
uint32_t duty_chng_end_ch0_int_raw:1;
/** duty_chng_end_ch1_int_raw : R/WTC/SS; bitpos: [5]; default: 0;
* Interrupt raw bit for channel 1. Triggered when the gradual change of duty has
* finished.
*/
uint32_t duty_chng_end_ch1_int_raw:1;
/** duty_chng_end_ch2_int_raw : R/WTC/SS; bitpos: [6]; default: 0;
* Interrupt raw bit for channel 2. Triggered when the gradual change of duty has
* finished.
*/
uint32_t duty_chng_end_ch2_int_raw:1;
/** duty_chng_end_ch3_int_raw : R/WTC/SS; bitpos: [7]; default: 0;
* Interrupt raw bit for channel 3. Triggered when the gradual change of duty has
* finished.
*/
uint32_t duty_chng_end_ch3_int_raw:1;
/** duty_chng_end_ch4_int_raw : R/WTC/SS; bitpos: [8]; default: 0;
* Interrupt raw bit for channel 4. Triggered when the gradual change of duty has
* finished.
*/
uint32_t duty_chng_end_ch4_int_raw:1;
/** duty_chng_end_ch5_int_raw : R/WTC/SS; bitpos: [9]; default: 0;
* Interrupt raw bit for channel 5. Triggered when the gradual change of duty has
* finished.
*/
uint32_t duty_chng_end_ch5_int_raw:1;
/** ovf_cnt_ch0_int_raw : R/WTC/SS; bitpos: [10]; default: 0;
* Interrupt raw bit for channel 0. Triggered when the ovf_cnt has reached the value
* specified by LEDC_OVF_NUM_CH0.
*/
uint32_t ovf_cnt_ch0_int_raw:1;
/** ovf_cnt_ch1_int_raw : R/WTC/SS; bitpos: [11]; default: 0;
* Interrupt raw bit for channel 1. Triggered when the ovf_cnt has reached the value
* specified by LEDC_OVF_NUM_CH1.
*/
uint32_t ovf_cnt_ch1_int_raw:1;
/** ovf_cnt_ch2_int_raw : R/WTC/SS; bitpos: [12]; default: 0;
* Interrupt raw bit for channel 2. Triggered when the ovf_cnt has reached the value
* specified by LEDC_OVF_NUM_CH2.
*/
uint32_t ovf_cnt_ch2_int_raw:1;
/** ovf_cnt_ch3_int_raw : R/WTC/SS; bitpos: [13]; default: 0;
* Interrupt raw bit for channel 3. Triggered when the ovf_cnt has reached the value
* specified by LEDC_OVF_NUM_CH3.
*/
uint32_t ovf_cnt_ch3_int_raw:1;
/** ovf_cnt_ch4_int_raw : R/WTC/SS; bitpos: [14]; default: 0;
* Interrupt raw bit for channel 4. Triggered when the ovf_cnt has reached the value
* specified by LEDC_OVF_NUM_CH4.
*/
uint32_t ovf_cnt_ch4_int_raw:1;
/** ovf_cnt_ch5_int_raw : R/WTC/SS; bitpos: [15]; default: 0;
* Interrupt raw bit for channel 5. Triggered when the ovf_cnt has reached the value
* specified by LEDC_OVF_NUM_CH5.
*/
uint32_t ovf_cnt_ch5_int_raw:1;
uint32_t reserved_16:16;
};
uint32_t val;
} ledc_int_raw_reg_t;
/** Type of int_st register
* Masked interrupt status
*/
typedef union {
struct {
/** timer0_ovf_int_st : RO; bitpos: [0]; default: 0;
* This is the masked interrupt status bit for the LEDC_TIMER0_OVF_INT interrupt when
* LEDC_TIMER0_OVF_INT_ENA is set to 1.
*/
uint32_t timer0_ovf_int_st:1;
/** timer1_ovf_int_st : RO; bitpos: [1]; default: 0;
* This is the masked interrupt status bit for the LEDC_TIMER1_OVF_INT interrupt when
* LEDC_TIMER1_OVF_INT_ENA is set to 1.
*/
uint32_t timer1_ovf_int_st:1;
/** timer2_ovf_int_st : RO; bitpos: [2]; default: 0;
* This is the masked interrupt status bit for the LEDC_TIMER2_OVF_INT interrupt when
* LEDC_TIMER2_OVF_INT_ENA is set to 1.
*/
uint32_t timer2_ovf_int_st:1;
/** timer3_ovf_int_st : RO; bitpos: [3]; default: 0;
* This is the masked interrupt status bit for the LEDC_TIMER3_OVF_INT interrupt when
* LEDC_TIMER3_OVF_INT_ENA is set to 1.
*/
uint32_t timer3_ovf_int_st:1;
/** duty_chng_end_ch0_int_st : RO; bitpos: [4]; default: 0;
* This is the masked interrupt status bit for the LEDC_DUTY_CHNG_END_CH0_INT
* interrupt when LEDC_DUTY_CHNG_END_CH0_INT_ENAIS set to 1.
*/
uint32_t duty_chng_end_ch0_int_st:1;
/** duty_chng_end_ch1_int_st : RO; bitpos: [5]; default: 0;
* This is the masked interrupt status bit for the LEDC_DUTY_CHNG_END_CH1_INT
* interrupt when LEDC_DUTY_CHNG_END_CH1_INT_ENAIS set to 1.
*/
uint32_t duty_chng_end_ch1_int_st:1;
/** duty_chng_end_ch2_int_st : RO; bitpos: [6]; default: 0;
* This is the masked interrupt status bit for the LEDC_DUTY_CHNG_END_CH2_INT
* interrupt when LEDC_DUTY_CHNG_END_CH2_INT_ENAIS set to 1.
*/
uint32_t duty_chng_end_ch2_int_st:1;
/** duty_chng_end_ch3_int_st : RO; bitpos: [7]; default: 0;
* This is the masked interrupt status bit for the LEDC_DUTY_CHNG_END_CH3_INT
* interrupt when LEDC_DUTY_CHNG_END_CH3_INT_ENAIS set to 1.
*/
uint32_t duty_chng_end_ch3_int_st:1;
/** duty_chng_end_ch4_int_st : RO; bitpos: [8]; default: 0;
* This is the masked interrupt status bit for the LEDC_DUTY_CHNG_END_CH4_INT
* interrupt when LEDC_DUTY_CHNG_END_CH4_INT_ENAIS set to 1.
*/
uint32_t duty_chng_end_ch4_int_st:1;
/** duty_chng_end_ch5_int_st : RO; bitpos: [9]; default: 0;
* This is the masked interrupt status bit for the LEDC_DUTY_CHNG_END_CH5_INT
* interrupt when LEDC_DUTY_CHNG_END_CH5_INT_ENAIS set to 1.
*/
uint32_t duty_chng_end_ch5_int_st:1;
/** ovf_cnt_ch0_int_st : RO; bitpos: [10]; default: 0;
* This is the masked interrupt status bit for the LEDC_OVF_CNT_CH0_INT interrupt when
* LEDC_OVF_CNT_CH0_INT_ENA is set to 1.
*/
uint32_t ovf_cnt_ch0_int_st:1;
/** ovf_cnt_ch1_int_st : RO; bitpos: [11]; default: 0;
* This is the masked interrupt status bit for the LEDC_OVF_CNT_CH1_INT interrupt when
* LEDC_OVF_CNT_CH1_INT_ENA is set to 1.
*/
uint32_t ovf_cnt_ch1_int_st:1;
/** ovf_cnt_ch2_int_st : RO; bitpos: [12]; default: 0;
* This is the masked interrupt status bit for the LEDC_OVF_CNT_CH2_INT interrupt when
* LEDC_OVF_CNT_CH2_INT_ENA is set to 1.
*/
uint32_t ovf_cnt_ch2_int_st:1;
/** ovf_cnt_ch3_int_st : RO; bitpos: [13]; default: 0;
* This is the masked interrupt status bit for the LEDC_OVF_CNT_CH3_INT interrupt when
* LEDC_OVF_CNT_CH3_INT_ENA is set to 1.
*/
uint32_t ovf_cnt_ch3_int_st:1;
/** ovf_cnt_ch4_int_st : RO; bitpos: [14]; default: 0;
* This is the masked interrupt status bit for the LEDC_OVF_CNT_CH4_INT interrupt when
* LEDC_OVF_CNT_CH4_INT_ENA is set to 1.
*/
uint32_t ovf_cnt_ch4_int_st:1;
/** ovf_cnt_ch5_int_st : RO; bitpos: [15]; default: 0;
* This is the masked interrupt status bit for the LEDC_OVF_CNT_CH5_INT interrupt when
* LEDC_OVF_CNT_CH5_INT_ENA is set to 1.
*/
uint32_t ovf_cnt_ch5_int_st:1;
uint32_t reserved_16:16;
};
uint32_t val;
} ledc_int_st_reg_t;
/** Type of int_ena register
* Interrupt enable bits
*/
typedef union {
struct {
/** timer0_ovf_int_ena : R/W; bitpos: [0]; default: 0;
* The interrupt enable bit for the LEDC_TIMER0_OVF_INT interrupt.
*/
uint32_t timer0_ovf_int_ena:1;
/** timer1_ovf_int_ena : R/W; bitpos: [1]; default: 0;
* The interrupt enable bit for the LEDC_TIMER1_OVF_INT interrupt.
*/
uint32_t timer1_ovf_int_ena:1;
/** timer2_ovf_int_ena : R/W; bitpos: [2]; default: 0;
* The interrupt enable bit for the LEDC_TIMER2_OVF_INT interrupt.
*/
uint32_t timer2_ovf_int_ena:1;
/** timer3_ovf_int_ena : R/W; bitpos: [3]; default: 0;
* The interrupt enable bit for the LEDC_TIMER3_OVF_INT interrupt.
*/
uint32_t timer3_ovf_int_ena:1;
/** duty_chng_end_ch0_int_ena : R/W; bitpos: [4]; default: 0;
* The interrupt enable bit for the LEDC_DUTY_CHNG_END_CH0_INT interrupt.
*/
uint32_t duty_chng_end_ch0_int_ena:1;
/** duty_chng_end_ch1_int_ena : R/W; bitpos: [5]; default: 0;
* The interrupt enable bit for the LEDC_DUTY_CHNG_END_CH1_INT interrupt.
*/
uint32_t duty_chng_end_ch1_int_ena:1;
/** duty_chng_end_ch2_int_ena : R/W; bitpos: [6]; default: 0;
* The interrupt enable bit for the LEDC_DUTY_CHNG_END_CH2_INT interrupt.
*/
uint32_t duty_chng_end_ch2_int_ena:1;
/** duty_chng_end_ch3_int_ena : R/W; bitpos: [7]; default: 0;
* The interrupt enable bit for the LEDC_DUTY_CHNG_END_CH3_INT interrupt.
*/
uint32_t duty_chng_end_ch3_int_ena:1;
/** duty_chng_end_ch4_int_ena : R/W; bitpos: [8]; default: 0;
* The interrupt enable bit for the LEDC_DUTY_CHNG_END_CH4_INT interrupt.
*/
uint32_t duty_chng_end_ch4_int_ena:1;
/** duty_chng_end_ch5_int_ena : R/W; bitpos: [9]; default: 0;
* The interrupt enable bit for the LEDC_DUTY_CHNG_END_CH5_INT interrupt.
*/
uint32_t duty_chng_end_ch5_int_ena:1;
/** ovf_cnt_ch0_int_ena : R/W; bitpos: [10]; default: 0;
* The interrupt enable bit for the LEDC_OVF_CNT_CH0_INT interrupt.
*/
uint32_t ovf_cnt_ch0_int_ena:1;
/** ovf_cnt_ch1_int_ena : R/W; bitpos: [11]; default: 0;
* The interrupt enable bit for the LEDC_OVF_CNT_CH1_INT interrupt.
*/
uint32_t ovf_cnt_ch1_int_ena:1;
/** ovf_cnt_ch2_int_ena : R/W; bitpos: [12]; default: 0;
* The interrupt enable bit for the LEDC_OVF_CNT_CH2_INT interrupt.
*/
uint32_t ovf_cnt_ch2_int_ena:1;
/** ovf_cnt_ch3_int_ena : R/W; bitpos: [13]; default: 0;
* The interrupt enable bit for the LEDC_OVF_CNT_CH3_INT interrupt.
*/
uint32_t ovf_cnt_ch3_int_ena:1;
/** ovf_cnt_ch4_int_ena : R/W; bitpos: [14]; default: 0;
* The interrupt enable bit for the LEDC_OVF_CNT_CH4_INT interrupt.
*/
uint32_t ovf_cnt_ch4_int_ena:1;
/** ovf_cnt_ch5_int_ena : R/W; bitpos: [15]; default: 0;
* The interrupt enable bit for the LEDC_OVF_CNT_CH5_INT interrupt.
*/
uint32_t ovf_cnt_ch5_int_ena:1;
uint32_t reserved_16:16;
};
uint32_t val;
} ledc_int_ena_reg_t;
/** Type of int_clr register
* Interrupt clear bits
*/
typedef union {
struct {
/** timer0_ovf_int_clr : WT; bitpos: [0]; default: 0;
* Set this bit to clear the LEDC_TIMER0_OVF_INT interrupt.
*/
uint32_t timer0_ovf_int_clr:1;
/** timer1_ovf_int_clr : WT; bitpos: [1]; default: 0;
* Set this bit to clear the LEDC_TIMER1_OVF_INT interrupt.
*/
uint32_t timer1_ovf_int_clr:1;
/** timer2_ovf_int_clr : WT; bitpos: [2]; default: 0;
* Set this bit to clear the LEDC_TIMER2_OVF_INT interrupt.
*/
uint32_t timer2_ovf_int_clr:1;
/** timer3_ovf_int_clr : WT; bitpos: [3]; default: 0;
* Set this bit to clear the LEDC_TIMER3_OVF_INT interrupt.
*/
uint32_t timer3_ovf_int_clr:1;
/** duty_chng_end_ch0_int_clr : WT; bitpos: [4]; default: 0;
* Set this bit to clear the LEDC_DUTY_CHNG_END_CH0_INT interrupt.
*/
uint32_t duty_chng_end_ch0_int_clr:1;
/** duty_chng_end_ch1_int_clr : WT; bitpos: [5]; default: 0;
* Set this bit to clear the LEDC_DUTY_CHNG_END_CH1_INT interrupt.
*/
uint32_t duty_chng_end_ch1_int_clr:1;
/** duty_chng_end_ch2_int_clr : WT; bitpos: [6]; default: 0;
* Set this bit to clear the LEDC_DUTY_CHNG_END_CH2_INT interrupt.
*/
uint32_t duty_chng_end_ch2_int_clr:1;
/** duty_chng_end_ch3_int_clr : WT; bitpos: [7]; default: 0;
* Set this bit to clear the LEDC_DUTY_CHNG_END_CH3_INT interrupt.
*/
uint32_t duty_chng_end_ch3_int_clr:1;
/** duty_chng_end_ch4_int_clr : WT; bitpos: [8]; default: 0;
* Set this bit to clear the LEDC_DUTY_CHNG_END_CH4_INT interrupt.
*/
uint32_t duty_chng_end_ch4_int_clr:1;
/** duty_chng_end_ch5_int_clr : WT; bitpos: [9]; default: 0;
* Set this bit to clear the LEDC_DUTY_CHNG_END_CH5_INT interrupt.
*/
uint32_t duty_chng_end_ch5_int_clr:1;
/** ovf_cnt_ch0_int_clr : WT; bitpos: [10]; default: 0;
* Set this bit to clear the LEDC_OVF_CNT_CH0_INT interrupt.
*/
uint32_t ovf_cnt_ch0_int_clr:1;
/** ovf_cnt_ch1_int_clr : WT; bitpos: [11]; default: 0;
* Set this bit to clear the LEDC_OVF_CNT_CH1_INT interrupt.
*/
uint32_t ovf_cnt_ch1_int_clr:1;
/** ovf_cnt_ch2_int_clr : WT; bitpos: [12]; default: 0;
* Set this bit to clear the LEDC_OVF_CNT_CH2_INT interrupt.
*/
uint32_t ovf_cnt_ch2_int_clr:1;
/** ovf_cnt_ch3_int_clr : WT; bitpos: [13]; default: 0;
* Set this bit to clear the LEDC_OVF_CNT_CH3_INT interrupt.
*/
uint32_t ovf_cnt_ch3_int_clr:1;
/** ovf_cnt_ch4_int_clr : WT; bitpos: [14]; default: 0;
* Set this bit to clear the LEDC_OVF_CNT_CH4_INT interrupt.
*/
uint32_t ovf_cnt_ch4_int_clr:1;
/** ovf_cnt_ch5_int_clr : WT; bitpos: [15]; default: 0;
* Set this bit to clear the LEDC_OVF_CNT_CH5_INT interrupt.
*/
uint32_t ovf_cnt_ch5_int_clr:1;
uint32_t reserved_16:16;
};
uint32_t val;
} ledc_int_clr_reg_t;
/** Group: Version Register */
/** Type of date register
* Version control register
*/
typedef union {
struct {
/** ledc_date : R/W; bitpos: [31:0]; default: 419829504;
* This is the version control register.
*/
uint32_t ledc_date:32;
};
uint32_t val;
} 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;
volatile ledc_chn_conf1_reg_t conf1;
volatile ledc_chn_duty_r_reg_t duty_rd;
} ledc_chn_reg_t;
typedef struct {
volatile ledc_chn_reg_t channel[6];
} ledc_ch_group_reg_t;
typedef struct {
volatile ledc_timerx_conf_reg_t conf;
volatile ledc_timerx_value_reg_t value;
} ledc_timerx_reg_t;
typedef struct {
volatile ledc_timerx_reg_t timer[4];
} ledc_timer_group_reg_t;
typedef struct ledc_dev_t {
volatile ledc_ch_group_reg_t channel_group[1];
uint32_t reserved_078[10];
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;
volatile ledc_conf_reg_t conf;
uint32_t reserved_0d4[10];
volatile ledc_date_reg_t date;
} ledc_dev_t;
extern ledc_dev_t LEDC;
#ifndef __cplusplus
_Static_assert(sizeof(ledc_dev_t) == 0x100, "Invalid size of ledc_dev_t structure");
#endif
#ifdef __cplusplus
}
#endif
#endif /*_SOC_LEDC_STRUCT_H_ */

View File

@ -125,10 +125,11 @@
#define SOC_I2C_SUPPORT_RTC (1)
/*-------------------------- LEDC CAPS ---------------------------------------*/
#define SOC_LEDC_SUPPORT_XTAL_CLOCK (1)
#define SOC_LEDC_CHANNEL_NUM (6)
#define SOC_LEDC_TIMER_BIT_WIDE_NUM (14)
#define SOC_LEDC_SUPPORT_FADE_STOP (1)
#define SOC_LEDC_SUPPORT_PLL_DIV_CLOCK (1)
#define SOC_LEDC_SUPPORT_XTAL_CLOCK (1)
#define SOC_LEDC_CHANNEL_NUM (6)
#define SOC_LEDC_TIMER_BIT_WIDE_NUM (14)
#define SOC_LEDC_SUPPORT_FADE_STOP (1)
/*-------------------------- MPU CAPS ----------------------------------------*/
#define SOC_MPU_CONFIGURABLE_REGIONS_SUPPORTED 0

View File

@ -335,6 +335,10 @@ config SOC_I2S_SUPPORTS_TDM
bool
default y
config SOC_LEDC_SUPPORT_APB_CLOCK
bool
default y
config SOC_LEDC_SUPPORT_XTAL_CLOCK
bool
default y

View File

@ -171,6 +171,7 @@
#define SOC_I2S_SUPPORTS_TDM (1)
/*-------------------------- LEDC CAPS ---------------------------------------*/
#define SOC_LEDC_SUPPORT_APB_CLOCK (1)
#define SOC_LEDC_SUPPORT_XTAL_CLOCK (1)
#define SOC_LEDC_CHANNEL_NUM (6)
#define SOC_LEDC_TIMER_BIT_WIDE_NUM (14)

View File

@ -327,6 +327,10 @@ config SOC_I2S_SUPPORTS_TDM
bool
default y
config SOC_LEDC_SUPPORT_APB_CLOCK
bool
default y
config SOC_LEDC_SUPPORT_XTAL_CLOCK
bool
default y

View File

@ -182,6 +182,7 @@
#define SOC_I2S_SUPPORTS_TDM (1)
/*-------------------------- LEDC CAPS ---------------------------------------*/
#define SOC_LEDC_SUPPORT_APB_CLOCK (1)
#define SOC_LEDC_SUPPORT_XTAL_CLOCK (1)
#define SOC_LEDC_CHANNEL_NUM (6)
#define SOC_LEDC_TIMER_BIT_WIDE_NUM (14)

View File

@ -359,6 +359,10 @@ config SOC_LEDC_HAS_TIMER_SPECIFIC_MUX
bool
default y
config SOC_LEDC_SUPPORT_APB_CLOCK
bool
default y
config SOC_LEDC_SUPPORT_REF_TICK
bool
default y

View File

@ -183,11 +183,12 @@
/*-------------------------- LEDC CAPS ---------------------------------------*/
#define SOC_LEDC_HAS_TIMER_SPECIFIC_MUX (1)
#define SOC_LEDC_SUPPORT_REF_TICK (1)
#define SOC_LEDC_SUPPORT_XTAL_CLOCK (1)
#define SOC_LEDC_CHANNEL_NUM (8)
#define SOC_LEDC_TIMER_BIT_WIDE_NUM (14)
#define SOC_LEDC_SUPPORT_FADE_STOP (1)
#define SOC_LEDC_SUPPORT_APB_CLOCK (1)
#define SOC_LEDC_SUPPORT_REF_TICK (1)
#define SOC_LEDC_SUPPORT_XTAL_CLOCK (1)
#define SOC_LEDC_CHANNEL_NUM (8)
#define SOC_LEDC_TIMER_BIT_WIDE_NUM (14)
#define SOC_LEDC_SUPPORT_FADE_STOP (1)
/*-------------------------- MPU CAPS ----------------------------------------*/
//TODO: correct the caller and remove unsupported lines

View File

@ -23,6 +23,10 @@ config SOC_CPU_HAS_FPU
bool
default y
config SOC_LEDC_SUPPORT_APB_CLOCK
bool
default y
config SOC_LEDC_SUPPORT_XTAL_CLOCK
bool
default y

View File

@ -10,8 +10,9 @@
extern "C" {
#endif
#define SOC_LEDC_SUPPORT_APB_CLOCK (1)
#define SOC_LEDC_SUPPORT_XTAL_CLOCK (1)
#define SOC_LEDC_CHANNEL_NUM 8
#define SOC_LEDC_CHANNEL_NUM (8)
#define SOC_LEDC_TIMER_BIT_WIDE_NUM (14)
#define SOC_LEDC_SUPPORT_FADE_STOP (1)

View File

@ -88,7 +88,6 @@ api-reference/peripherals/adc
api-reference/peripherals/sdspi_host
api-reference/peripherals/lcd
api-reference/peripherals/secure_element
api-reference/peripherals/ledc
api-reference/peripherals/temp_sensor
api-reference/peripherals/spi_slave_hd
api-reference/peripherals/i2c

View File

@ -1,6 +1,6 @@
LED Control (LEDC)
==================
{IDF_TARGET_LEDC_CHAN_NUM:default="8", esp32="16", esp32s2="8", esp32c3="6", esp32s3="8"}
{IDF_TARGET_LEDC_CHAN_NUM:default="8", esp32="16", esp32s2="8", esp32c3="6", esp32s3="8", esp32c2="6", esp32h2="6"}
:link_to_translation:`zh_CN:[中文]`
@ -127,9 +127,57 @@ The source clock can also limit the PWM frequency. The higher the source clock f
- 40 MHz
- Dynamic Frequency Scaling compatible
.. note::
.. only:: esp32c2
For {IDF_TARGET_NAME}, all timers share one clock source. In other words, it is impossible to use different clock sources for different timers.
.. list-table:: Characteristics of {IDF_TARGET_NAME} LEDC source clocks
:widths: 15 15 30
:header-rows: 1
* - Clock name
- Clock freq
- Clock capabilities
* - PLL_60M_CLK
- 60 MHz
- /
* - RTC20M_CLK
- ~20 MHz
- Dynamic Frequency Scaling compatible, Light sleep compatible
* - XTAL_CLK
- 40 MHz
- Dynamic Frequency Scaling compatible
.. only:: esp32h2
.. list-table:: Characteristics of {IDF_TARGET_NAME} LEDC source clocks
:widths: 15 15 30
:header-rows: 1
* - Clock name
- Clock freq
- Clock capabilities
* - APB_CLK
- 96 MHz
- /
* - RTC8M_CLK
- ~8 MHz
- Dynamic Frequency Scaling compatible, Light sleep compatible
* - XTAL_CLK
- 32 MHz
- Dynamic Frequency Scaling compatible
.. note::
.. only:: not esp32h2
1. On {IDF_TARGET_NAME}, if RTCxM_CLK is chosen as the LEDC clock source, an internal calibration will be performed to get the exact frequency of the clock. This ensures the accuracy of output PWM signal frequency.
.. only:: esp32h2
1. On {IDF_TARGET_NAME}, if RTC8M_CLK is chosen as the LEDC clock source, you may see the frequency of output PWM signal is not very accurate. This is because no internal calibration is performed to get the exact frequency of the clock due to hardware limitation, a theoretic frequency value is used.
.. only:: not SOC_LEDC_HAS_TIMER_SPECIFIC_MUX
2. For {IDF_TARGET_NAME}, all timers share one clock source. In other words, it is impossible to use different clock sources for different timers.
.. _ledc-api-configure-channel:

View File

@ -1,6 +1,6 @@
LED PWM 控制器
==============
{IDF_TARGET_LEDC_CHAN_NUM:default="8", esp32="16", esp32s2="8", esp32c3="6", esp32s3="8"}
{IDF_TARGET_LEDC_CHAN_NUM:default="8", esp32="16", esp32s2="8", esp32c3="6", esp32s3="8", esp32c2="6", esp32h2="6"}
:link_to_translation:`en:[English]`
@ -127,9 +127,57 @@ LED PWM 控制器可在无需 CPU 干预的情况下自动改变占空比,实
- 40 MHz
- 支持动态调频DFS功能
.. note::
.. only:: esp32c2
{IDF_TARGET_NAME}的所有定时器共用一个时钟源。因此{IDF_TARGET_NAME}不支持给不同的定时器配置不同的时钟源。
.. list-table:: {IDF_TARGET_NAME} LEDC 时钟源特性
:widths: 10 10 30
:header-rows: 1
* - 时钟名称
- 时钟频率
- 时钟功能
* - PLL_60M_CLK
- 60 MHz
- /
* - RTC20M_CLK
- ~20 MHz
- 支持动态调频DFS功能支持Light-sleep模式
* - XTAL_CLK
- 40 MHz
- 支持动态调频DFS功能
.. only:: esp32h2
.. list-table:: {IDF_TARGET_NAME} LEDC 时钟源特性
:widths: 10 10 30
:header-rows: 1
* - 时钟名称
- 时钟频率
- 时钟功能
* - APB_CLK
- 96 MHz
- /
* - RTC8M_CLK
- ~8 MHz
- 支持动态调频DFS功能支持Light-sleep模式
* - XTAL_CLK
- 32 MHz
- 支持动态调频DFS功能
.. note::
.. only:: not esp32h2
1. 如果 {IDF_TARGET_NAME} 的定时器选用了RTCxM_CLK作为其时钟源驱动会通过内部校准来得知这个时钟源的实际频率。这样确保了输出PWM信号频率的精准性。
.. only:: esp32h2
1. 如果 {IDF_TARGET_NAME} 的定时器选用了RTC8M_CLK作为其时钟源LEDC的输出PWM信号频率可能会与设定值有一定偏差。由于{IDF_TARGET_NAME} 的硬件限制,驱动无法通过内部校准得知这个时钟源的实际频率。因此驱动默认使用其理论频率进行计算。
.. only:: not SOC_LEDC_HAS_TIMER_SPECIFIC_MUX
2. {IDF_TARGET_NAME} 的所有定时器共用一个时钟源。因此 {IDF_TARGET_NAME} 不支持给不同的定时器配置不同的时钟源。
.. _ledc-api-configure-channel:

View File

@ -150,9 +150,9 @@ static IRAM_ATTR esp_err_t _iot_set_fade_with_time(ledc_mode_t speed_mode, ledc_
uint32_t precision = (0x1U << duty_resolution);
if (timer_source_clk == LEDC_APB_CLK) {
freq = ((uint64_t)LEDC_APB_CLK_HZ << 8) / precision / clock_divider;
freq = ((uint64_t)APB_CLK_FREQ << 8) / precision / clock_divider;
} else {
freq = ((uint64_t)LEDC_REF_CLK_HZ << 8) / precision / clock_divider;
freq = ((uint64_t)REF_CLK_FREQ << 8) / precision / clock_divider;
}
if (duty_delta == 0) {

View File

@ -31,7 +31,7 @@ Before project configuration and build, be sure to set the correct chip target u
### Hardware Required
* A development board with with any Espressif SoC (e.g., ESP32-DevKitC, ESP-WROVER-KIT, etc.)
* A development board with any Espressif SoC (e.g., ESP32-DevKitC, ESP-WROVER-KIT, etc.)
* A USB cable for Power supply and programming
* Some jumper wires to connect GPIOs.

View File

@ -9,7 +9,7 @@ To use `HIGH SPEED` mode check if the selected SoC supports this mode.
### Hardware Required
* A development board with ESP32, ESP32-S2, ESP32-C3 or ESP32-S3 SoC (e.g., ESP32-DevKitC, ESP-WROVER-KIT, etc.)
* A development board with any Espressif SoC (e.g., ESP32-DevKitC, ESP-WROVER-KIT, etc.)
* A USB cable for power supply and programming
Connect the GPIO to an oscilloscope to see the generated signal:

View File

@ -2,23 +2,21 @@
(See the README.md file in the upper level 'examples' directory for more information about examples.)
This example shows how to control intensity of LEDs using ESP32's on-board hardware LED PWM Controller module.
This example shows how to control intensity of LEDs using selected SoC's on-board hardware LED PWM Controller module.
## How to use example
### Hardware Required
* A development board with ESP32 SoC (e.g., ESP32-DevKitC, ESP-WROVER-KIT, etc.)
* A development board with any Espressif SoC (e.g., ESP32-DevKitC, ESP-WROVER-KIT, etc.)
* A USB cable for power supply and programming
Connect four LEDs to the following LEDC channels / individual GPIOs:
|ledc channel|GPIO|
|:---:|:---:|
|channel 0|GPIO18|
|channel 1|GPIO19|
|channel 2|GPIO4|
|channel 3|GPIO5|
| | Channel 0 | Channel 1 | Channel 2 | Channel 3 |
| --------------- | --------- | --------- | --------- | --------- |
| ESP32 | GPIO18 | GPIO19 | GPIO4 | GPIO5 |
| All other chips | GPIO8 | GPIO9 | GPIO4 | GPIO5 |
### Configure the project
@ -28,19 +26,13 @@ idf.py menuconfig
### Build and Flash
* [ESP-IDF Getting Started Guide on ESP32](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/get-started/index.html)
* [ESP-IDF Getting Started Guide on ESP32-S2](https://docs.espressif.com/projects/esp-idf/en/latest/esp32s2/get-started/index.html)
* [ESP-IDF Getting Started Guide on ESP32-C3](https://docs.espressif.com/projects/esp-idf/en/latest/esp32c3/get-started/index.html)
Build the project and flash it to the board, then run the monitor tool to view the serial output:
Build the project and flash it to the board, then run monitor tool to view serial output:
```
idf.py -p PORT flash monitor
```
Run `idf.py -p PORT flash monitor` to build, flash and monitor the project.
(To exit the serial monitor, type ``Ctrl-]``.)
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
See the [Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/index.html) for full steps to configure and use ESP-IDF to build projects.
## Example Output

View File

@ -27,11 +27,14 @@
*
* 3. You can also set a target duty directly without fading.
*
* 4. This example uses GPIO18/19/4/5 as LEDC output,
* and it will change the duty repeatedly.
* 4. On ESP32, GPIO18/19/4/5 are used as the LEDC outputs:
* GPIO18/19 are from the high speed channel group
* GPIO4/5 are from the low speed channel group
*
* 5. GPIO18/19 are from high speed channel group.
* GPIO4/5 are from low speed channel group.
* On other targets, GPIO8/9/4/5 are used as the LEDC outputs,
* and they are all from the low speed channel group.
*
* 5. All the LEDC outputs change the duty repeatedly.
*
*/
#if CONFIG_IDF_TARGET_ESP32
@ -45,9 +48,9 @@
#define LEDC_LS_TIMER LEDC_TIMER_1
#define LEDC_LS_MODE LEDC_LOW_SPEED_MODE
#if !CONFIG_IDF_TARGET_ESP32
#define LEDC_LS_CH0_GPIO (18)
#define LEDC_LS_CH0_GPIO (8)
#define LEDC_LS_CH0_CHANNEL LEDC_CHANNEL_0
#define LEDC_LS_CH1_GPIO (19)
#define LEDC_LS_CH1_GPIO (9)
#define LEDC_LS_CH1_CHANNEL LEDC_CHANNEL_1
#endif
#define LEDC_LS_CH2_GPIO (4)

View File

@ -909,7 +909,6 @@ components/hal/include/hal/ds_hal.h
components/hal/include/hal/esp_flash_err.h
components/hal/include/hal/interrupt_controller_hal.h
components/hal/include/hal/interrupt_controller_types.h
components/hal/include/hal/ledc_hal.h
components/hal/include/hal/mcpwm_hal.h
components/hal/include/hal/mcpwm_types.h
components/hal/include/hal/mpu_hal.h