Просмотр исходного кода

feat(ledc): refactor ledc driver

1. add hal and low-level layer for ledc driver
2. support esp32s2beta ledc
chenjianqiang 6 лет назад
Родитель
Сommit
857dec108d

+ 16 - 126
components/driver/include/driver/ledc.h

@@ -1,4 +1,4 @@
-// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
+// Copyright 2015-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.
@@ -12,131 +12,23 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef _DRIVER_LEDC_H_
-#define _DRIVER_LEDC_H_
+#pragma once
+
 #include "esp_err.h"
+#include "esp_intr_alloc.h"
 #include "soc/soc.h"
+#include "hal/ledc_types.h"
 #include "driver/gpio.h"
 #include "driver/periph_ctrl.h"
-#include "esp_intr_alloc.h"
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-#define LEDC_APB_CLK_HZ (APB_CLK_FREQ)
-#define LEDC_REF_CLK_HZ (1*1000000)
-#define LEDC_ERR_DUTY   (0xFFFFFFFF)
-#define LEDC_ERR_VAL    (-1)
-
-typedef enum {
-#ifdef CONFIG_IDF_TARGET_ESP32
-    LEDC_HIGH_SPEED_MODE = 0, /*!< LEDC high speed speed_mode */
-#endif
-    LEDC_LOW_SPEED_MODE,      /*!< LEDC low speed speed_mode */
-    LEDC_SPEED_MODE_MAX,      /*!< LEDC speed limit */
-} ledc_mode_t;
-
-typedef enum {
-    LEDC_INTR_DISABLE = 0,    /*!< Disable LEDC interrupt */
-    LEDC_INTR_FADE_END,       /*!< Enable LEDC interrupt */
-} ledc_intr_type_t;
-
-typedef enum {
-    LEDC_DUTY_DIR_DECREASE = 0,    /*!< LEDC duty decrease direction */
-    LEDC_DUTY_DIR_INCREASE = 1,    /*!< LEDC duty increase direction */
-    LEDC_DUTY_DIR_MAX,
-} ledc_duty_direction_t;
-
-typedef enum  {
-    LEDC_REF_TICK = 0, /*!< LEDC timer clock divided from reference tick (1Mhz) */
-    LEDC_APB_CLK,      /*!< LEDC timer clock divided from APB clock (80Mhz) */
-} ledc_clk_src_t;
-
-typedef enum {
-    LEDC_AUTO_CLK,        /*!< 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_USE_REF_TICK,    /*!< LEDC timer select REF_TICK clock as source clock*/
-    LEDC_USE_APB_CLK,     /*!< LEDC timer select APB clock as source clock*/
-    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*/
-} ledc_clk_cfg_t;
-
-typedef enum {
-    LEDC_TIMER_0 = 0, /*!< LEDC timer 0 */
-    LEDC_TIMER_1,     /*!< LEDC timer 1 */
-    LEDC_TIMER_2,     /*!< LEDC timer 2 */
-    LEDC_TIMER_3,     /*!< LEDC timer 3 */
-    LEDC_TIMER_MAX,
-} ledc_timer_t;
-
-typedef enum {
-    LEDC_CHANNEL_0 = 0, /*!< LEDC channel 0 */
-    LEDC_CHANNEL_1,     /*!< LEDC channel 1 */
-    LEDC_CHANNEL_2,     /*!< LEDC channel 2 */
-    LEDC_CHANNEL_3,     /*!< LEDC channel 3 */
-    LEDC_CHANNEL_4,     /*!< LEDC channel 4 */
-    LEDC_CHANNEL_5,     /*!< LEDC channel 5 */
-    LEDC_CHANNEL_6,     /*!< LEDC channel 6 */
-    LEDC_CHANNEL_7,     /*!< LEDC channel 7 */
-    LEDC_CHANNEL_MAX,
-} ledc_channel_t;
-
-typedef enum {
-    LEDC_TIMER_1_BIT = 1,   /*!< LEDC PWM duty resolution of  1 bits */
-    LEDC_TIMER_2_BIT,       /*!< LEDC PWM duty resolution of  2 bits */
-    LEDC_TIMER_3_BIT,       /*!< LEDC PWM duty resolution of  3 bits */
-    LEDC_TIMER_4_BIT,       /*!< LEDC PWM duty resolution of  4 bits */
-    LEDC_TIMER_5_BIT,       /*!< LEDC PWM duty resolution of  5 bits */
-    LEDC_TIMER_6_BIT,       /*!< LEDC PWM duty resolution of  6 bits */
-    LEDC_TIMER_7_BIT,       /*!< LEDC PWM duty resolution of  7 bits */
-    LEDC_TIMER_8_BIT,       /*!< LEDC PWM duty resolution of  8 bits */
-    LEDC_TIMER_9_BIT,       /*!< LEDC PWM duty resolution of  9 bits */
-    LEDC_TIMER_10_BIT,      /*!< LEDC PWM duty resolution of 10 bits */
-    LEDC_TIMER_11_BIT,      /*!< LEDC PWM duty resolution of 11 bits */
-    LEDC_TIMER_12_BIT,      /*!< LEDC PWM duty resolution of 12 bits */
-    LEDC_TIMER_13_BIT,      /*!< LEDC PWM duty resolution of 13 bits */
-    LEDC_TIMER_14_BIT,      /*!< LEDC PWM duty resolution of 14 bits */
-#ifdef CONFIG_IDF_TARGET_ESP32
-    LEDC_TIMER_15_BIT,      /*!< LEDC PWM duty resolution of 15 bits */
-    LEDC_TIMER_16_BIT,      /*!< LEDC PWM duty resolution of 16 bits */
-    LEDC_TIMER_17_BIT,      /*!< LEDC PWM duty resolution of 17 bits */
-    LEDC_TIMER_18_BIT,      /*!< LEDC PWM duty resolution of 18 bits */
-    LEDC_TIMER_19_BIT,      /*!< LEDC PWM duty resolution of 19 bits */
-    LEDC_TIMER_20_BIT,      /*!< LEDC PWM duty resolution of 20 bits */
-#endif
-    LEDC_TIMER_BIT_MAX,
-} ledc_timer_bit_t;
-
-typedef enum {
-    LEDC_FADE_NO_WAIT = 0,  /*!< LEDC fade function will return immediately */
-    LEDC_FADE_WAIT_DONE,    /*!< LEDC fade function will block until fading to the target duty */
-    LEDC_FADE_MAX,
-} ledc_fade_mode_t;
-
-/**
- * @brief Configuration parameters of LEDC channel for ledc_channel_config function
- */
-typedef struct {
-    int gpio_num;                   /*!< the LEDC output gpio_num, if you want to use gpio16, gpio_num = 16 */
-    ledc_mode_t speed_mode;         /*!< LEDC speed speed_mode, high-speed mode or low-speed mode */
-    ledc_channel_t channel;         /*!< LEDC channel (0 - 7) */
-    ledc_intr_type_t intr_type;     /*!< configure interrupt, Fade interrupt enable  or Fade interrupt disable */
-    ledc_timer_t timer_sel;         /*!< Select the timer source of channel (0 - 3) */
-    uint32_t duty;                  /*!< LEDC channel duty, the range of duty setting is [0, (2**duty_resolution)] */
-    int hpoint;                     /*!< LEDC channel hpoint value, the max value is 0xfffff */
-} ledc_channel_config_t;
-
-/**
- * @brief Configuration parameters of LEDC Timer timer for ledc_timer_config function
- */
-typedef struct {
-    ledc_mode_t speed_mode;                /*!< LEDC speed speed_mode, high-speed mode or low-speed mode */
-    ledc_timer_bit_t duty_resolution;  /*!< LEDC channel duty resolution */
-    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_timer_config_t;
+#define LEDC_APB_CLK_HZ  (APB_CLK_FREQ)
+#define LEDC_REF_CLK_HZ  (REF_CLK_FREQ)
+#define LEDC_ERR_DUTY    (0xFFFFFFFF)
+#define LEDC_ERR_VAL     (-1)
 
 typedef intr_handle_t ledc_isr_handle_t;
 
@@ -293,7 +185,7 @@ uint32_t ledc_get_duty(ledc_mode_t speed_mode, ledc_channel_t channel);
  * @param duty Set the start of the gradient duty, the range of duty setting is [0, (2**duty_resolution)]
  * @param fade_direction Set the direction of the gradient
  * @param step_num Set the number of the gradient
- * @param duty_cyle_num Set how many LEDC tick each time the gradient lasts
+ * @param duty_cycle_num Set how many LEDC tick each time the gradient lasts
  * @param duty_scale Set gradient change amplitude
  *
  * @return
@@ -301,7 +193,7 @@ uint32_t ledc_get_duty(ledc_mode_t speed_mode, ledc_channel_t channel);
  *     - ESP_ERR_INVALID_ARG Parameter error
  */
 esp_err_t ledc_set_fade(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t duty, ledc_duty_direction_t fade_direction,
-                        uint32_t step_num, uint32_t duty_cyle_num, uint32_t duty_scale);
+                        uint32_t step_num, uint32_t duty_cycle_num, uint32_t duty_scale);
 
 /**
  * @brief Register LEDC interrupt handler, the handler is an ISR.
@@ -345,7 +237,7 @@ esp_err_t ledc_timer_set(ledc_mode_t speed_mode, ledc_timer_t timer_sel, uint32_
  *     - ESP_ERR_INVALID_ARG Parameter error
  *     - ESP_OK Success
  */
-esp_err_t ledc_timer_rst(ledc_mode_t speed_mode, uint32_t timer_sel);
+esp_err_t ledc_timer_rst(ledc_mode_t speed_mode, ledc_timer_t timer_sel);
 
 /**
  * @brief Pause LEDC timer counter
@@ -358,7 +250,7 @@ esp_err_t ledc_timer_rst(ledc_mode_t speed_mode, uint32_t timer_sel);
  *     - ESP_OK Success
  *
  */
-esp_err_t ledc_timer_pause(ledc_mode_t speed_mode, uint32_t timer_sel);
+esp_err_t ledc_timer_pause(ledc_mode_t speed_mode, ledc_timer_t timer_sel);
 
 /**
  * @brief Resume LEDC timer
@@ -370,20 +262,20 @@ esp_err_t ledc_timer_pause(ledc_mode_t speed_mode, uint32_t timer_sel);
  *     - ESP_ERR_INVALID_ARG Parameter error
  *     - ESP_OK Success
  */
-esp_err_t ledc_timer_resume(ledc_mode_t speed_mode, uint32_t timer_sel);
+esp_err_t ledc_timer_resume(ledc_mode_t speed_mode, ledc_timer_t timer_sel);
 
 /**
  * @brief Bind LEDC channel with the selected timer
  *
  * @param speed_mode Select the LEDC speed_mode, high-speed mode and low-speed mode
  * @param channel LEDC channel index (0-7), select from ledc_channel_t
- * @param timer_idx LEDC timer index (0-3), select from ledc_timer_t
+ * @param timer_sel LEDC timer index (0-3), select from ledc_timer_t
  *
  * @return
  *     - ESP_ERR_INVALID_ARG Parameter error
  *     - ESP_OK Success
  */
-esp_err_t ledc_bind_channel_timer(ledc_mode_t speed_mode, uint32_t channel, uint32_t timer_idx);
+esp_err_t ledc_bind_channel_timer(ledc_mode_t speed_mode, ledc_channel_t channel, ledc_timer_t timer_sel);
 
 /**
  * @brief Set LEDC fade function.
@@ -516,5 +408,3 @@ esp_err_t ledc_set_fade_step_and_start(ledc_mode_t speed_mode, ledc_channel_t ch
 #ifdef __cplusplus
 }
 #endif
-
-#endif /* _DRIVER_LEDC_H_ */

+ 202 - 200
components/driver/ledc.c

@@ -16,25 +16,25 @@
 #include "freertos/FreeRTOS.h"
 #include "freertos/semphr.h"
 #include "freertos/xtensa_api.h"
+#include "esp_log.h"
 #include "soc/gpio_periph.h"
-#include "driver/ledc.h"
 #include "soc/ledc_periph.h"
 #include "soc/rtc.h"
-#include "esp_log.h"
+#include "hal/ledc_hal.h"
+#include "driver/ledc.h"
 
 static const char* LEDC_TAG = "ledc";
-static portMUX_TYPE ledc_spinlock = portMUX_INITIALIZER_UNLOCKED;
+
 #define LEDC_CHECK(a, str, ret_val) \
     if (!(a)) { \
         ESP_LOGE(LEDC_TAG, "%s(%d): %s", __FUNCTION__, __LINE__, str); \
         return (ret_val); \
     }
-
 #define LEDC_ARG_CHECK(a, param) LEDC_CHECK(a, param " argument is invalid", ESP_ERR_INVALID_ARG)
 
 typedef struct {
-    uint16_t speed_mode;
-    uint16_t direction;
+    ledc_mode_t speed_mode;
+    ledc_duty_direction_t direction;
     uint32_t target_duty;
     int cycle_num;
     int scale;
@@ -46,8 +46,14 @@ typedef struct {
 #endif
 } ledc_fade_t;
 
+typedef struct {
+    ledc_hal_context_t ledc_hal;        /*!< LEDC hal context*/
+} ledc_obj_t;
+
+static ledc_obj_t *p_ledc_obj[LEDC_SPEED_MODE_MAX] = {0};
 static ledc_fade_t *s_ledc_fade_rec[LEDC_SPEED_MODE_MAX][LEDC_CHANNEL_MAX];
 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)
@@ -61,6 +67,8 @@ static ledc_isr_handle_t s_ledc_fade_isr_handle = NULL;
 #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"
+
+static const char *LEDC_NOT_INIT = "LEDC is not initialized";
 static const char *LEDC_FADE_SERVICE_ERR_STR = "LEDC fade service not installed";
 static const char *LEDC_FADE_INIT_ERROR_STR = "LEDC fade channel init error, not enough memory or service not installed";
 
@@ -70,14 +78,14 @@ static uint32_t s_ledc_slow_clk_8M = 0;
 static void ledc_ls_timer_update(ledc_mode_t speed_mode, ledc_timer_t timer_sel)
 {
     if (speed_mode == LEDC_LOW_SPEED_MODE) {
-        LEDC.timer_group[speed_mode].timer[timer_sel].conf.low_speed_update = 1;
+        ledc_hal_ls_timer_update(&(p_ledc_obj[speed_mode]->ledc_hal), timer_sel);
     }
 }
 
-static IRAM_ATTR void ledc_ls_channel_update(ledc_mode_t speed_mode, ledc_channel_t channel_num)
+static IRAM_ATTR void ledc_ls_channel_update(ledc_mode_t speed_mode, ledc_channel_t channel)
 {
     if (speed_mode == LEDC_LOW_SPEED_MODE) {
-        LEDC.channel_group[speed_mode].channel[channel_num].conf0.low_speed_update = 1;
+        ledc_hal_ls_channel_update(&(p_ledc_obj[speed_mode]->ledc_hal), channel);
     }
 }
 
@@ -103,25 +111,30 @@ static bool ledc_slow_clk_calibrate(void)
 #endif
 }
 
-static esp_err_t ledc_enable_intr_type(ledc_mode_t speed_mode, uint32_t channel, ledc_intr_type_t type)
+static uint32_t ledc_get_src_clk_freq(ledc_clk_cfg_t clk_cfg)
 {
-    LEDC_ARG_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "speed_mode");
-    uint32_t value;
-    uint32_t intr_type = type;
-    portENTER_CRITICAL(&ledc_spinlock);
-    value = LEDC.int_ena.val;
-#ifdef CONFIG_IDF_TARGET_ESP32
-    uint8_t int_en_base = LEDC_DUTY_CHNG_END_HSCH0_INT_ENA_S;
-#elif defined CONFIG_IDF_TARGET_ESP32S2BETA
-    uint8_t int_en_base = LEDC_DUTY_CHNG_END_LSCH0_INT_ENA_S;
+    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_REF_TICK) {
+        src_clk_freq = LEDC_REF_CLK_HZ;
+    } else if (clk_cfg == LEDC_USE_RTC8M_CLK) {
+        src_clk_freq = s_ledc_slow_clk_8M;
+#ifdef CONFIG_IDF_TARGET_ESP32S2BETA
+    } else if (clk_cfg == LEDC_USE_XTAL_CLK) {
+        src_clk_freq = rtc_clk_xtal_freq_get() * 1000000;
 #endif
-    if (speed_mode == LEDC_LOW_SPEED_MODE) {
-        int_en_base = LEDC_DUTY_CHNG_END_LSCH0_INT_ENA_S;
     }
-    if (intr_type == LEDC_INTR_FADE_END) {
-        LEDC.int_ena.val = value | BIT(int_en_base + channel);
+    return src_clk_freq;
+}
+
+static esp_err_t ledc_enable_intr_type(ledc_mode_t speed_mode, ledc_channel_t channel, ledc_intr_type_t type)
+{
+    portENTER_CRITICAL(&ledc_spinlock);
+    if (type == LEDC_INTR_FADE_END) {
+        ledc_hal_set_fade_end_intr(&(p_ledc_obj[speed_mode]->ledc_hal), channel, true);
     } else {
-        LEDC.int_ena.val = (value & (~(BIT(int_en_base + channel))));
+        ledc_hal_set_fade_end_intr(&(p_ledc_obj[speed_mode]->ledc_hal), channel, false);
     }
     portEXIT_CRITICAL(&ledc_spinlock);
     return ESP_OK;
@@ -163,117 +176,88 @@ static void _ledc_op_lock_release(ledc_mode_t mode, ledc_channel_t channel)
 static int ledc_get_max_duty(ledc_mode_t speed_mode, ledc_channel_t channel)
 {
     // The arguments are checked before internally calling this function.
-    int timer_sel = LEDC.channel_group[speed_mode].channel[channel].conf0.timer_sel;
-    int max_duty = (1 << (LEDC.timer_group[speed_mode].timer[timer_sel].conf.duty_resolution));
+    uint32_t max_duty;
+    ledc_hal_get_max_duty(&(p_ledc_obj[speed_mode]->ledc_hal), channel, &max_duty);
     return max_duty;
 }
 
-static ledc_clk_cfg_t ledc_timer_get_source_clk(ledc_mode_t speed_mode, ledc_timer_t timer_sel)
-{
-    ledc_clk_cfg_t clk_cfg = LEDC_USE_APB_CLK;
-#ifdef CONFIG_IDF_TARGET_ESP32
-    if (speed_mode == LEDC_LOW_SPEED_MODE && LEDC.conf.slow_clk_sel == 0) {
-        clk_cfg = LEDC_USE_RTC8M_CLK;
-    } else if( LEDC.timer_group[speed_mode].timer[timer_sel].conf.tick_sel == 0) {
-        clk_cfg = LEDC_USE_REF_TICK;
-    }
-#elif defined CONFIG_IDF_TARGET_ESP32S2BETA
-    if (LEDC.conf.apb_clk_sel == 2) {
-        clk_cfg = LEDC_USE_RTC8M_CLK;
-    } else if (LEDC.conf.apb_clk_sel == 1) {
-        if (LEDC.timer_group[speed_mode].timer[timer_sel].conf.tick_sel) {
-            clk_cfg = LEDC_USE_REF_TICK;
-        }
-    }
-#endif
-    return clk_cfg;
-}
-
 esp_err_t ledc_timer_set(ledc_mode_t speed_mode, ledc_timer_t timer_sel, uint32_t clock_divider, uint32_t duty_resolution,
         ledc_clk_src_t clk_src)
 {
     LEDC_ARG_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "speed_mode");
     LEDC_ARG_CHECK(timer_sel < LEDC_TIMER_MAX, "timer_select");
+    LEDC_CHECK(p_ledc_obj[speed_mode] != NULL, LEDC_NOT_INIT, ESP_ERR_INVALID_STATE);
     portENTER_CRITICAL(&ledc_spinlock);
-    LEDC.timer_group[speed_mode].timer[timer_sel].conf.clock_divider = clock_divider;
-#ifdef CONFIG_IDF_TARGET_ESP32
-    LEDC.timer_group[speed_mode].timer[timer_sel].conf.tick_sel = clk_src;
-#elif defined CONFIG_IDF_TARGET_ESP32S2BETA
-    if(clk_src == LEDC_REF_TICK) {
-        //REF_TICK can only be used when APB is selected. 
-        LEDC.timer_group[speed_mode].timer[timer_sel].conf.tick_sel = 1;
-        LEDC.conf.apb_clk_sel = 1;
-    } else {
-        LEDC.timer_group[speed_mode].timer[timer_sel].conf.tick_sel = 0;
-    }
-#endif
-    LEDC.timer_group[speed_mode].timer[timer_sel].conf.duty_resolution = duty_resolution;
+    ledc_hal_set_clock_divider(&(p_ledc_obj[speed_mode]->ledc_hal), timer_sel, clock_divider);
+    ledc_hal_set_clock_source(&(p_ledc_obj[speed_mode]->ledc_hal), timer_sel, clk_src);
+    ledc_hal_set_duty_resolution(&(p_ledc_obj[speed_mode]->ledc_hal), timer_sel, duty_resolution);
     ledc_ls_timer_update(speed_mode, timer_sel);
     portEXIT_CRITICAL(&ledc_spinlock);
     return ESP_OK;
 }
 
-static IRAM_ATTR esp_err_t ledc_duty_config(ledc_mode_t speed_mode, ledc_channel_t channel_num, int hpoint_val, int duty_val,
-    uint32_t duty_direction, uint32_t duty_num, uint32_t duty_cycle, uint32_t duty_scale)
+static IRAM_ATTR esp_err_t ledc_duty_config(ledc_mode_t speed_mode, ledc_channel_t channel, int hpoint_val, int duty_val,
+    ledc_duty_direction_t duty_direction, uint32_t duty_num, uint32_t duty_cycle, uint32_t duty_scale)
 {
     portENTER_CRITICAL(&ledc_spinlock);
     if (hpoint_val >= 0) {
-        LEDC.channel_group[speed_mode].channel[channel_num].hpoint.hpoint = hpoint_val;
+        ledc_hal_set_hpoint(&(p_ledc_obj[speed_mode]->ledc_hal), channel, hpoint_val);
     }
     if (duty_val >= 0) {
-        LEDC.channel_group[speed_mode].channel[channel_num].duty.duty = duty_val;
-    }
-    typeof(LEDC.channel_group[0].channel[0].conf1) channel_cfg;
-    channel_cfg.val =  0;
-    channel_cfg.duty_inc = duty_direction;
-    channel_cfg.duty_num = duty_num;
-    channel_cfg.duty_cycle =  duty_cycle;
-    channel_cfg.duty_scale = duty_scale;
-    LEDC.channel_group[speed_mode].channel[channel_num].conf1.val = channel_cfg.val;
-    ledc_ls_channel_update(speed_mode, channel_num);
+        ledc_hal_set_duty_int_part(&(p_ledc_obj[speed_mode]->ledc_hal), channel, duty_val);
+    }
+    ledc_hal_set_duty_direction(&(p_ledc_obj[speed_mode]->ledc_hal), channel, duty_direction);
+    ledc_hal_set_duty_num(&(p_ledc_obj[speed_mode]->ledc_hal), channel, duty_num);
+    ledc_hal_set_duty_cycle(&(p_ledc_obj[speed_mode]->ledc_hal), channel, duty_cycle);
+    ledc_hal_set_duty_scale(&(p_ledc_obj[speed_mode]->ledc_hal), channel, duty_scale);
+    ledc_ls_channel_update(speed_mode, channel);
     portEXIT_CRITICAL(&ledc_spinlock);
     return ESP_OK;
 }
 
-esp_err_t ledc_bind_channel_timer(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t timer_idx)
+esp_err_t ledc_bind_channel_timer(ledc_mode_t speed_mode, ledc_channel_t channel, ledc_timer_t timer_sel)
 {
     LEDC_ARG_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "speed_mode");
-    LEDC_ARG_CHECK(timer_idx < LEDC_TIMER_MAX, "timer_select");    portENTER_CRITICAL(&ledc_spinlock);
-    LEDC.channel_group[speed_mode].channel[channel].conf0.timer_sel = timer_idx;
+    LEDC_ARG_CHECK(timer_sel < LEDC_TIMER_MAX, "timer_select");
+    LEDC_CHECK(p_ledc_obj[speed_mode] != NULL, LEDC_NOT_INIT, ESP_ERR_INVALID_STATE);
+    portENTER_CRITICAL(&ledc_spinlock);
+    ledc_hal_bind_channel_timer(&(p_ledc_obj[speed_mode]->ledc_hal), channel, timer_sel);
     ledc_ls_channel_update(speed_mode, channel);
     portEXIT_CRITICAL(&ledc_spinlock);
     return ESP_OK;
 }
 
-esp_err_t ledc_timer_rst(ledc_mode_t speed_mode, uint32_t timer_sel)
+esp_err_t ledc_timer_rst(ledc_mode_t speed_mode, ledc_timer_t timer_sel)
 {
     LEDC_ARG_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "speed_mode");
     LEDC_ARG_CHECK(timer_sel < LEDC_TIMER_MAX, "timer_select");
+    LEDC_CHECK(p_ledc_obj[speed_mode] != NULL, LEDC_NOT_INIT, ESP_ERR_INVALID_STATE);
     portENTER_CRITICAL(&ledc_spinlock);
-    LEDC.timer_group[speed_mode].timer[timer_sel].conf.rst = 1;
-    LEDC.timer_group[speed_mode].timer[timer_sel].conf.rst = 0;
+    ledc_hal_timer_rst(&(p_ledc_obj[speed_mode]->ledc_hal), timer_sel);
     ledc_ls_timer_update(speed_mode, timer_sel);
     portEXIT_CRITICAL(&ledc_spinlock);
     return ESP_OK;
 }
 
-esp_err_t ledc_timer_pause(ledc_mode_t speed_mode, uint32_t timer_sel)
+esp_err_t ledc_timer_pause(ledc_mode_t speed_mode, ledc_timer_t timer_sel)
 {
     LEDC_ARG_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "speed_mode");
     LEDC_ARG_CHECK(timer_sel < LEDC_TIMER_MAX, "timer_select");
+    LEDC_CHECK(p_ledc_obj[speed_mode] != NULL, LEDC_NOT_INIT, ESP_ERR_INVALID_STATE);
     portENTER_CRITICAL(&ledc_spinlock);
-    LEDC.timer_group[speed_mode].timer[timer_sel].conf.pause = 1;
+    ledc_hal_timer_pause(&(p_ledc_obj[speed_mode]->ledc_hal), timer_sel);
     ledc_ls_timer_update(speed_mode, timer_sel);
     portEXIT_CRITICAL(&ledc_spinlock);
     return ESP_OK;
 }
 
-esp_err_t ledc_timer_resume(ledc_mode_t speed_mode, uint32_t timer_sel)
+esp_err_t ledc_timer_resume(ledc_mode_t speed_mode, ledc_timer_t timer_sel)
 {
     LEDC_ARG_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "speed_mode");
     LEDC_ARG_CHECK(timer_sel < LEDC_TIMER_MAX, "timer_select");
+    LEDC_CHECK(p_ledc_obj[speed_mode] != NULL, LEDC_NOT_INIT, ESP_ERR_INVALID_STATE);
     portENTER_CRITICAL(&ledc_spinlock);
-    LEDC.timer_group[speed_mode].timer[timer_sel].conf.pause = 0;
+    ledc_hal_timer_resume(&(p_ledc_obj[speed_mode]->ledc_hal), timer_sel);
     ledc_ls_timer_update(speed_mode, timer_sel);
     portEXIT_CRITICAL(&ledc_spinlock);
     return ESP_OK;
@@ -295,7 +279,6 @@ static esp_err_t ledc_set_timer_div(ledc_mode_t speed_mode, ledc_timer_t timer_n
     uint32_t div_param = 0;
     uint32_t precision = ( 0x1 << duty_resolution );
     ledc_clk_src_t timer_clk_src = LEDC_APB_CLK;
-
     // Calculate the divisor
     // User specified source clock(RTC8M_CLK) for low speed channel
     if ((speed_mode == LEDC_LOW_SPEED_MODE) && (clk_cfg == LEDC_USE_RTC8M_CLK)) {
@@ -320,29 +303,19 @@ static esp_err_t ledc_set_timer_div(ledc_mode_t speed_mode, ledc_timer_t timer_n
             }
         // User specified source clock(LEDC_APB_CLK_HZ or LEDC_REF_TICK)
         } else {
-            timer_clk_src = (clk_cfg == LEDC_USE_APB_CLK) ? LEDC_APB_CLK : LEDC_REF_TICK;
-            uint32_t sclk_freq = (clk_cfg == LEDC_USE_APB_CLK) ? LEDC_APB_CLK_HZ : LEDC_REF_CLK_HZ;
-            div_param = ( (uint64_t) sclk_freq << 8 ) / freq_hz / precision;
+            timer_clk_src = (clk_cfg == LEDC_USE_REF_TICK) ? LEDC_REF_TICK : LEDC_APB_CLK;
+            uint32_t src_clk_freq = ledc_get_src_clk_freq(clk_cfg);
+            div_param = ( (uint64_t) src_clk_freq << 8 ) / freq_hz / precision;
         }
     }
     if (div_param < 256 || div_param > LEDC_TIMER_DIV_NUM_MAX) {
         goto error;
     }
-    portENTER_CRITICAL(&ledc_spinlock);
-#ifdef CONFIG_IDF_TARGET_ESP32
-    // 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.
     if (speed_mode == LEDC_LOW_SPEED_MODE) {
-        LEDC.conf.slow_clk_sel = (clk_cfg == LEDC_USE_RTC8M_CLK) ? 0 : 1;
-    }
-#elif defined CONFIG_IDF_TARGET_ESP32S2BETA
-    if (clk_cfg == LEDC_USE_RTC8M_CLK) {
-        LEDC.conf.apb_clk_sel = 2;
-    } else {
-        LEDC.conf.apb_clk_sel = 1;
+        portENTER_CRITICAL(&ledc_spinlock);
+        ledc_hal_set_slow_clk(&(p_ledc_obj[speed_mode]->ledc_hal), clk_cfg);
+        portEXIT_CRITICAL(&ledc_spinlock);
     }
-    //TODO:Support XTAL_CLK
-#endif
-    portEXIT_CRITICAL(&ledc_spinlock);
     //Set the divisor
     ledc_timer_set(speed_mode, timer_num, div_param, duty_resolution, timer_clk_src);
     // reset the timer
@@ -372,6 +345,12 @@ esp_err_t ledc_timer_config(const ledc_timer_config_t* timer_conf)
         ESP_LOGE(LEDC_TAG, "invalid timer #%u", timer_num);
         return ESP_ERR_INVALID_ARG;
     }
+
+    if(p_ledc_obj[speed_mode] == NULL) {
+        p_ledc_obj[speed_mode] = (ledc_obj_t *) heap_caps_calloc(1, sizeof(ledc_obj_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
+        ledc_hal_init(&(p_ledc_obj[speed_mode]->ledc_hal), speed_mode);
+    }
+
     return ledc_set_timer_div(speed_mode, timer_num, timer_conf->clk_cfg, freq_hz, duty_resolution);
 }
 
@@ -402,6 +381,12 @@ esp_err_t ledc_channel_config(const ledc_channel_config_t* ledc_conf)
     LEDC_ARG_CHECK(timer_select < LEDC_TIMER_MAX, "timer_select");
     periph_module_enable(PERIPH_LEDC_MODULE);
     esp_err_t ret = ESP_OK;
+
+    if(p_ledc_obj[speed_mode] == NULL) {
+        p_ledc_obj[speed_mode] = (ledc_obj_t *) heap_caps_calloc(1, sizeof(ledc_obj_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
+        ledc_hal_init(&(p_ledc_obj[speed_mode]->ledc_hal), speed_mode);
+    }
+
     /*set channel parameters*/
     /*   channel parameters decide how the waveform looks like in one period*/
     /*   set channel duty and hpoint value, duty range is (0 ~ ((2 ** duty_resolution) - 1)), max hpoint value is 0xfffff*/
@@ -427,9 +412,10 @@ esp_err_t ledc_update_duty(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_CHECK(p_ledc_obj[speed_mode] != NULL, LEDC_NOT_INIT, ESP_ERR_INVALID_STATE);
     portENTER_CRITICAL(&ledc_spinlock);
-    LEDC.channel_group[speed_mode].channel[channel].conf0.sig_out_en = 1;
-    LEDC.channel_group[speed_mode].channel[channel].conf1.duty_start = 1;
+    ledc_hal_set_sig_out_en(&(p_ledc_obj[speed_mode]->ledc_hal), channel, true);
+    ledc_hal_set_duty_start(&(p_ledc_obj[speed_mode]->ledc_hal), channel, true);
     ledc_ls_channel_update(speed_mode, channel);
     portEXIT_CRITICAL(&ledc_spinlock);
     return ESP_OK;
@@ -439,10 +425,11 @@ esp_err_t ledc_stop(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t idl
 {
     LEDC_ARG_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "speed_mode");
     LEDC_ARG_CHECK(channel < LEDC_CHANNEL_MAX, "channel");
+    LEDC_CHECK(p_ledc_obj[speed_mode] != NULL, LEDC_NOT_INIT, ESP_ERR_INVALID_STATE);
     portENTER_CRITICAL(&ledc_spinlock);
-    LEDC.channel_group[speed_mode].channel[channel].conf0.idle_lv = idle_level & 0x1;
-    LEDC.channel_group[speed_mode].channel[channel].conf0.sig_out_en = 0;
-    LEDC.channel_group[speed_mode].channel[channel].conf1.duty_start = 0;
+    ledc_hal_set_idle_level(&(p_ledc_obj[speed_mode]->ledc_hal), channel, idle_level);
+    ledc_hal_set_sig_out_en(&(p_ledc_obj[speed_mode]->ledc_hal), channel, false);
+    ledc_hal_set_duty_start(&(p_ledc_obj[speed_mode]->ledc_hal), channel, false);
     ledc_ls_channel_update(speed_mode, channel);
     portEXIT_CRITICAL(&ledc_spinlock);
     return ESP_OK;
@@ -457,11 +444,12 @@ esp_err_t ledc_set_fade(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t
     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_CHECK(p_ledc_obj[speed_mode] != NULL, LEDC_NOT_INIT, ESP_ERR_INVALID_STATE);
     _ledc_fade_hw_acquire(speed_mode, channel);
     ledc_duty_config(speed_mode,
                      channel,        //uint32_t chan_num,
                      LEDC_VAL_NO_CHANGE,
-                     duty << 4,      //uint32_t duty_val,the least 4 bits are decimal part
+                     duty,           //uint32_t duty_val,
                      fade_direction, //uint32_t increase,
                      step_num,       //uint32_t duty_num,
                      duty_cyle_num,  //uint32_t duty_cycle,
@@ -476,12 +464,13 @@ 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_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);
     ledc_duty_config(speed_mode,
                      channel,         //uint32_t chan_num,
                      hpoint,          //uint32_t hpoint_val,
-                     duty << 4,       //uint32_t duty_val,the least 4 bits are decimal part
+                     duty,           //uint32_t duty_val,
                      1,               //uint32_t increase,
                      1,               //uint32_t duty_num,
                      1,               //uint32_t duty_cycle,
@@ -495,12 +484,13 @@ esp_err_t ledc_set_duty(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_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);
     ledc_duty_config(speed_mode,
                      channel,         //uint32_t chan_num,
                      LEDC_VAL_NO_CHANGE,
-                     duty << 4,       //uint32_t duty_val,the least 4 bits are decimal part
+                     duty,           //uint32_t duty_val,
                      1,               //uint32_t increase,
                      1,               //uint32_t duty_num,
                      1,               //uint32_t duty_cycle,
@@ -513,7 +503,10 @@ esp_err_t ledc_set_duty(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t
 uint32_t ledc_get_duty(ledc_mode_t speed_mode, ledc_channel_t channel)
 {
     LEDC_ARG_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "speed_mode");
-    uint32_t duty = (LEDC.channel_group[speed_mode].channel[channel].duty_rd.duty_read >> 4);
+    LEDC_ARG_CHECK(channel < LEDC_CHANNEL_MAX, "channel");
+    LEDC_CHECK(p_ledc_obj[speed_mode] != NULL, LEDC_NOT_INIT, ESP_ERR_INVALID_STATE);
+    uint32_t duty = 0;
+    ledc_hal_get_duty(&(p_ledc_obj[speed_mode]->ledc_hal), channel, &duty);
     return duty;
 }
 
@@ -521,110 +514,114 @@ int ledc_get_hpoint(ledc_mode_t speed_mode, ledc_channel_t channel)
 {
     LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "speed_mode argument is invalid", LEDC_ERR_VAL);
     LEDC_CHECK(channel < LEDC_CHANNEL_MAX, "channel argument is invalid", LEDC_ERR_VAL);
-    uint32_t hpoint = LEDC.channel_group[speed_mode].channel[channel].hpoint.hpoint;
+    LEDC_CHECK(p_ledc_obj[speed_mode] != NULL, LEDC_NOT_INIT, ESP_ERR_INVALID_STATE);
+    uint32_t hpoint = 0;
+    ledc_hal_get_hpoint(&(p_ledc_obj[speed_mode]->ledc_hal), channel, &hpoint);
     return hpoint;
 }
 
 esp_err_t ledc_set_freq(ledc_mode_t speed_mode, ledc_timer_t timer_num, uint32_t freq_hz)
 {
     LEDC_ARG_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "speed_mode");
-    esp_err_t ret = ESP_OK;
-    ledc_clk_cfg_t clk_cfg = LEDC_AUTO_CLK;
-    portENTER_CRITICAL(&ledc_spinlock);
-    uint32_t duty_resolution = LEDC.timer_group[speed_mode].timer[timer_num].conf.duty_resolution;
-    ledc_set_timer_div(speed_mode, timer_num, clk_cfg, freq_hz, duty_resolution);
-    portEXIT_CRITICAL(&ledc_spinlock);
-    return ret;
+    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;
+    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);
+    return ledc_set_timer_div(speed_mode, timer_num, clk_cfg, freq_hz, duty_resolution);
 }
 
 uint32_t ledc_get_freq(ledc_mode_t speed_mode, ledc_timer_t timer_num)
 {
     LEDC_ARG_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "speed_mode");
-    uint32_t freq = 0;
+    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);
     portENTER_CRITICAL(&ledc_spinlock);
-    ledc_clk_cfg_t timer_source_clk = ledc_timer_get_source_clk(speed_mode, timer_num);
-    uint32_t duty_resolution = LEDC.timer_group[speed_mode].timer[timer_num].conf.duty_resolution;
-    uint32_t clock_divider = LEDC.timer_group[speed_mode].timer[timer_num].conf.clock_divider;
+    uint32_t clock_divider = 0;
+    uint32_t duty_resolution = 0;
+    ledc_clk_cfg_t clk_cfg = LEDC_USE_APB_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 (timer_source_clk == LEDC_USE_APB_CLK) {
-        freq = ((uint64_t) LEDC_APB_CLK_HZ << 8) / precision / clock_divider;
-    } else if(timer_source_clk == LEDC_USE_RTC8M_CLK) {
-        freq = ((uint64_t) s_ledc_slow_clk_8M << 8) / precision / clock_divider;
-    } else {
-        freq = ((uint64_t) LEDC_REF_CLK_HZ << 8) / precision / clock_divider;
-    }
-    return freq;
+    return ((uint64_t) src_clk_freq << 8) / precision / clock_divider;
 }
 
-static inline void ledc_calc_fade_end_channel(uint32_t *fade_end_status, int *channel, int *speed_mode)
+static inline void ledc_calc_fade_end_channel(uint32_t *fade_end_status, uint32_t *channel)
 {
-    int i = __builtin_ffs((*fade_end_status)) - 1;
+    uint32_t i = __builtin_ffs((*fade_end_status)) - 1;
     (*fade_end_status) &= ~(1 << i);
-    *speed_mode = LEDC_LOW_SPEED_MODE;
     *channel = i;
-#ifdef CONFIG_IDF_TARGET_ESP32
-    if (i < LEDC_CHANNEL_MAX) {
-        *speed_mode = LEDC_HIGH_SPEED_MODE;
-    } else {
-        *channel = i - LEDC_CHANNEL_MAX;
-    }
-#endif
 }
 
 void IRAM_ATTR ledc_fade_isr(void* arg)
 {
     portBASE_TYPE HPTaskAwoken = pdFALSE;
-    uint32_t intr_status = LEDC.int_st.val;  //read LEDC interrupt status.
-    uint32_t fade_end_status = (intr_status >> LEDC_LSTIMER0_OVF_INT_ST_S);
-    int speed_mode;
-    int channel;
-    while (fade_end_status) {
-        ledc_calc_fade_end_channel(&fade_end_status, &channel, &speed_mode);
-        if (s_ledc_fade_rec[speed_mode][channel] == NULL) {
-            //fade object not initialized yet.
-            continue;
-        }
-        uint32_t duty_cur = LEDC.channel_group[speed_mode].channel[channel].duty_rd.duty_read >> LEDC_DUTY_DECIMAL_BIT_NUM;
-        if (duty_cur == s_ledc_fade_rec[speed_mode][channel]->target_duty) {
-            xSemaphoreGiveFromISR(s_ledc_fade_rec[speed_mode][channel]->ledc_fade_sem, &HPTaskAwoken);
-            continue;
-        }
-        uint32_t duty_tar = s_ledc_fade_rec[speed_mode][channel]->target_duty;
-        int scale = s_ledc_fade_rec[speed_mode][channel]->scale;
-        if (scale == 0) {
-            xSemaphoreGiveFromISR(s_ledc_fade_rec[speed_mode][channel]->ledc_fade_sem, &HPTaskAwoken);
-            continue;
-        }
-        int cycle = s_ledc_fade_rec[speed_mode][channel]->cycle_num;
-        int delta = s_ledc_fade_rec[speed_mode][channel]->direction == LEDC_DUTY_DIR_DECREASE ? duty_cur - duty_tar : duty_tar - duty_cur;
-        int step = delta / scale > LEDC_STEP_NUM_MAX ? LEDC_STEP_NUM_MAX : delta / scale;
-        if (delta > scale) {
-            ledc_duty_config(
-                speed_mode,
-                channel,
-                LEDC_VAL_NO_CHANGE,
-                duty_cur << LEDC_DUTY_DECIMAL_BIT_NUM,
-                s_ledc_fade_rec[speed_mode][channel]->direction,
-                step,
-                cycle,
-                scale);
-        } else {
-            ledc_duty_config(
-                speed_mode,
-                channel,
-                LEDC_VAL_NO_CHANGE,
-                duty_tar << LEDC_DUTY_DECIMAL_BIT_NUM,
-                s_ledc_fade_rec[speed_mode][channel]->direction,
-                1,
-                1,
-                0);
+    uint32_t speed_mode = 0;
+    uint32_t channel = 0;
+    uint32_t intr_status = 0;
+
+    for (speed_mode = 0; speed_mode < LEDC_SPEED_MODE_MAX; speed_mode++) {
+        ledc_hal_get_fade_end_intr_status(&(p_ledc_obj[speed_mode]->ledc_hal), &intr_status);
+        while(intr_status) {
+            ledc_calc_fade_end_channel(&intr_status, &channel);
+
+            // clear interrupt
+            portENTER_CRITICAL(&ledc_spinlock);
+            ledc_hal_clear_fade_end_intr_status(&(p_ledc_obj[speed_mode]->ledc_hal), channel);
+            portEXIT_CRITICAL(&ledc_spinlock);
+
+            if (s_ledc_fade_rec[speed_mode][channel] == NULL) {
+                //fade object not initialized yet.
+                continue;
+            }
+
+            uint32_t duty_cur = 0;
+            ledc_hal_get_duty(&(p_ledc_obj[speed_mode]->ledc_hal), channel, &duty_cur);
+            if (duty_cur == s_ledc_fade_rec[speed_mode][channel]->target_duty) {
+                xSemaphoreGiveFromISR(s_ledc_fade_rec[speed_mode][channel]->ledc_fade_sem, &HPTaskAwoken);
+                if (HPTaskAwoken == pdTRUE) {
+                    portYIELD_FROM_ISR();
+                }
+                continue;
+            }
+            uint32_t duty_tar = s_ledc_fade_rec[speed_mode][channel]->target_duty;
+            int scale = s_ledc_fade_rec[speed_mode][channel]->scale;
+            if (scale == 0) {
+                xSemaphoreGiveFromISR(s_ledc_fade_rec[speed_mode][channel]->ledc_fade_sem, &HPTaskAwoken);
+                continue;
+            }
+            int cycle = s_ledc_fade_rec[speed_mode][channel]->cycle_num;
+            int delta = s_ledc_fade_rec[speed_mode][channel]->direction == LEDC_DUTY_DIR_DECREASE ? duty_cur - duty_tar : duty_tar - duty_cur;
+            int step = delta / scale > LEDC_STEP_NUM_MAX ? LEDC_STEP_NUM_MAX : delta / scale;
+            if (delta > scale) {
+                ledc_duty_config(
+                    speed_mode,
+                    channel,
+                    LEDC_VAL_NO_CHANGE,
+                    duty_cur,
+                    s_ledc_fade_rec[speed_mode][channel]->direction,
+                    step,
+                    cycle,
+                    scale);
+            } else {
+                ledc_duty_config(
+                    speed_mode,
+                    channel,
+                    LEDC_VAL_NO_CHANGE,
+                    duty_tar,
+                    s_ledc_fade_rec[speed_mode][channel]->direction,
+                    1,
+                    1,
+                    0);
+            }
+            portENTER_CRITICAL(&ledc_spinlock);
+            ledc_hal_set_duty_start(&(p_ledc_obj[speed_mode]->ledc_hal), channel, true);
+            portEXIT_CRITICAL(&ledc_spinlock);
         }
-        LEDC.channel_group[speed_mode].channel[channel].conf1.duty_start = 1;
-    }
-    LEDC.int_clr.val = intr_status;  //clear LEDC interrupt status.
-    if (HPTaskAwoken == pdTRUE) {
-        portYIELD_FROM_ISR();
     }
 }
 
@@ -653,7 +650,7 @@ static esp_err_t ledc_fade_channel_init_check(ledc_mode_t speed_mode, ledc_chann
     }
     if (s_ledc_fade_rec[speed_mode][channel] == NULL) {
 #if CONFIG_SPIRAM_USE_MALLOC
-        s_ledc_fade_rec[speed_mode][channel] = (ledc_fade_t *) heap_caps_calloc(1, sizeof(ledc_fade_t), MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT);
+        s_ledc_fade_rec[speed_mode][channel] = (ledc_fade_t *) heap_caps_calloc(1, sizeof(ledc_fade_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
         if (!s_ledc_fade_rec[speed_mode][channel]) {
             ledc_fade_channel_deinit(speed_mode, channel);
             return ESP_FAIL;
@@ -681,7 +678,8 @@ static esp_err_t ledc_fade_channel_init_check(ledc_mode_t speed_mode, ledc_chann
 static esp_err_t _ledc_set_fade_with_step(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t target_duty, int scale, int cycle_num)
 {
     portENTER_CRITICAL(&ledc_spinlock);
-    uint32_t duty_cur = LEDC.channel_group[speed_mode].channel[channel].duty_rd.duty_read >> LEDC_DUTY_DECIMAL_BIT_NUM;
+    uint32_t duty_cur = 0;
+    ledc_hal_get_duty(&(p_ledc_obj[speed_mode]->ledc_hal), channel, &duty_cur);
     // When duty == max_duty, meanwhile, if scale == 1 and fade_down == 1, counter would overflow.
     if (duty_cur == ledc_get_max_duty(speed_mode, channel)) {
         duty_cur -= 1;
@@ -707,11 +705,11 @@ static esp_err_t _ledc_set_fade_with_step(ledc_mode_t speed_mode, ledc_channel_t
 
     portEXIT_CRITICAL(&ledc_spinlock);
     if (scale > 0 && step_num > 0) {
-        ledc_duty_config(speed_mode, channel, LEDC_VAL_NO_CHANGE, duty_cur << 4, dir, step_num, cycle_num, scale);
+        ledc_duty_config(speed_mode, channel, LEDC_VAL_NO_CHANGE, duty_cur, dir, step_num, cycle_num, scale);
         ESP_LOGD(LEDC_TAG, "cur duty: %d; target: %d, step: %d, cycle: %d; scale: %d; dir: %d\n",
                 duty_cur, target_duty, step_num, cycle_num, scale, dir);
     } else {
-        ledc_duty_config(speed_mode, channel, LEDC_VAL_NO_CHANGE, target_duty << 4, dir, 0, 1, 0);
+        ledc_duty_config(speed_mode, channel, LEDC_VAL_NO_CHANGE, target_duty, dir, 0, 1, 0);
         ESP_LOGD(LEDC_TAG, "Set to target duty: %d", target_duty);
     }
     return ESP_OK;
@@ -719,9 +717,11 @@ static esp_err_t _ledc_set_fade_with_step(ledc_mode_t speed_mode, ledc_channel_t
 
 static esp_err_t _ledc_set_fade_with_time(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t target_duty, int max_fade_time_ms)
 {
-    int timer_sel = LEDC.channel_group[speed_mode].channel[channel].conf0.timer_sel;
+    ledc_timer_t timer_sel;
+    uint32_t duty_cur = 0;
+    ledc_hal_get_channel_timer(&(p_ledc_obj[speed_mode]->ledc_hal), channel, &timer_sel);
+    ledc_hal_get_duty(&(p_ledc_obj[speed_mode]->ledc_hal), channel, &duty_cur);
     uint32_t freq = ledc_get_freq(speed_mode, timer_sel);
-    uint32_t duty_cur = LEDC.channel_group[speed_mode].channel[channel].duty_rd.duty_read >> LEDC_DUTY_DECIMAL_BIT_NUM;
     uint32_t duty_delta = target_duty > duty_cur ? target_duty - duty_cur : duty_cur - target_duty;
 
     if (duty_delta == 0) {
@@ -755,12 +755,7 @@ static void _ledc_fade_start(ledc_mode_t speed_mode, ledc_channel_t channel, led
 {
     s_ledc_fade_rec[speed_mode][channel]->mode = fade_mode;
     // Clear interrupt status of channel
-#ifdef CONFIG_IDF_TARGET_ESP32
-    int duty_resolution_ch0 = (speed_mode == LEDC_HIGH_SPEED_MODE) ? LEDC_DUTY_CHNG_END_HSCH0_INT_ENA_S : LEDC_DUTY_CHNG_END_LSCH0_INT_ENA_S;
-#elif defined CONFIG_IDF_TARGET_ESP32S2BETA
-    int duty_resolution_ch0 = LEDC_DUTY_CHNG_END_LSCH0_INT_ENA_S;
-#endif
-    LEDC.int_clr.val |= BIT(duty_resolution_ch0 + channel);
+    ledc_hal_clear_fade_end_intr_status(&(p_ledc_obj[speed_mode]->ledc_hal), channel);
     // Enable interrupt for channel
     ledc_enable_intr_type(speed_mode, channel, LEDC_INTR_FADE_END);
     ledc_update_duty(speed_mode, channel);
@@ -774,6 +769,7 @@ esp_err_t ledc_set_fade_with_time(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(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);
 
     _ledc_fade_hw_acquire(speed_mode, channel);
@@ -789,6 +785,7 @@ esp_err_t ledc_set_fade_with_step(ledc_mode_t speed_mode, ledc_channel_t 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(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);
 
     _ledc_fade_hw_acquire(speed_mode, channel);
@@ -800,7 +797,9 @@ esp_err_t ledc_set_fade_with_step(ledc_mode_t speed_mode, ledc_channel_t channel
 esp_err_t ledc_fade_start(ledc_mode_t speed_mode, ledc_channel_t channel, ledc_fade_mode_t fade_mode)
 {
     LEDC_CHECK(s_ledc_fade_rec != NULL, LEDC_FADE_SERVICE_ERR_STR, ESP_ERR_INVALID_STATE);
+    LEDC_ARG_CHECK(channel < LEDC_CHANNEL_MAX, "channel");
     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_fade_hw_acquire(speed_mode, channel);
     _ledc_fade_start(speed_mode, channel, fade_mode);
     _ledc_fade_hw_release(speed_mode, channel);
@@ -840,6 +839,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_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_op_lock_acquire(speed_mode, channel);
     _ledc_fade_hw_acquire(speed_mode, channel);
@@ -855,6 +855,7 @@ esp_err_t ledc_set_fade_time_and_start(ledc_mode_t speed_mode, ledc_channel_t ch
     LEDC_ARG_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "speed_mode");
     LEDC_ARG_CHECK(channel < LEDC_CHANNEL_MAX, "channel");
     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(target_duty <= ledc_get_max_duty(speed_mode, channel), "target_duty");
     _ledc_op_lock_acquire(speed_mode, channel);
@@ -873,6 +874,7 @@ esp_err_t ledc_set_fade_step_and_start(ledc_mode_t speed_mode, ledc_channel_t ch
     LEDC_ARG_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "speed_mode");
     LEDC_ARG_CHECK(channel < LEDC_CHANNEL_MAX, "channel");
     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");

+ 2 - 0
components/soc/CMakeLists.txt

@@ -23,6 +23,8 @@ list(APPEND srcs
     "src/hal/i2s_hal.c"
     "src/hal/sigmadelta_hal.c"
     "src/hal/timer_hal.c"
+    "src/hal/ledc_hal.c"
+    "src/hal/ledc_hal_iram.c"
     )
 
 # TODO: SPI Flash HAL for ESP32S2Beta also

+ 454 - 0
components/soc/esp32/include/hal/ledc_ll.h

@@ -0,0 +1,454 @@
+// 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.
+
+// The LL layer for LEDC register operations.
+// Note that most of the register operations in this layer are non-atomic operations.
+
+#pragma once
+
+#include "hal/ledc_types.h"
+#include "soc/ledc_periph.h"
+
+#define LEDC_LL_GET_HW() &LEDC
+
+/**
+ * @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){
+    hw->conf.slow_clk_sel = slow_clk_sel;
+}
+
+/**
+ * @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){
+    *slow_clk_sel = hw->conf.slow_clk_sel;
+}
+
+/**
+ * @brief Update LEDC low speed timer
+ *
+ * @param hw Beginning address of the peripheral registers
+ * @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
+ * @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.low_speed_update = 1;
+}
+
+/**
+ * @brief Reset LEDC timer
+ *
+ * @param hw Beginning address of the peripheral registers
+ * @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
+ * @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, high-speed mode or low-speed mode
+ * @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, high-speed mode or low-speed mode
+ * @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, high-speed mode or low-speed mode
+ * @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.clock_divider = clock_divider;
+}
+
+/**
+ * @brief Get LEDC timer clock divider
+ *
+ * @param hw Beginning address of the peripheral registers
+ * @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
+ * @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.clock_divider;
+}
+
+/**
+ * @brief Set LEDC timer clock source
+ *
+ * @param hw Beginning address of the peripheral registers
+ * @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
+ * @param timer_sel LEDC timer index (0-3), select from ledc_timer_t
+ * @param clk_src Timer clock source
+ *
+ * @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){
+    hw->timer_group[speed_mode].timer[timer_sel].conf.tick_sel = clk_src;
+}
+
+/**
+ * @brief Get LEDC timer clock source
+ *
+ * @param hw Beginning address of the peripheral registers
+ * @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
+ * @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){
+    *clk_src = hw->timer_group[speed_mode].timer[timer_sel].conf.tick_sel;
+}
+
+/**
+ * @brief Set LEDC duty resolution
+ *
+ * @param hw Beginning address of the peripheral registers
+ * @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
+ * @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_resolution = duty_resolution;
+}
+
+/**
+ * @brief Get LEDC duty resolution
+ *
+ * @param hw Beginning address of the peripheral registers
+ * @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
+ * @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_resolution;
+}
+
+/**
+ * @brief Update channel configure when select low speed mode
+ *
+ * @param hw Beginning address of the peripheral registers
+ * @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
+ * @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.low_speed_update = 1;
+}
+
+/**
+ * @brief Get LEDC max duty
+ *
+ * @param hw Beginning address of the peripheral registers
+ * @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
+ * @param channel_num LEDC channel index (0-7), select from ledc_channel_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_channel_t channel_num, uint32_t *max_duty){
+    int 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));
+}
+
+/**
+ * @brief Set LEDC hpoint value
+ *
+ * @param hw Beginning address of the peripheral registers
+ * @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
+ * @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, high-speed mode or low-speed mode
+ * @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, high-speed mode or low-speed mode
+ * @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.duty = duty_val << 4;
+}
+
+/**
+ * @brief Get LEDC duty value
+ *
+ * @param hw Beginning address of the peripheral registers
+ * @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
+ * @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_rd.duty_read >> 4);
+}
+
+/**
+ * @brief Set LEDC duty change direction
+ *
+ * @param hw Beginning address of the peripheral registers
+ * @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
+ * @param channel_num LEDC channel index (0-7), select from ledc_channel_t
+ * @param duty_direction LEDC duty change direction, increase or decrease
+ *
+ * @return None
+ */
+static inline void ledc_ll_set_duty_direction(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel_num, ledc_duty_direction_t duty_direction){
+    hw->channel_group[speed_mode].channel[channel_num].conf1.duty_inc = duty_direction;
+}
+
+/**
+ * @brief Get LEDC duty change direction
+ *
+ * @param hw Beginning address of the peripheral registers
+ * @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
+ * @param channel_num LEDC channel index (0-7), select from ledc_channel_t
+ * @param duty_direction Pointer to accept the LEDC duty change direction, increase or decrease
+ *
+ * @return None
+ */
+static inline void ledc_ll_get_duty_direction(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel_num, ledc_duty_direction_t *duty_direction){
+    *duty_direction = hw->channel_group[speed_mode].channel[channel_num].conf1.duty_inc;
+}
+
+/**
+ * @brief Set the number of increased or decreased times
+ *
+ * @param hw Beginning address of the peripheral registers
+ * @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
+ * @param channel_num LEDC channel index (0-7), select from ledc_channel_t
+ * @param duty_num The number of increased or decreased times
+ *
+ * @return None
+ */
+static inline void ledc_ll_set_duty_num(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel_num, uint32_t duty_num){
+    hw->channel_group[speed_mode].channel[channel_num].conf1.duty_num = duty_num;
+}
+
+/**
+ * @brief Set the duty cycles of increase or decrease
+ *
+ * @param hw Beginning address of the peripheral registers
+ * @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
+ * @param channel_num LEDC channel index (0-7), select from ledc_channel_t
+ * @param duty_cycle The duty cycles
+ *
+ * @return None
+ */
+static inline void ledc_ll_set_duty_cycle(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel_num, uint32_t duty_cycle){
+    hw->channel_group[speed_mode].channel[channel_num].conf1.duty_cycle = duty_cycle;
+}
+
+/**
+ * @brief Set the step scale of increase or decrease
+ *
+ * @param hw Beginning address of the peripheral registers
+ * @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
+ * @param channel_num LEDC channel index (0-7), select from ledc_channel_t
+ * @param duty_scale The step scale
+ *
+ * @return None
+ */
+static inline void ledc_ll_set_duty_scale(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel_num, uint32_t duty_scale){
+    hw->channel_group[speed_mode].channel[channel_num].conf1.duty_scale = duty_scale;
+}
+
+/**
+ * @brief Set the output enable
+ *
+ * @param hw Beginning address of the peripheral registers
+ * @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
+ * @param channel_num LEDC channel index (0-7), select from ledc_channel_t
+ * @param sig_out_en The output enable status
+ *
+ * @return None
+ */
+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, high-speed mode or low-speed mode
+ * @param channel_num LEDC channel index (0-7), select from ledc_channel_t
+ * @param duty_start The duty start
+ *
+ * @return None
+ */
+static inline void ledc_ll_set_duty_start(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel_num, bool duty_start){
+    hw->channel_group[speed_mode].channel[channel_num].conf1.duty_start = duty_start;
+}
+
+/**
+ * @brief Set output idle level
+ *
+ * @param hw Beginning address of the peripheral registers
+ * @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
+ * @param channel_num LEDC channel index (0-7), select from ledc_channel_t
+ * @param idle_level The output idle level
+ *
+ * @return None
+ */
+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 Set fade end interrupt enable
+ *
+ * @param hw Beginning address of the peripheral registers
+ * @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
+ * @param channel_num LEDC channel index (0-7), select from ledc_channel_t
+ * @param fade_end_intr_en The fade end interrupt enable status
+ *
+ * @return None
+ */
+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 = (speed_mode == LEDC_LOW_SPEED_MODE) ? LEDC_DUTY_CHNG_END_LSCH0_INT_ENA_S : LEDC_DUTY_CHNG_END_HSCH0_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))));
+}
+
+/**
+ * @brief Get fade end interrupt status
+ *
+ * @param hw Beginning address of the peripheral registers
+ * @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
+ * @param channel_num LEDC channel index (0-7), select from ledc_channel_t
+ * @param intr_status The fade end interrupt status
+ *
+ * @return None
+ */
+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 = (speed_mode == LEDC_LOW_SPEED_MODE) ? LEDC_DUTY_CHNG_END_LSCH0_INT_ENA_S : LEDC_DUTY_CHNG_END_HSCH0_INT_ENA_S;
+    *intr_status = (value >> int_en_base) & 0xff;
+}
+
+/**
+ * @brief Clear fade end interrupt status
+ *
+ * @param hw Beginning address of the peripheral registers
+ * @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
+ * @param channel_num LEDC channel index (0-7), select from ledc_channel_t
+ *
+ * @return None
+ */
+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 = (speed_mode == LEDC_LOW_SPEED_MODE) ? LEDC_DUTY_CHNG_END_LSCH0_INT_ENA_S : LEDC_DUTY_CHNG_END_HSCH0_INT_ENA_S;
+    hw->int_clr.val = BIT(int_en_base + channel_num);
+}
+
+/**
+ * @brief Set timer index of the specified channel
+ *
+ * @param hw Beginning address of the peripheral registers
+ * @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
+ * @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, high-speed mode or low-speed mode
+ * @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 = hw->channel_group[speed_mode].channel[channel_num].conf0.timer_sel;
+}

+ 479 - 0
components/soc/esp32s2beta/include/hal/ledc_ll.h

@@ -0,0 +1,479 @@
+// 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.
+
+// The LL layer for LEDC register operations.
+// Note that most of the register operations in this layer are non-atomic operations.
+
+#pragma once
+
+#include "hal/ledc_types.h"
+#include "soc/ledc_periph.h"
+
+#define LEDC_LL_GET_HW() &LEDC
+
+/**
+ * @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 = 0;
+    if (slow_clk_sel == LEDC_SLOW_CLK_APB) {
+        clk_sel_val = 1;
+    } else if (slow_clk_sel == LEDC_SLOW_CLK_RTC8M) {
+        clk_sel_val = 2;
+    } else if (slow_clk_sel == LEDC_SLOW_CLK_XTAL) {
+        clk_sel_val = 3;
+    }
+    hw->conf.apb_clk_sel = clk_sel_val;
+}
+
+/**
+ * @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 = hw->conf.apb_clk_sel;
+    if (clk_sel_val == 1) {
+        *slow_clk_sel = LEDC_SLOW_CLK_APB;
+    } 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;
+    }
+}
+
+/**
+ * @brief Update LEDC low speed timer
+ *
+ * @param hw Beginning address of the peripheral registers
+ * @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
+ * @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.low_speed_update = 1;
+}
+
+/**
+ * @brief Reset LEDC timer
+ *
+ * @param hw Beginning address of the peripheral registers
+ * @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
+ * @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, high-speed mode or low-speed mode
+ * @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, high-speed mode or low-speed mode
+ * @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, high-speed mode or low-speed mode
+ * @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.clock_divider = clock_divider;
+}
+
+/**
+ * @brief Get LEDC timer clock divider
+ *
+ * @param hw Beginning address of the peripheral registers
+ * @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
+ * @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.clock_divider;
+}
+
+/**
+ * @brief Set LEDC timer clock source
+ *
+ * @param hw Beginning address of the peripheral registers
+ * @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
+ * @param timer_sel LEDC timer index (0-3), select from ledc_timer_t
+ * @param clk_src Timer clock source
+ *
+ * @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;
+    }
+}
+
+/**
+ * @brief Get LEDC timer clock source
+ *
+ * @param hw Beginning address of the peripheral registers
+ * @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
+ * @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){
+    if (hw->timer_group[speed_mode].timer[timer_sel].conf.tick_sel == 1) {
+        *clk_src = LEDC_REF_TICK;
+    } else {
+        *clk_src = LEDC_APB_CLK;
+    }
+}
+
+/**
+ * @brief Set LEDC duty resolution
+ *
+ * @param hw Beginning address of the peripheral registers
+ * @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
+ * @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_resolution = duty_resolution;
+}
+
+/**
+ * @brief Get LEDC duty resolution
+ *
+ * @param hw Beginning address of the peripheral registers
+ * @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
+ * @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_resolution;
+}
+
+/**
+ * @brief Update channel configure when select low speed mode
+ *
+ * @param hw Beginning address of the peripheral registers
+ * @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
+ * @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.low_speed_update = 1;
+}
+
+/**
+ * @brief Get LEDC max duty
+ *
+ * @param hw Beginning address of the peripheral registers
+ * @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
+ * @param channel_num LEDC channel index (0-7), select from ledc_channel_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_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));
+}
+
+/**
+ * @brief Set LEDC hpoint value
+ *
+ * @param hw Beginning address of the peripheral registers
+ * @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
+ * @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, high-speed mode or low-speed mode
+ * @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, high-speed mode or low-speed mode
+ * @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.duty = duty_val << 4;
+}
+
+/**
+ * @brief Get LEDC duty value
+ *
+ * @param hw Beginning address of the peripheral registers
+ * @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
+ * @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_rd.duty_read >> 4);
+}
+
+/**
+ * @brief Set LEDC duty change direction
+ *
+ * @param hw Beginning address of the peripheral registers
+ * @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
+ * @param channel_num LEDC channel index (0-7), select from ledc_channel_t
+ * @param duty_direction LEDC duty change direction, increase or decrease
+ *
+ * @return None
+ */
+static inline void ledc_ll_set_duty_direction(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel_num, ledc_duty_direction_t duty_direction){
+    hw->channel_group[speed_mode].channel[channel_num].conf1.duty_inc = duty_direction;
+}
+
+/**
+ * @brief Get LEDC duty change direction
+ *
+ * @param hw Beginning address of the peripheral registers
+ * @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
+ * @param channel_num LEDC channel index (0-7), select from ledc_channel_t
+ * @param duty_direction Pointer to accept the LEDC duty change direction, increase or decrease
+ *
+ * @return None
+ */
+static inline void ledc_ll_get_duty_direction(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel_num, ledc_duty_direction_t *duty_direction){
+    *duty_direction = hw->channel_group[speed_mode].channel[channel_num].conf1.duty_inc;
+}
+
+/**
+ * @brief Set the number of increased or decreased times
+ *
+ * @param hw Beginning address of the peripheral registers
+ * @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
+ * @param channel_num LEDC channel index (0-7), select from ledc_channel_t
+ * @param duty_num The number of increased or decreased times
+ *
+ * @return None
+ */
+static inline void ledc_ll_set_duty_num(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel_num, uint32_t duty_num){
+    hw->channel_group[speed_mode].channel[channel_num].conf1.duty_num = duty_num;
+}
+
+/**
+ * @brief Set the duty cycles of increase or decrease
+ *
+ * @param hw Beginning address of the peripheral registers
+ * @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
+ * @param channel_num LEDC channel index (0-7), select from ledc_channel_t
+ * @param duty_cycle The duty cycles
+ *
+ * @return None
+ */
+static inline void ledc_ll_set_duty_cycle(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel_num, uint32_t duty_cycle){
+    hw->channel_group[speed_mode].channel[channel_num].conf1.duty_cycle = duty_cycle;
+}
+
+/**
+ * @brief Set the step scale of increase or decrease
+ *
+ * @param hw Beginning address of the peripheral registers
+ * @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
+ * @param channel_num LEDC channel index (0-7), select from ledc_channel_t
+ * @param duty_scale The step scale
+ *
+ * @return None
+ */
+static inline void ledc_ll_set_duty_scale(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel_num, uint32_t duty_scale){
+    hw->channel_group[speed_mode].channel[channel_num].conf1.duty_scale = duty_scale;
+}
+
+/**
+ * @brief Set the output enable
+ *
+ * @param hw Beginning address of the peripheral registers
+ * @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
+ * @param channel_num LEDC channel index (0-7), select from ledc_channel_t
+ * @param sig_out_en The output enable status
+ *
+ * @return None
+ */
+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, high-speed mode or low-speed mode
+ * @param channel_num LEDC channel index (0-7), select from ledc_channel_t
+ * @param duty_start The duty start
+ *
+ * @return None
+ */
+static inline void ledc_ll_set_duty_start(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel_num, bool duty_start){
+    hw->channel_group[speed_mode].channel[channel_num].conf1.duty_start = duty_start;
+}
+
+/**
+ * @brief Set output idle level
+ *
+ * @param hw Beginning address of the peripheral registers
+ * @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
+ * @param channel_num LEDC channel index (0-7), select from ledc_channel_t
+ * @param idle_level The output idle level
+ *
+ * @return None
+ */
+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 Set fade end interrupt enable
+ *
+ * @param hw Beginning address of the peripheral registers
+ * @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
+ * @param channel_num LEDC channel index (0-7), select from ledc_channel_t
+ * @param fade_end_intr_en The fade end interrupt enable status
+ *
+ * @return None
+ */
+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;
+    hw->int_ena.val = fade_end_intr_en ? (value | BIT(int_en_base + channel_num)) : (value & (~(BIT(int_en_base + channel_num))));
+}
+
+/**
+ * @brief Get fade end interrupt status
+ *
+ * @param hw Beginning address of the peripheral registers
+ * @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
+ * @param channel_num LEDC channel index (0-7), select from ledc_channel_t
+ * @param intr_status The fade end interrupt status
+ *
+ * @return None
+ */
+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;
+    *intr_status = (value >> int_en_base) & 0xff;
+}
+
+/**
+ * @brief Clear fade end interrupt status
+ *
+ * @param hw Beginning address of the peripheral registers
+ * @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
+ * @param channel_num LEDC channel index (0-7), select from ledc_channel_t
+ *
+ * @return None
+ */
+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;
+    hw->int_clr.val = BIT(int_en_base + channel_num);
+}
+
+/**
+ * @brief Set timer index of the specified channel
+ *
+ * @param hw Beginning address of the peripheral registers
+ * @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
+ * @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, high-speed mode or low-speed mode
+ * @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 = hw->channel_group[speed_mode].channel[channel_num].conf0.timer_sel;
+}

+ 1 - 1
components/soc/esp32s2beta/include/soc/ledc_struct.h

@@ -198,7 +198,7 @@ typedef volatile struct {
     } int_clr;
     union {
         struct {
-            uint32_t apb_clk_sel: 2;
+            uint32_t apb_clk_sel: 2; // 0:invalid; 1:80MHz APB clock; 2:8MHz RTC clock; 3:XTAL clock
             uint32_t reserved2:  30;
         };
         uint32_t val;

+ 388 - 0
components/soc/include/hal/ledc_hal.h

@@ -0,0 +1,388 @@
+// 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.
+
+/*******************************************************************************
+ * NOTICE
+ * The hal is not public api, don't use in application code.
+ * See readme.md in soc/include/hal/readme.md
+ ******************************************************************************/
+
+// The HAL layer for LEDC.
+// There is no parameter check in the hal layer, so the caller must ensure the correctness of the parameters.
+
+#pragma once
+
+#include "hal/ledc_ll.h"
+#include "hal/ledc_types.h"
+
+/**
+ * Context that should be maintained by both the driver and the HAL
+ */
+typedef struct {
+    ledc_dev_t *dev;
+    ledc_mode_t speed_mode;
+} ledc_hal_context_t;
+
+/**
+ * @brief Set LEDC low speed timer clock
+ *
+ * @param hal Context of the HAL layer
+ * @param slow_clk_sel LEDC low speed timer clock source
+ *
+ * @return None
+ */
+#define ledc_hal_set_slow_clk_sel(hal, slow_clk_sel)  ledc_ll_set_slow_clk_sel((hal)->dev, slow_clk_sel)
+
+/**
+ * @brief Get LEDC low speed timer clock
+ *
+ * @param hal Context of the HAL layer
+ * @param slow_clk_sel LEDC low speed timer clock source
+ *
+ * @return None
+ */
+#define ledc_hal_get_slow_clk_sel(hal, slow_clk_sel)  ledc_ll_get_slow_clk_sel((hal)->dev, slow_clk_sel)
+
+/**
+ * @brief Update LEDC low speed timer
+ *
+ * @param hal Context of the HAL layer
+ * @param timer_sel LEDC timer index (0-3), select from ledc_timer_t
+ *
+ * @return None
+ */
+#define ledc_hal_ls_timer_update(hal, timer_sel)  ledc_ll_ls_timer_update((hal)->dev, (hal)->speed_mode, timer_sel)
+
+/**
+ * @brief Reset LEDC timer
+ *
+ * @param hal Context of the HAL layer
+ * @param timer_sel LEDC timer index (0-3), select from ledc_timer_t
+ *
+ * @return None
+ */
+#define ledc_hal_timer_rst(hal, timer_sel)  ledc_ll_timer_rst((hal)->dev, (hal)->speed_mode, timer_sel)
+
+/**
+ * @brief Pause LEDC timer
+ *
+ * @param hal Context of the HAL layer
+ * @param timer_sel LEDC timer index (0-3), select from ledc_timer_t
+ *
+ * @return None
+ */
+#define ledc_hal_timer_pause(hal, timer_sel)  ledc_ll_timer_pause((hal)->dev, (hal)->speed_mode, timer_sel)
+
+/**
+ * @brief Resume LEDC timer
+ *
+ * @param hal Context of the HAL layer
+ * @param timer_sel LEDC timer index (0-3), select from ledc_timer_t
+ *
+ * @return None
+ */
+#define ledc_hal_timer_resume(hal, timer_sel)  ledc_ll_timer_resume((hal)->dev, (hal)->speed_mode, timer_sel)
+
+/**
+ * @brief Set LEDC timer clock divider
+ *
+ * @param hal Context of the HAL layer
+ * @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
+ */
+#define ledc_hal_set_clock_divider(hal, timer_sel, clock_divider)  ledc_ll_set_clock_divider((hal)->dev, (hal)->speed_mode, timer_sel, clock_divider)
+
+/**
+ * @brief Get LEDC timer clock divider
+ *
+ * @param hal Context of the HAL layer
+ * @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
+ */
+#define ledc_hal_get_clock_divider(hal, timer_sel, clock_divider)  ledc_ll_get_clock_divider((hal)->dev, (hal)->speed_mode, timer_sel, clock_divider)
+
+/**
+ * @brief Set LEDC timer clock source
+ *
+ * @param hal Context of the HAL layer
+ * @param timer_sel LEDC timer index (0-3), select from ledc_timer_t
+ * @param clk_src Timer clock source
+ *
+ * @return None
+ */
+#define ledc_hal_set_clock_source(hal, timer_sel, clk_src)  ledc_ll_set_clock_source((hal)->dev, (hal)->speed_mode, timer_sel, clk_src)
+
+/**
+ * @brief Get LEDC timer clock source
+ *
+ * @param hal Context of the HAL layer
+ * @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
+ */
+#define ledc_hal_get_clock_source(hal, timer_sel, clk_src)  ledc_ll_get_clock_source((hal)->dev, (hal)->speed_mode, timer_sel, clk_src)
+
+/**
+ * @brief Set LEDC duty resolution
+ *
+ * @param hal Context of the HAL layer
+ * @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
+ */
+#define ledc_hal_set_duty_resolution(hal, timer_sel, duty_resolution)  ledc_ll_set_duty_resolution((hal)->dev, (hal)->speed_mode, timer_sel, duty_resolution)
+
+/**
+ * @brief Get LEDC duty resolution
+ *
+ * @param hal Context of the HAL layer
+ * @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
+ */
+#define ledc_hal_get_duty_resolution(hal, timer_sel, duty_resolution)  ledc_ll_get_duty_resolution((hal)->dev, (hal)->speed_mode, timer_sel, duty_resolution)
+
+/**
+ * @brief Get LEDC max duty
+ *
+ * @param hal Context of the HAL layer
+ * @param channel_num LEDC channel index (0-7), select from ledc_channel_t
+ * @param max_duty Pointer to accept the max duty
+ *
+ * @return None
+ */
+#define ledc_hal_get_max_duty(hal, channel_num, max_duty)  ledc_ll_get_max_duty((hal)->dev, (hal)->speed_mode, channel_num, max_duty)
+
+/**
+ * @brief Get LEDC hpoint value
+ *
+ * @param hal Context of the HAL layer
+ * @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
+ */
+#define ledc_hal_get_hpoint(hal, channel_num, hpoint_val)  ledc_ll_get_hpoint((hal)->dev, (hal)->speed_mode, channel_num, hpoint_val)
+
+/**
+ * @brief Set LEDC the integer part of duty value
+ *
+ * @param hal Context of the HAL layer
+ * @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
+ */
+#define ledc_hal_set_duty_int_part(hal, channel_num, duty_val)  ledc_ll_set_duty_int_part((hal)->dev, (hal)->speed_mode, channel_num, duty_val)
+
+/**
+ * @brief Set the output enable
+ *
+ * @param hal Context of the HAL layer
+ * @param channel_num LEDC channel index (0-7), select from ledc_channel_t
+ * @param sig_out_en The output enable status
+ *
+ * @return None
+ */
+#define ledc_hal_set_sig_out_en(hal, channel_num, sig_out_en)  ledc_ll_set_sig_out_en((hal)->dev, (hal)->speed_mode, channel_num, sig_out_en)
+
+/**
+ * @brief Set the duty start
+ *
+ * @param hal Context of the HAL layer
+ * @param channel_num LEDC channel index (0-7), select from ledc_channel_t
+ * @param duty_start The duty start
+ *
+ * @return None
+ */
+#define ledc_hal_set_duty_start(hal, channel_num, duty_start)  ledc_ll_set_duty_start((hal)->dev, (hal)->speed_mode, channel_num, duty_start)
+
+/**
+ * @brief Set output idle level
+ *
+ * @param hal Context of the HAL layer
+ * @param channel_num LEDC channel index (0-7), select from ledc_channel_t
+ * @param idle_level The output idle level
+ *
+ * @return None
+ */
+#define ledc_hal_set_idle_level(hal, channel_num, idle_level)  ledc_ll_set_idle_level((hal)->dev, (hal)->speed_mode, channel_num, idle_level)
+
+/**
+ * @brief Set fade end interrupt enable
+ *
+ * @param hal Context of the HAL layer
+ * @param channel_num LEDC channel index (0-7), select from ledc_channel_t
+ * @param fade_end_intr_en The fade end interrupt enable status
+ *
+ * @return None
+ */
+#define ledc_hal_set_fade_end_intr(hal, channel_num, fade_end_intr_en)  ledc_ll_set_fade_end_intr((hal)->dev, (hal)->speed_mode, channel_num, fade_end_intr_en)
+
+/**
+ * @brief Set timer index of the specified channel
+ *
+ * @param hal Context of the HAL layer
+ * @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
+ */
+#define ledc_hal_bind_channel_timer(hal, channel_num, timer_sel)  ledc_ll_bind_channel_timer((hal)->dev, (hal)->speed_mode, channel_num, timer_sel)
+
+/**
+ * @brief Get timer index of the specified channel
+ *
+ * @param hal Context of the HAL layer
+ * @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
+ */
+#define ledc_hal_get_channel_timer(hal, channel_num, timer_sel)  ledc_ll_get_channel_timer((hal)->dev, (hal)->speed_mode, channel_num, timer_sel)
+
+/**
+ * @brief Init the LEDC hal. This function should be called first before other hal layer function is called
+ *
+ * @param hal Context of the HAL layer
+ * @param speed_mode speed_mode Select the LEDC speed_mode, high-speed mode and low-speed mod
+ *
+ * @return None
+ */
+void ledc_hal_init(ledc_hal_context_t *hal, ledc_mode_t speed_mode);
+
+/**
+ * @brief Update channel configure when select low speed mode
+ *
+ * @param hal Context of the HAL layer
+ * @param channel_num LEDC channel index (0-7), select from ledc_channel_t
+ *
+ * @return None
+ */
+void ledc_hal_ls_channel_update(ledc_hal_context_t *hal, ledc_channel_t channel_num);
+
+/**
+ * @brief Set LEDC hpoint value
+ *
+ * @param hal Context of the HAL layer
+ * @param channel_num LEDC channel index (0-7), select from ledc_channel_t
+ * @param hpoint_val LEDC hpoint value(max: 0xfffff)
+ *
+ * @return None
+ */
+void ledc_hal_set_hpoint(ledc_hal_context_t *hal, ledc_channel_t channel_num, uint32_t hpoint_val);
+
+/**
+ * @brief Get LEDC duty value
+ *
+ * @param hal Context of the HAL layer
+ * @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
+ */
+void ledc_hal_get_duty(ledc_hal_context_t *hal, ledc_channel_t channel_num, uint32_t *duty_val);
+
+/**
+ * @brief Set LEDC duty change direction
+ *
+ * @param hal Context of the HAL layer
+ * @param channel_num LEDC channel index (0-7), select from ledc_channel_t
+ * @param duty_direction LEDC duty change direction, increase or decrease
+ *
+ * @return None
+ */
+void ledc_hal_set_duty_direction(ledc_hal_context_t *hal, ledc_channel_t channel_num, ledc_duty_direction_t duty_direction);
+
+/**
+ * @brief Set the number of increased or decreased times
+ *
+ * @param hal Context of the HAL layer
+ * @param channel_num LEDC channel index (0-7), select from ledc_channel_t
+ * @param duty_num The number of increased or decreased times
+ *
+ * @return None
+ */
+void ledc_hal_set_duty_num(ledc_hal_context_t *hal, ledc_channel_t channel_num, uint32_t duty_num);
+
+/**
+ * @brief Set the duty cycles of increase or decrease
+ *
+ * @param hal Context of the HAL layer
+ * @param channel_num LEDC channel index (0-7), select from ledc_channel_t
+ * @param duty_cycle The duty cycles
+ *
+ * @return None
+ */
+void ledc_hal_set_duty_cycle(ledc_hal_context_t *hal, ledc_channel_t channel_num, uint32_t duty_cycle);
+
+/**
+ * @brief Set the step scale of increase or decrease
+ *
+ * @param hal Context of the HAL layer
+ * @param channel_num LEDC channel index (0-7), select from ledc_channel_t
+ * @param duty_scale The step scale
+ *
+ * @return None
+ */
+void ledc_hal_set_duty_scale(ledc_hal_context_t *hal, ledc_channel_t channel_num, uint32_t duty_scale);
+
+/**
+ * @brief Get interrupt status of the specified channel
+ *
+ * @param hal Context of the HAL layer
+ * @param channel_num LEDC channel index (0-7), select from ledc_channel_t
+ * @param intr_status Pointer to accept the interrupt status
+ *
+ * @return None
+ */
+void ledc_hal_get_fade_end_intr_status(ledc_hal_context_t *hal, uint32_t *intr_status);
+
+/**
+ * @brief Clear interrupt status of the specified channel
+ *
+ * @param hal Context of the HAL layer
+ * @param channel_num LEDC channel index (0-7), select from ledc_channel_t
+ *
+ * @return None
+ */
+void ledc_hal_clear_fade_end_intr_status(ledc_hal_context_t *hal, ledc_channel_t channel_num);
+
+/**
+ * @brief Get clock config of LEDC timer
+ *
+ * @param hal Context of the HAL layer
+ * @param timer_sel LEDC timer index (0-3), select from ledc_timer_t
+ * @param clk_cfg Pointer to accept clock config
+ *
+ * @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);

+ 148 - 0
components/soc/include/hal/ledc_types.h

@@ -0,0 +1,148 @@
+// 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.
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+#include <stdbool.h>
+
+typedef enum {
+#ifdef CONFIG_IDF_TARGET_ESP32
+    LEDC_HIGH_SPEED_MODE = 0, /*!< LEDC high speed speed_mode */
+#endif
+    LEDC_LOW_SPEED_MODE,      /*!< LEDC low speed speed_mode */
+    LEDC_SPEED_MODE_MAX,      /*!< LEDC speed limit */
+} ledc_mode_t;
+
+typedef enum {
+    LEDC_INTR_DISABLE = 0,    /*!< Disable LEDC interrupt */
+    LEDC_INTR_FADE_END,       /*!< Enable LEDC interrupt */
+    LEDC_INTR_MAX,
+} ledc_intr_type_t;
+
+typedef enum {
+    LEDC_DUTY_DIR_DECREASE = 0,    /*!< LEDC duty decrease direction */
+    LEDC_DUTY_DIR_INCREASE = 1,    /*!< LEDC duty increase direction */
+    LEDC_DUTY_DIR_MAX,
+} ledc_duty_direction_t;
+
+typedef enum  {
+    LEDC_REF_TICK = 0, /*!< LEDC timer clock divided from reference tick (1Mhz) */
+    LEDC_APB_CLK,      /*!< LEDC timer clock divided from APB clock (80Mhz) */
+} ledc_clk_src_t;
+
+typedef enum {
+    LEDC_SLOW_CLK_RTC8M = 0,  /*!< LEDC low speed timer clock source is 8MHz RTC clock*/
+    LEDC_SLOW_CLK_APB,     /*!< LEDC low speed timer clock source is 80MHz APB clock*/
+#ifdef CONFIG_IDF_TARGET_ESP32S2BETA
+    LEDC_SLOW_CLK_XTAL,    /*!< LEDC low speed timer clock source XTAL clock*/
+#endif
+} ledc_slow_clk_sel_t;
+
+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_USE_REF_TICK,    /*!< LEDC timer select REF_TICK clock as source clock*/
+    LEDC_USE_APB_CLK,     /*!< LEDC timer select APB clock as source clock*/
+    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*/
+#ifdef CONFIG_IDF_TARGET_ESP32S2BETA
+    LEDC_USE_XTAL_CLK,    /*!< LEDC timer select XTAL clock as source clock*/
+#endif
+} ledc_clk_cfg_t;
+
+typedef enum {
+    LEDC_TIMER_0 = 0, /*!< LEDC timer 0 */
+    LEDC_TIMER_1,     /*!< LEDC timer 1 */
+    LEDC_TIMER_2,     /*!< LEDC timer 2 */
+    LEDC_TIMER_3,     /*!< LEDC timer 3 */
+    LEDC_TIMER_MAX,
+} ledc_timer_t;
+
+typedef enum {
+    LEDC_CHANNEL_0 = 0, /*!< LEDC channel 0 */
+    LEDC_CHANNEL_1,     /*!< LEDC channel 1 */
+    LEDC_CHANNEL_2,     /*!< LEDC channel 2 */
+    LEDC_CHANNEL_3,     /*!< LEDC channel 3 */
+    LEDC_CHANNEL_4,     /*!< LEDC channel 4 */
+    LEDC_CHANNEL_5,     /*!< LEDC channel 5 */
+    LEDC_CHANNEL_6,     /*!< LEDC channel 6 */
+    LEDC_CHANNEL_7,     /*!< LEDC channel 7 */
+    LEDC_CHANNEL_MAX,
+} ledc_channel_t;
+
+typedef enum {
+    LEDC_TIMER_1_BIT = 1,   /*!< LEDC PWM duty resolution of  1 bits */
+    LEDC_TIMER_2_BIT,       /*!< LEDC PWM duty resolution of  2 bits */
+    LEDC_TIMER_3_BIT,       /*!< LEDC PWM duty resolution of  3 bits */
+    LEDC_TIMER_4_BIT,       /*!< LEDC PWM duty resolution of  4 bits */
+    LEDC_TIMER_5_BIT,       /*!< LEDC PWM duty resolution of  5 bits */
+    LEDC_TIMER_6_BIT,       /*!< LEDC PWM duty resolution of  6 bits */
+    LEDC_TIMER_7_BIT,       /*!< LEDC PWM duty resolution of  7 bits */
+    LEDC_TIMER_8_BIT,       /*!< LEDC PWM duty resolution of  8 bits */
+    LEDC_TIMER_9_BIT,       /*!< LEDC PWM duty resolution of  9 bits */
+    LEDC_TIMER_10_BIT,      /*!< LEDC PWM duty resolution of 10 bits */
+    LEDC_TIMER_11_BIT,      /*!< LEDC PWM duty resolution of 11 bits */
+    LEDC_TIMER_12_BIT,      /*!< LEDC PWM duty resolution of 12 bits */
+    LEDC_TIMER_13_BIT,      /*!< LEDC PWM duty resolution of 13 bits */
+    LEDC_TIMER_14_BIT,      /*!< LEDC PWM duty resolution of 14 bits */
+    LEDC_TIMER_15_BIT,      /*!< LEDC PWM duty resolution of 15 bits */
+    LEDC_TIMER_16_BIT,      /*!< LEDC PWM duty resolution of 16 bits */
+    LEDC_TIMER_17_BIT,      /*!< LEDC PWM duty resolution of 17 bits */
+    LEDC_TIMER_18_BIT,      /*!< LEDC PWM duty resolution of 18 bits */
+    LEDC_TIMER_19_BIT,      /*!< LEDC PWM duty resolution of 19 bits */
+    LEDC_TIMER_20_BIT,      /*!< LEDC PWM duty resolution of 20 bits */
+    LEDC_TIMER_BIT_MAX,
+} ledc_timer_bit_t;
+
+typedef enum {
+    LEDC_FADE_NO_WAIT = 0,  /*!< LEDC fade function will return immediately */
+    LEDC_FADE_WAIT_DONE,    /*!< LEDC fade function will block until fading to the target duty */
+    LEDC_FADE_MAX,
+} ledc_fade_mode_t;
+
+/**
+ * @brief Configuration parameters of LEDC channel for ledc_channel_config function
+ */
+typedef struct {
+    int gpio_num;                   /*!< the LEDC output gpio_num, if you want to use gpio16, gpio_num = 16 */
+    ledc_mode_t speed_mode;         /*!< LEDC speed speed_mode, high-speed mode or low-speed mode */
+    ledc_channel_t channel;         /*!< LEDC channel (0 - 7) */
+    ledc_intr_type_t intr_type;     /*!< configure interrupt, Fade interrupt enable  or Fade interrupt disable */
+    ledc_timer_t timer_sel;         /*!< Select the timer source of channel (0 - 3) */
+    uint32_t duty;                  /*!< LEDC channel duty, the range of duty setting is [0, (2**duty_resolution)] */
+    int hpoint;                     /*!< LEDC channel hpoint value, the max value is 0xfffff */
+} ledc_channel_config_t;
+
+/**
+ * @brief Configuration parameters of LEDC Timer timer for ledc_timer_config function
+ */
+typedef struct {
+    ledc_mode_t speed_mode;                /*!< LEDC speed speed_mode, high-speed mode or low-speed mode */
+    union {
+        ledc_timer_bit_t duty_resolution;  /*!< LEDC channel duty resolution */
+        ledc_timer_bit_t bit_num __attribute__((deprecated)); /*!< Deprecated in ESP-IDF 3.0. This is an alias to 'duty_resolution' for backward compatibility with ESP-IDF 2.1 */
+    };
+    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_timer_config_t;
+
+#ifdef __cplusplus
+}
+#endif

+ 1 - 0
components/soc/linker.lf

@@ -13,4 +13,5 @@ entries:
     spi_hal_iram (noflash_text)
     spi_slave_hal_iram (noflash_text)
     spi_flash_hal_iram (noflash)
+    ledc_hal_iram (noflash_text)
     lldesc (noflash_text)

+ 60 - 0
components/soc/src/hal/ledc_hal.c

@@ -0,0 +1,60 @@
+// 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.
+
+// The HAL layer for LEDC (common part)
+
+#include "esp_attr.h"
+#include "hal/ledc_hal.h"
+
+void ledc_hal_init(ledc_hal_context_t *hal, ledc_mode_t speed_mode)
+{
+    //Get hardware instance.
+    hal->dev = LEDC_LL_GET_HW();
+    hal->speed_mode = speed_mode;
+}
+
+void ledc_hal_get_clk_cfg(ledc_hal_context_t *hal, ledc_timer_t timer_sel, ledc_clk_cfg_t *clk_cfg)
+{
+    ledc_clk_src_t clk_src = LEDC_APB_CLK;
+    ledc_hal_get_clock_source(hal, timer_sel, &clk_src);
+    if (clk_src == LEDC_REF_TICK) {
+        *clk_cfg = LEDC_USE_REF_TICK;
+    } else {
+        *clk_cfg = LEDC_USE_APB_CLK;
+        if (hal->speed_mode == LEDC_LOW_SPEED_MODE) {
+            ledc_slow_clk_sel_t slow_clk = LEDC_SLOW_CLK_APB;
+            ledc_hal_get_slow_clk_sel(hal, &slow_clk);
+            if (slow_clk == LEDC_SLOW_CLK_RTC8M) {
+                *clk_cfg = LEDC_USE_RTC8M_CLK;
+#ifdef CONFIG_IDF_TARGET_ESP32S2BETA
+            } else if (slow_clk == LEDC_SLOW_CLK_XTAL) {
+                *clk_cfg = LEDC_USE_XTAL_CLK;
+#endif
+            }
+        }
+    }
+}
+
+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 = LEDC_SLOW_CLK_APB;
+#ifdef CONFIG_IDF_TARGET_ESP32
+    slow_clk_sel = (clk_cfg == LEDC_USE_RTC8M_CLK) ? LEDC_SLOW_CLK_RTC8M : LEDC_SLOW_CLK_APB;
+#elif defined CONFIG_IDF_TARGET_ESP32S2BETA
+    slow_clk_sel = (clk_cfg == LEDC_USE_RTC8M_CLK) ? LEDC_SLOW_CLK_RTC8M :
+                                       ((clk_cfg == LEDC_USE_XTAL_CLK) ? LEDC_SLOW_CLK_XTAL : LEDC_SLOW_CLK_APB);
+#endif
+    ledc_hal_set_slow_clk_sel(hal, slow_clk_sel);
+}

+ 64 - 0
components/soc/src/hal/ledc_hal_iram.c

@@ -0,0 +1,64 @@
+// 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.
+
+// The HAL layer for LEDC (common part, in iram)
+// make these functions in a seperate file to make sure all LL functions are in the IRAM.
+
+#include "esp_attr.h"
+#include "hal/ledc_hal.h"
+
+void ledc_hal_ls_channel_update(ledc_hal_context_t *hal, ledc_channel_t channel_num)
+{
+    ledc_ll_ls_channel_update(hal->dev, hal->speed_mode, channel_num);
+}
+
+void ledc_hal_set_hpoint(ledc_hal_context_t *hal, ledc_channel_t channel_num, uint32_t hpoint_val)
+{
+    ledc_ll_set_hpoint(hal->dev, hal->speed_mode, channel_num, hpoint_val);
+}
+
+void ledc_hal_get_duty(ledc_hal_context_t *hal, ledc_channel_t channel_num, uint32_t *duty_val)
+{
+    ledc_ll_get_duty(hal->dev, hal->speed_mode, channel_num, duty_val);
+}
+
+void ledc_hal_set_duty_direction(ledc_hal_context_t *hal, ledc_channel_t channel_num, ledc_duty_direction_t duty_direction)
+{
+    ledc_ll_set_duty_direction(hal->dev, hal->speed_mode, channel_num, duty_direction);
+}
+
+void ledc_hal_set_duty_num(ledc_hal_context_t *hal, ledc_channel_t channel_num, uint32_t duty_num)
+{
+    ledc_ll_set_duty_num(hal->dev, hal->speed_mode, channel_num, duty_num);
+}
+
+void ledc_hal_set_duty_cycle(ledc_hal_context_t *hal, ledc_channel_t channel_num, uint32_t duty_cycle)
+{
+    ledc_ll_set_duty_cycle(hal->dev, hal->speed_mode, channel_num, duty_cycle);
+}
+
+void ledc_hal_set_duty_scale(ledc_hal_context_t *hal, ledc_channel_t channel_num, uint32_t duty_scale)
+{
+    ledc_ll_set_duty_scale(hal->dev, hal->speed_mode, channel_num, duty_scale);
+}
+
+void ledc_hal_get_fade_end_intr_status(ledc_hal_context_t *hal, uint32_t *intr_status)
+{
+    ledc_ll_get_fade_end_intr_status(hal->dev, hal->speed_mode, intr_status);
+}
+
+void ledc_hal_clear_fade_end_intr_status(ledc_hal_context_t *hal, ledc_channel_t channel_num)
+{
+    ledc_ll_clear_fade_end_intr_status(hal->dev, hal->speed_mode, channel_num);
+}

+ 1 - 0
docs/Doxyfile

@@ -110,6 +110,7 @@ INPUT = \
     ../../components/soc/include/hal/rtc_io_types.h \
     ../../components/soc/include/hal/sigmadelta_types.h \
     ../../components/soc/include/hal/timer_types.h \
+    ../../components/soc/include/hal/ledc_types.h \
     ../../components/soc/esp32/include/soc/adc_channel.h \
     ../../components/soc/esp32/include/soc/dac_channel.h \
     ../../components/soc/esp32/include/soc/touch_channel.h \