From 857dec108dbfa127945ee9df6fa582c7016bd323 Mon Sep 17 00:00:00 2001 From: chenjianqiang Date: Fri, 9 Aug 2019 20:30:19 +0800 Subject: [PATCH] feat(ledc): refactor ledc driver 1. add hal and low-level layer for ledc driver 2. support esp32s2beta ledc --- components/driver/include/driver/ledc.h | 142 +----- components/driver/ledc.c | 412 +++++++-------- components/soc/CMakeLists.txt | 2 + components/soc/esp32/include/hal/ledc_ll.h | 454 +++++++++++++++++ .../soc/esp32s2beta/include/hal/ledc_ll.h | 479 ++++++++++++++++++ .../soc/esp32s2beta/include/soc/ledc_struct.h | 2 +- components/soc/include/hal/ledc_hal.h | 388 ++++++++++++++ components/soc/include/hal/ledc_types.h | 148 ++++++ components/soc/linker.lf | 1 + components/soc/src/hal/ledc_hal.c | 60 +++ components/soc/src/hal/ledc_hal_iram.c | 64 +++ docs/Doxyfile | 1 + 12 files changed, 1821 insertions(+), 332 deletions(-) create mode 100644 components/soc/esp32/include/hal/ledc_ll.h create mode 100644 components/soc/esp32s2beta/include/hal/ledc_ll.h create mode 100644 components/soc/include/hal/ledc_hal.h create mode 100644 components/soc/include/hal/ledc_types.h create mode 100644 components/soc/src/hal/ledc_hal.c create mode 100644 components/soc/src/hal/ledc_hal_iram.c diff --git a/components/driver/include/driver/ledc.h b/components/driver/include/driver/ledc.h index 82ab7a1f8..fb3ffcaf0 100644 --- a/components/driver/include/driver/ledc.h +++ b/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_ */ diff --git a/components/driver/ledc.c b/components/driver/ledc.c index 352c76257..6be0169c8 100644 --- a/components/driver/ledc.c +++ b/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; + ledc_hal_set_duty_int_part(&(p_ledc_obj[speed_mode]->ledc_hal), channel, 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); - 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) -{ - 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_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_timer_rst(ledc_mode_t speed_mode, uint32_t timer_sel) +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_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_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, 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_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; + portENTER_CRITICAL(&ledc_spinlock); + ledc_hal_set_slow_clk(&(p_ledc_obj[speed_mode]->ledc_hal), clk_cfg); + portEXIT_CRITICAL(&ledc_spinlock); } -#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; - } - //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 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); } - 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); - } - 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"); diff --git a/components/soc/CMakeLists.txt b/components/soc/CMakeLists.txt index 1aba1a759..6f13bf733 100644 --- a/components/soc/CMakeLists.txt +++ b/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 diff --git a/components/soc/esp32/include/hal/ledc_ll.h b/components/soc/esp32/include/hal/ledc_ll.h new file mode 100644 index 000000000..2082d9a70 --- /dev/null +++ b/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; +} diff --git a/components/soc/esp32s2beta/include/hal/ledc_ll.h b/components/soc/esp32s2beta/include/hal/ledc_ll.h new file mode 100644 index 000000000..3cd87a9de --- /dev/null +++ b/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; +} diff --git a/components/soc/esp32s2beta/include/soc/ledc_struct.h b/components/soc/esp32s2beta/include/soc/ledc_struct.h index aedaeefaf..471a1cd87 100644 --- a/components/soc/esp32s2beta/include/soc/ledc_struct.h +++ b/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; diff --git a/components/soc/include/hal/ledc_hal.h b/components/soc/include/hal/ledc_hal.h new file mode 100644 index 000000000..967e82674 --- /dev/null +++ b/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); diff --git a/components/soc/include/hal/ledc_types.h b/components/soc/include/hal/ledc_types.h new file mode 100644 index 000000000..855c18c6c --- /dev/null +++ b/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 +#include + +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 diff --git a/components/soc/linker.lf b/components/soc/linker.lf index 092322a0c..70a7454a7 100644 --- a/components/soc/linker.lf +++ b/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) diff --git a/components/soc/src/hal/ledc_hal.c b/components/soc/src/hal/ledc_hal.c new file mode 100644 index 000000000..4895f58e8 --- /dev/null +++ b/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); +} diff --git a/components/soc/src/hal/ledc_hal_iram.c b/components/soc/src/hal/ledc_hal_iram.c new file mode 100644 index 000000000..3ca0d1dd0 --- /dev/null +++ b/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); +} diff --git a/docs/Doxyfile b/docs/Doxyfile index d59099866..70ae701c4 100644 --- a/docs/Doxyfile +++ b/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 \