mirror of
https://github.com/espressif/esp-idf.git
synced 2025-09-23 09:13:11 +00:00
driver: ledc - update fading functions, add example and doc
1. add fading functions. 2. clear up ledc.c and ledc.h 3. update api doc. 4. add ledc example 5. edit ledc.rst and add readme for example code. 6. add s_ prefix for static global values. 7. add mutex for fade functions 8. minor changes according to the comments.
This commit is contained in:
@@ -19,6 +19,8 @@
|
||||
#include "freertos/xtensa_api.h"
|
||||
#include "soc/gpio_sig_map.h"
|
||||
#include "driver/ledc.h"
|
||||
#include "soc/ledc_reg.h"
|
||||
#include "soc/ledc_struct.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
static const char* LEDC_TAG = "ledc";
|
||||
@@ -29,26 +31,56 @@ static portMUX_TYPE ledc_spinlock = portMUX_INITIALIZER_UNLOCKED;
|
||||
return (ret_val); \
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
uint16_t speed_mode;
|
||||
uint16_t direction;
|
||||
int target_duty;
|
||||
int cycle_num;
|
||||
int scale;
|
||||
ledc_fade_mode_t mode;
|
||||
xSemaphoreHandle ledc_fade_sem;
|
||||
xSemaphoreHandle ledc_fade_mux;
|
||||
} ledc_fade_t;
|
||||
static ledc_fade_t* s_ledc_fade_rec = NULL;
|
||||
static ledc_isr_handle_t s_ledc_fade_isr_handle = NULL;
|
||||
|
||||
#define LEDC_VAL_NO_CHANGE (-1)
|
||||
#define LEDC_STEP_NUM_MAX (1023)
|
||||
#define LEDC_DUTY_DECIMAL_BIT_NUM (4)
|
||||
|
||||
#define LEDC_MODE_ERR_STR "LEDC mode error"
|
||||
#define LEDC_TIMER_ERR_STR "LEDC timer error"
|
||||
#define LEDC_CHANNEL_ERR_STR "LEDC channel error"
|
||||
#define LEDC_GPIO_OUT_ERR_STR "LEDC GPIO output number error"
|
||||
#define LEDC_FADE_DIR_ERR_STR "LEDC fade direction error"
|
||||
#define LEDC_FADE_SERVICE_ERR_STR "LEDC fade service not installed"
|
||||
#define LEDC_FADE_TARGET_ERR_STR "LEDC fade target duty error"
|
||||
#define LEDC_FADE_INSTALLED_ERR_STR "LEDC fade service already installed"
|
||||
#define LEDC_FADE_MODE_ERR_STR "LEDC fade mode error"
|
||||
|
||||
|
||||
esp_err_t ledc_timer_set(ledc_mode_t speed_mode, ledc_timer_t timer_sel, uint32_t div_num, uint32_t bit_num, ledc_clk_src_t clk_src)
|
||||
{
|
||||
LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "ledc mode error", ESP_ERR_INVALID_ARG);
|
||||
LEDC_CHECK(timer_sel <= LEDC_TIMER_3, "ledc timer error", ESP_ERR_INVALID_ARG);
|
||||
LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, LEDC_MODE_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
LEDC_CHECK(timer_sel <= LEDC_TIMER_3, LEDC_TIMER_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
portENTER_CRITICAL(&ledc_spinlock);
|
||||
LEDC.timer_group[speed_mode].timer[timer_sel].conf.div_num = div_num;
|
||||
LEDC.timer_group[speed_mode].timer[timer_sel].conf.tick_sel = clk_src;
|
||||
LEDC.timer_group[speed_mode].timer[timer_sel].conf.bit_num = bit_num;
|
||||
if(speed_mode != LEDC_HIGH_SPEED_MODE) {
|
||||
if (speed_mode != LEDC_HIGH_SPEED_MODE) {
|
||||
LEDC.timer_group[speed_mode].timer[timer_sel].conf.low_speed_update = 1;
|
||||
}
|
||||
portEXIT_CRITICAL(&ledc_spinlock);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t ledc_duty_config(ledc_mode_t speed_mode, ledc_channel_t channel_num, uint32_t hpoint_val, uint32_t duty_val,
|
||||
static IRAM_ATTR esp_err_t ledc_duty_config(ledc_mode_t speed_mode, ledc_channel_t channel_num, int hpoint_val, uint32_t duty_val,
|
||||
uint32_t duty_direction, uint32_t duty_num, uint32_t duty_cycle, uint32_t duty_scale)
|
||||
{
|
||||
portENTER_CRITICAL(&ledc_spinlock);
|
||||
LEDC.channel_group[speed_mode].channel[channel_num].hpoint.hpoint = hpoint_val;
|
||||
if (hpoint_val >= 0) {
|
||||
LEDC.channel_group[speed_mode].channel[channel_num].hpoint.hpoint = hpoint_val;
|
||||
}
|
||||
LEDC.channel_group[speed_mode].channel[channel_num].duty.duty = duty_val;
|
||||
LEDC.channel_group[speed_mode].channel[channel_num].conf1.val = ((duty_direction & LEDC_DUTY_INC_HSCH0_V) << LEDC_DUTY_INC_HSCH0_S) |
|
||||
((duty_num & LEDC_DUTY_NUM_HSCH0_V) << LEDC_DUTY_NUM_HSCH0_S) |
|
||||
@@ -60,8 +92,8 @@ static esp_err_t ledc_duty_config(ledc_mode_t speed_mode, ledc_channel_t channel
|
||||
|
||||
esp_err_t ledc_bind_channel_timer(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t timer_idx)
|
||||
{
|
||||
LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "ledc mode error", ESP_ERR_INVALID_ARG);
|
||||
LEDC_CHECK(timer_idx <= LEDC_TIMER_3, "ledc timer error", ESP_ERR_INVALID_ARG);
|
||||
LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, LEDC_MODE_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
LEDC_CHECK(timer_idx <= LEDC_TIMER_3, LEDC_TIMER_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
portENTER_CRITICAL(&ledc_spinlock);
|
||||
LEDC.channel_group[speed_mode].channel[channel].conf0.timer_sel = timer_idx;
|
||||
portEXIT_CRITICAL(&ledc_spinlock);
|
||||
@@ -70,8 +102,8 @@ esp_err_t ledc_bind_channel_timer(ledc_mode_t speed_mode, ledc_channel_t channel
|
||||
|
||||
esp_err_t ledc_timer_rst(ledc_mode_t speed_mode, uint32_t timer_sel)
|
||||
{
|
||||
LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "ledc mode error", ESP_ERR_INVALID_ARG);
|
||||
LEDC_CHECK(timer_sel <= LEDC_TIMER_3, "ledc timer error", ESP_ERR_INVALID_ARG);
|
||||
LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, LEDC_MODE_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
LEDC_CHECK(timer_sel <= LEDC_TIMER_3, LEDC_TIMER_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
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;
|
||||
@@ -81,8 +113,8 @@ esp_err_t ledc_timer_rst(ledc_mode_t speed_mode, uint32_t timer_sel)
|
||||
|
||||
esp_err_t ledc_timer_pause(ledc_mode_t speed_mode, uint32_t timer_sel)
|
||||
{
|
||||
LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "ledc mode error", ESP_ERR_INVALID_ARG);
|
||||
LEDC_CHECK(timer_sel <= LEDC_TIMER_3, "ledc timer error", ESP_ERR_INVALID_ARG);
|
||||
LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, LEDC_MODE_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
LEDC_CHECK(timer_sel <= LEDC_TIMER_3, LEDC_TIMER_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
portENTER_CRITICAL(&ledc_spinlock);
|
||||
LEDC.timer_group[speed_mode].timer[timer_sel].conf.pause = 1;
|
||||
portEXIT_CRITICAL(&ledc_spinlock);
|
||||
@@ -91,8 +123,8 @@ esp_err_t ledc_timer_pause(ledc_mode_t speed_mode, uint32_t timer_sel)
|
||||
|
||||
esp_err_t ledc_timer_resume(ledc_mode_t speed_mode, uint32_t timer_sel)
|
||||
{
|
||||
LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "ledc mode error", ESP_ERR_INVALID_ARG);
|
||||
LEDC_CHECK(timer_sel <= LEDC_TIMER_3, "ledc timer error", ESP_ERR_INVALID_ARG);
|
||||
LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, LEDC_MODE_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
LEDC_CHECK(timer_sel <= LEDC_TIMER_3, LEDC_TIMER_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
portENTER_CRITICAL(&ledc_spinlock);
|
||||
LEDC.timer_group[speed_mode].timer[timer_sel].conf.pause = 0;
|
||||
portEXIT_CRITICAL(&ledc_spinlock);
|
||||
@@ -101,15 +133,15 @@ esp_err_t ledc_timer_resume(ledc_mode_t speed_mode, uint32_t timer_sel)
|
||||
|
||||
static esp_err_t ledc_enable_intr_type(ledc_mode_t speed_mode, uint32_t channel, ledc_intr_type_t type)
|
||||
{
|
||||
LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "ledc mode error", ESP_ERR_INVALID_ARG);
|
||||
LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, LEDC_MODE_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
uint32_t value;
|
||||
uint32_t intr_type = type;
|
||||
portENTER_CRITICAL(&ledc_spinlock);
|
||||
value = LEDC.int_ena.val;
|
||||
if(intr_type == LEDC_INTR_FADE_END) {
|
||||
if (intr_type == LEDC_INTR_FADE_END) {
|
||||
LEDC.int_ena.val = value | BIT(LEDC_DUTY_CHNG_END_HSCH0_INT_ENA_S + channel);
|
||||
} else {
|
||||
LEDC.int_ena.val = (value & (~(BIT(LEDC_DUTY_CHNG_END_HSCH0_INT_ENA_S + channel))));
|
||||
LEDC.int_ena.val = ( value & ( ~( BIT(LEDC_DUTY_CHNG_END_HSCH0_INT_ENA_S + channel) ) ) );
|
||||
}
|
||||
portEXIT_CRITICAL(&ledc_spinlock);
|
||||
return ESP_OK;
|
||||
@@ -120,7 +152,7 @@ esp_err_t ledc_isr_register(void (*fn)(void*), void * arg, int intr_alloc_flags,
|
||||
esp_err_t ret;
|
||||
LEDC_CHECK(fn, "ledc isr null", ESP_ERR_INVALID_ARG);
|
||||
portENTER_CRITICAL(&ledc_spinlock);
|
||||
ret=esp_intr_alloc(ETS_LEDC_INTR_SOURCE, intr_alloc_flags, fn, arg, handle);
|
||||
ret = esp_intr_alloc(ETS_LEDC_INTR_SOURCE, intr_alloc_flags, fn, arg, handle);
|
||||
portEXIT_CRITICAL(&ledc_spinlock);
|
||||
return ret;
|
||||
}
|
||||
@@ -131,32 +163,35 @@ esp_err_t ledc_timer_config(ledc_timer_config_t* timer_conf)
|
||||
int bit_num = timer_conf->bit_num;
|
||||
int timer_num = timer_conf->timer_num;
|
||||
int speed_mode = timer_conf->speed_mode;
|
||||
LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "ledc mode error", ESP_ERR_INVALID_ARG);
|
||||
if(freq_hz == 0 || bit_num == 0 || bit_num > LEDC_TIMER_15_BIT) {
|
||||
LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, LEDC_MODE_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
periph_module_enable(PERIPH_LEDC_MODULE);
|
||||
if (freq_hz == 0 || bit_num == 0 || bit_num > LEDC_TIMER_15_BIT) {
|
||||
ESP_LOGE(LEDC_TAG, "freq_hz=%u bit_num=%u", freq_hz, bit_num);
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if(timer_num > LEDC_TIMER_3) {
|
||||
if (timer_num > LEDC_TIMER_3) {
|
||||
ESP_LOGE(LEDC_TAG, "invalid timer #%u", timer_num);
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
esp_err_t ret = ESP_OK;
|
||||
uint32_t precision = (0x1 << bit_num); // 2**depth
|
||||
uint32_t precision = ( 0x1 << bit_num ); // 2**depth
|
||||
// Try calculating divisor based on LEDC_APB_CLK
|
||||
ledc_clk_src_t timer_clk_src = LEDC_APB_CLK;
|
||||
// div_param is a Q10.8 fixed point value
|
||||
uint64_t div_param = ((uint64_t) LEDC_APB_CLK_HZ << 8) / freq_hz / precision;
|
||||
uint64_t div_param = ( (uint64_t) LEDC_APB_CLK_HZ << 8 ) / freq_hz / precision;
|
||||
if (div_param < 256) {
|
||||
// divisor is too low
|
||||
ESP_LOGE(LEDC_TAG, "requested frequency and bit depth can not be achieved, try reducing freq_hz or bit_num. div_param=%d", (uint32_t) div_param);
|
||||
ESP_LOGE(LEDC_TAG, "requested frequency and bit depth can not be achieved, try reducing freq_hz or bit_num. div_param=%d",
|
||||
(uint32_t ) div_param);
|
||||
ret = ESP_FAIL;
|
||||
}
|
||||
if (div_param > LEDC_DIV_NUM_HSTIMER0_V) {
|
||||
// APB_CLK results in divisor which too high. Try using REF_TICK as clock source.
|
||||
timer_clk_src = LEDC_REF_TICK;
|
||||
div_param = ((uint64_t) LEDC_REF_CLK_HZ << 8) / freq_hz / precision;
|
||||
if(div_param < 256 || div_param > LEDC_DIV_NUM_HSTIMER0_V) {
|
||||
ESP_LOGE(LEDC_TAG, "requested frequency and bit depth can not be achieved, try increasing freq_hz or bit_num. div_param=%d", (uint32_t) div_param);
|
||||
div_param = ( (uint64_t) LEDC_REF_CLK_HZ << 8 ) / freq_hz / precision;
|
||||
if (div_param < 256 || div_param > LEDC_DIV_NUM_HSTIMER0_V) {
|
||||
ESP_LOGE(LEDC_TAG, "requested frequency and bit depth can not be achieved, try increasing freq_hz or bit_num. div_param=%d",
|
||||
(uint32_t ) div_param);
|
||||
ret = ESP_FAIL;
|
||||
}
|
||||
}
|
||||
@@ -169,12 +204,12 @@ esp_err_t ledc_timer_config(ledc_timer_config_t* timer_conf)
|
||||
|
||||
esp_err_t ledc_set_pin(int gpio_num, ledc_mode_t speed_mode, ledc_channel_t ledc_channel)
|
||||
{
|
||||
LEDC_CHECK(ledc_channel <= LEDC_CHANNEL_7, "ledc channel error", ESP_ERR_INVALID_ARG);
|
||||
LEDC_CHECK(GPIO_IS_VALID_OUTPUT_GPIO(gpio_num), "ledc GPIO output number error", ESP_ERR_INVALID_ARG);
|
||||
LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "ledc mode error", ESP_ERR_INVALID_ARG);
|
||||
LEDC_CHECK(ledc_channel <= LEDC_CHANNEL_7, LEDC_CHANNEL_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
LEDC_CHECK(GPIO_IS_VALID_OUTPUT_GPIO(gpio_num), LEDC_GPIO_OUT_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, LEDC_MODE_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[gpio_num], PIN_FUNC_GPIO);
|
||||
gpio_set_direction(gpio_num, GPIO_MODE_OUTPUT);
|
||||
if(speed_mode == LEDC_HIGH_SPEED_MODE) {
|
||||
if (speed_mode == LEDC_HIGH_SPEED_MODE) {
|
||||
gpio_matrix_out(gpio_num, LEDC_HS_SIG_OUT0_IDX + ledc_channel, 0, 0);
|
||||
} else {
|
||||
ESP_LOGE(LEDC_TAG, "low speed mode is not implemented");
|
||||
@@ -191,10 +226,10 @@ esp_err_t ledc_channel_config(ledc_channel_config_t* ledc_conf)
|
||||
uint32_t timer_select = ledc_conf->timer_sel;
|
||||
uint32_t intr_type = ledc_conf->intr_type;
|
||||
uint32_t duty = ledc_conf->duty;
|
||||
LEDC_CHECK(ledc_channel <= LEDC_CHANNEL_7, "ledc channel error", ESP_ERR_INVALID_ARG);
|
||||
LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "ledc mode error", ESP_ERR_INVALID_ARG);
|
||||
LEDC_CHECK(GPIO_IS_VALID_OUTPUT_GPIO(gpio_num), "ledc GPIO output number error", ESP_ERR_INVALID_ARG);
|
||||
LEDC_CHECK(timer_select <= LEDC_TIMER_3, "ledc timer error", ESP_ERR_INVALID_ARG);
|
||||
LEDC_CHECK(ledc_channel <= LEDC_CHANNEL_7, LEDC_CHANNEL_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, LEDC_MODE_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
LEDC_CHECK(GPIO_IS_VALID_OUTPUT_GPIO(gpio_num), LEDC_GPIO_OUT_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
LEDC_CHECK(timer_select <= LEDC_TIMER_3, LEDC_TIMER_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
periph_module_enable(PERIPH_LEDC_MODULE);
|
||||
esp_err_t ret = ESP_OK;
|
||||
/*set channel parameters*/
|
||||
@@ -207,7 +242,7 @@ esp_err_t ledc_channel_config(ledc_channel_config_t* ledc_conf)
|
||||
ledc_bind_channel_timer(speed_mode, ledc_channel, timer_select);
|
||||
/*set interrupt type*/
|
||||
ledc_enable_intr_type(speed_mode, ledc_channel, intr_type);
|
||||
ESP_LOGI(LEDC_TAG, "LEDC_PWM CHANNEL %1u|GPIO %02u|Duty %04u|Time %01u",
|
||||
ESP_LOGD(LEDC_TAG, "LEDC_PWM CHANNEL %1u|GPIO %02u|Duty %04u|Time %01u",
|
||||
ledc_channel, gpio_num, duty, timer_select
|
||||
);
|
||||
/*set LEDC signal in gpio matrix*/
|
||||
@@ -219,8 +254,8 @@ esp_err_t ledc_channel_config(ledc_channel_config_t* ledc_conf)
|
||||
|
||||
esp_err_t ledc_update_duty(ledc_mode_t speed_mode, ledc_channel_t channel)
|
||||
{
|
||||
LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "ledc mode error", ESP_ERR_INVALID_ARG);
|
||||
LEDC_CHECK(channel <= LEDC_CHANNEL_7, "ledc channel error", ESP_ERR_INVALID_ARG);
|
||||
LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, LEDC_MODE_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
LEDC_CHECK(channel <= LEDC_CHANNEL_7, LEDC_CHANNEL_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
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;
|
||||
@@ -230,8 +265,8 @@ esp_err_t ledc_update_duty(ledc_mode_t speed_mode, ledc_channel_t channel)
|
||||
|
||||
esp_err_t ledc_stop(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t idle_level)
|
||||
{
|
||||
LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "ledc mode error", ESP_ERR_INVALID_ARG);
|
||||
LEDC_CHECK(channel <= LEDC_CHANNEL_7, "ledc channel error", ESP_ERR_INVALID_ARG);
|
||||
LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, LEDC_MODE_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
LEDC_CHECK(channel <= LEDC_CHANNEL_7, LEDC_CHANNEL_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
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;
|
||||
@@ -239,16 +274,20 @@ esp_err_t ledc_stop(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t idl
|
||||
portEXIT_CRITICAL(&ledc_spinlock);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "ledc mode error", ESP_ERR_INVALID_ARG);
|
||||
LEDC_CHECK(channel <= LEDC_CHANNEL_7, "ledc channel error", ESP_ERR_INVALID_ARG);
|
||||
LEDC_CHECK(fade_direction <= LEDC_DUTY_DIR_INCREASE, "ledc fade direction error", ESP_ERR_INVALID_ARG);
|
||||
if(step_num > LEDC_DUTY_NUM_HSCH0_V || duty_cyle_num > LEDC_DUTY_CYCLE_HSCH0_V || duty_scale > LEDC_DUTY_SCALE_HSCH0_V) {
|
||||
LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, LEDC_MODE_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
LEDC_CHECK(channel <= LEDC_CHANNEL_7, LEDC_CHANNEL_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
LEDC_CHECK(fade_direction <= LEDC_DUTY_DIR_INCREASE, LEDC_FADE_DIR_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
if (step_num > LEDC_DUTY_NUM_HSCH0_V || duty_cyle_num > LEDC_DUTY_CYCLE_HSCH0_V || duty_scale > LEDC_DUTY_SCALE_HSCH0_V) {
|
||||
ESP_LOGE(LEDC_TAG, "step_num=%u duty_cyle_num=%u duty_scale=%u", step_num, duty_cyle_num, duty_scale);
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if (s_ledc_fade_rec) {
|
||||
ledc_enable_intr_type(speed_mode, channel, LEDC_INTR_DISABLE);
|
||||
}
|
||||
ledc_duty_config(speed_mode,
|
||||
channel, //uint32_t chan_num,
|
||||
0, //uint32_t hpoint_val,
|
||||
@@ -263,8 +302,11 @@ esp_err_t ledc_set_fade(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t
|
||||
|
||||
esp_err_t ledc_set_duty(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t duty)
|
||||
{
|
||||
LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "ledc mode error", ESP_ERR_INVALID_ARG);
|
||||
LEDC_CHECK(channel <= LEDC_CHANNEL_7, "ledc channel error", ESP_ERR_INVALID_ARG);
|
||||
LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, LEDC_MODE_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
LEDC_CHECK(channel <= LEDC_CHANNEL_7, LEDC_CHANNEL_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
if (s_ledc_fade_rec) {
|
||||
ledc_enable_intr_type(speed_mode, channel, LEDC_INTR_DISABLE);
|
||||
}
|
||||
ledc_duty_config(speed_mode,
|
||||
channel, //uint32_t chan_num,
|
||||
0, //uint32_t hpoint_val,
|
||||
@@ -279,26 +321,26 @@ esp_err_t ledc_set_duty(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t
|
||||
|
||||
int ledc_get_duty(ledc_mode_t speed_mode, ledc_channel_t channel)
|
||||
{
|
||||
LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "ledc mode error", (-1));
|
||||
LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, LEDC_MODE_ERR_STR, (-1));
|
||||
uint32_t duty = (LEDC.channel_group[speed_mode].channel[channel].duty_rd.duty_read >> 4);
|
||||
return duty;
|
||||
}
|
||||
|
||||
esp_err_t ledc_set_freq(ledc_mode_t speed_mode, ledc_timer_t timer_num, uint32_t freq_hz)
|
||||
{
|
||||
LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "ledc mode error", ESP_ERR_INVALID_ARG);
|
||||
LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, LEDC_MODE_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
portENTER_CRITICAL(&ledc_spinlock);
|
||||
esp_err_t ret = ESP_OK;
|
||||
uint32_t div_num = 0;
|
||||
uint32_t bit_num = LEDC.timer_group[speed_mode].timer[timer_num].conf.bit_num;
|
||||
uint32_t timer_source_clk = LEDC.timer_group[speed_mode].timer[timer_num].conf.tick_sel;
|
||||
uint32_t precision = (0x1 << bit_num);
|
||||
if(timer_source_clk == LEDC_APB_CLK) {
|
||||
div_num = ((uint64_t) LEDC_APB_CLK_HZ << 8) / freq_hz / precision;
|
||||
uint32_t precision = ( 0x1 << bit_num );
|
||||
if (timer_source_clk == LEDC_APB_CLK) {
|
||||
div_num = ( (uint64_t) LEDC_APB_CLK_HZ << 8 ) / freq_hz / precision;
|
||||
} else {
|
||||
div_num = ((uint64_t) LEDC_REF_CLK_HZ << 8) / freq_hz / precision;
|
||||
div_num = ( (uint64_t) LEDC_REF_CLK_HZ << 8 ) / freq_hz / precision;
|
||||
}
|
||||
if(div_num <= 256 || div_num > LEDC_DIV_NUM_HSTIMER0) {
|
||||
if (div_num <= 256 || div_num > LEDC_DIV_NUM_HSTIMER0) {
|
||||
ESP_LOGE(LEDC_TAG, "div param err,div_param=%u", div_num);
|
||||
ret = ESP_FAIL;
|
||||
}
|
||||
@@ -309,18 +351,217 @@ esp_err_t ledc_set_freq(ledc_mode_t speed_mode, ledc_timer_t timer_num, uint32_t
|
||||
|
||||
uint32_t ledc_get_freq(ledc_mode_t speed_mode, ledc_timer_t timer_num)
|
||||
{
|
||||
LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "ledc mode error", (0));
|
||||
LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, LEDC_MODE_ERR_STR, ( 0 ));
|
||||
portENTER_CRITICAL(&ledc_spinlock);
|
||||
uint32_t freq = 0;
|
||||
uint32_t timer_source_clk = LEDC.timer_group[speed_mode].timer[timer_num].conf.tick_sel;
|
||||
uint32_t bit_num = LEDC.timer_group[speed_mode].timer[timer_num].conf.bit_num;
|
||||
uint32_t div_num = LEDC.timer_group[speed_mode].timer[timer_num].conf.div_num;
|
||||
uint32_t precision = (0x1 << bit_num);
|
||||
if(timer_source_clk == LEDC_APB_CLK) {
|
||||
freq = ((uint64_t) LEDC_APB_CLK_HZ << 8) / precision / div_num;
|
||||
uint32_t precision = ( 0x1 << bit_num );
|
||||
if (timer_source_clk == LEDC_APB_CLK) {
|
||||
freq = ( (uint64_t) LEDC_APB_CLK_HZ << 8 ) / precision / div_num;
|
||||
} else {
|
||||
freq = ((uint64_t) LEDC_REF_CLK_HZ << 8) / precision / div_num;
|
||||
freq = ( (uint64_t) LEDC_REF_CLK_HZ << 8 ) / precision / div_num;
|
||||
}
|
||||
portEXIT_CRITICAL(&ledc_spinlock);
|
||||
return freq;
|
||||
}
|
||||
|
||||
void IRAM_ATTR ledc_fade_isr()
|
||||
{
|
||||
int i;
|
||||
portBASE_TYPE HPTaskAwoken = pdFALSE;
|
||||
uint32_t intr_status = LEDC.int_st.val; //read LEDC interrupt status.
|
||||
LEDC.int_clr.val = intr_status; //clear LEDC interrupt status.
|
||||
for (i = 0; i < 8; i++) {
|
||||
if (intr_status & BIT(LEDC_DUTY_CHNG_END_HSCH0_INT_ST_S + i)) {
|
||||
int speed_mode = s_ledc_fade_rec[i].speed_mode;
|
||||
int duty_cur = LEDC.channel_group[speed_mode].channel[i].duty_rd.duty_read >> LEDC_DUTY_DECIMAL_BIT_NUM;
|
||||
if (duty_cur == s_ledc_fade_rec[i].target_duty) {
|
||||
if(s_ledc_fade_rec[i].mode == LEDC_FADE_WAIT_DONE) {
|
||||
xSemaphoreGiveFromISR(s_ledc_fade_rec[i].ledc_fade_sem, &HPTaskAwoken);
|
||||
if(HPTaskAwoken == pdTRUE) {
|
||||
portYIELD_FROM_ISR() ;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
int duty_tar = s_ledc_fade_rec[i].target_duty;
|
||||
int scale = s_ledc_fade_rec[i].scale;
|
||||
if (scale == 0) {
|
||||
continue;
|
||||
}
|
||||
int cycle = s_ledc_fade_rec[i].cycle_num;
|
||||
int delta = s_ledc_fade_rec[i].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,
|
||||
i,
|
||||
LEDC_VAL_NO_CHANGE,
|
||||
duty_cur << LEDC_DUTY_DECIMAL_BIT_NUM,
|
||||
s_ledc_fade_rec[i].direction,
|
||||
step,
|
||||
cycle,
|
||||
scale);
|
||||
} else {
|
||||
ledc_duty_config(
|
||||
speed_mode,
|
||||
i,
|
||||
LEDC_VAL_NO_CHANGE,
|
||||
duty_tar << LEDC_DUTY_DECIMAL_BIT_NUM,
|
||||
s_ledc_fade_rec[i].direction,
|
||||
1,
|
||||
1,
|
||||
0);
|
||||
}
|
||||
LEDC.channel_group[speed_mode].channel[i].conf1.duty_start = 1;
|
||||
}
|
||||
}
|
||||
LEDC.int_clr.val = intr_status; //clear LEDC interrupt status.
|
||||
}
|
||||
|
||||
esp_err_t ledc_set_fade_with_time(ledc_mode_t speed_mode, ledc_channel_t channel, int target_duty, int max_fade_time_ms)
|
||||
{
|
||||
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.bit_num ) ) - 1;
|
||||
LEDC_CHECK(target_duty <= max_duty, LEDC_FADE_TARGET_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
uint32_t freq = ledc_get_freq(speed_mode, timer_sel);
|
||||
int duty_cur = LEDC.channel_group[speed_mode].channel[channel].duty_rd.duty_read >> LEDC_DUTY_DECIMAL_BIT_NUM;
|
||||
int duty_delta = target_duty > duty_cur ? target_duty - duty_cur : duty_cur - target_duty;
|
||||
|
||||
if (duty_delta == 0) {
|
||||
return ESP_OK;
|
||||
}
|
||||
int total_cycles = max_fade_time_ms * freq / 1000;
|
||||
int scale, cycle_num;
|
||||
if (total_cycles > duty_delta) {
|
||||
scale = 1;
|
||||
cycle_num = total_cycles / duty_delta;
|
||||
} else {
|
||||
cycle_num = 1;
|
||||
scale = ( duty_delta + total_cycles - 1 ) / total_cycles;
|
||||
}
|
||||
return ledc_set_fade_with_step(speed_mode, channel, target_duty, scale, cycle_num);
|
||||
}
|
||||
|
||||
esp_err_t ledc_set_fade_with_step(ledc_mode_t speed_mode, ledc_channel_t channel, int target_duty, int scale, int cycle_num)
|
||||
{
|
||||
LEDC_CHECK(s_ledc_fade_rec != NULL, LEDC_FADE_SERVICE_ERR_STR, ESP_ERR_INVALID_STATE);
|
||||
LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, LEDC_MODE_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
LEDC_CHECK(channel < LEDC_CHANNEL_MAX, LEDC_CHANNEL_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
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.bit_num)) - 1;
|
||||
LEDC_CHECK(target_duty <= max_duty, LEDC_FADE_TARGET_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
//disable the interrupt, so the operation will not mess up
|
||||
ledc_enable_intr_type(speed_mode, channel, LEDC_INTR_DISABLE);
|
||||
|
||||
portENTER_CRITICAL(&ledc_spinlock);
|
||||
int duty_cur = LEDC.channel_group[speed_mode].channel[channel].duty_rd.duty_read >> LEDC_DUTY_DECIMAL_BIT_NUM;
|
||||
int duty_delta = target_duty > duty_cur ? target_duty - duty_cur : duty_cur - target_duty;
|
||||
if (duty_delta == 0) {
|
||||
return ESP_OK;
|
||||
}
|
||||
s_ledc_fade_rec[channel].speed_mode = speed_mode;
|
||||
s_ledc_fade_rec[channel].target_duty = target_duty;
|
||||
s_ledc_fade_rec[channel].cycle_num = cycle_num;
|
||||
s_ledc_fade_rec[channel].scale = scale;
|
||||
int step_num;
|
||||
if (duty_cur > target_duty) {
|
||||
s_ledc_fade_rec[channel].direction = LEDC_DUTY_DIR_DECREASE;
|
||||
step_num = ( duty_cur - target_duty ) / scale;
|
||||
step_num = step_num > LEDC_STEP_NUM_MAX ? LEDC_STEP_NUM_MAX : step_num;
|
||||
} else {
|
||||
s_ledc_fade_rec[channel].direction = LEDC_DUTY_DIR_INCREASE;
|
||||
step_num = ( target_duty - duty_cur ) / scale;
|
||||
step_num = step_num > LEDC_STEP_NUM_MAX ? LEDC_STEP_NUM_MAX : step_num;
|
||||
}
|
||||
portEXIT_CRITICAL(&ledc_spinlock);
|
||||
|
||||
ledc_set_fade(
|
||||
speed_mode,
|
||||
channel,
|
||||
duty_cur,
|
||||
s_ledc_fade_rec[channel].direction,
|
||||
step_num,
|
||||
s_ledc_fade_rec[channel].cycle_num,
|
||||
s_ledc_fade_rec[channel].scale
|
||||
);
|
||||
ESP_LOGD(LEDC_TAG, "cur duty: %d; target: %d, step: %d, cycle: %d; scale: %d\n",
|
||||
LEDC.channel_group[speed_mode].channel[channel].duty_rd.duty_read >> LEDC_DUTY_DECIMAL_BIT_NUM,
|
||||
target_duty,
|
||||
step_num,
|
||||
s_ledc_fade_rec[channel].cycle_num,
|
||||
s_ledc_fade_rec[channel].scale
|
||||
);
|
||||
LEDC.int_clr.val |= BIT(LEDC_DUTY_CHNG_END_HSCH0_INT_ENA_S + channel);
|
||||
ledc_enable_intr_type(speed_mode, channel, LEDC_INTR_FADE_END);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t ledc_fade_func_install(int intr_alloc_flags)
|
||||
{
|
||||
LEDC_CHECK(s_ledc_fade_rec == NULL, LEDC_FADE_INSTALLED_ERR_STR, ESP_ERR_INVALID_STATE);
|
||||
s_ledc_fade_rec = (ledc_fade_t*) calloc(LEDC_CHANNEL_MAX, sizeof(ledc_fade_t));
|
||||
if (s_ledc_fade_rec == NULL) {
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
int i = 0;
|
||||
for (i = 0; i < LEDC_CHANNEL_MAX; i++) {
|
||||
s_ledc_fade_rec[i].ledc_fade_sem = xSemaphoreCreateBinary();
|
||||
s_ledc_fade_rec[i].ledc_fade_mux = xSemaphoreCreateMutex();
|
||||
if (s_ledc_fade_rec[i].ledc_fade_sem == NULL || s_ledc_fade_rec[i].ledc_fade_mux == NULL) {
|
||||
ledc_fade_func_uninstall();
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
}
|
||||
//OR intr_alloc_flags with ESP_INTR_FLAG_IRAM because the fade isr is in IRAM
|
||||
ledc_isr_register(ledc_fade_isr, NULL, intr_alloc_flags | ESP_INTR_FLAG_IRAM, &s_ledc_fade_isr_handle);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void ledc_fade_func_uninstall()
|
||||
{
|
||||
if (s_ledc_fade_rec == NULL) {
|
||||
return;
|
||||
}
|
||||
if(s_ledc_fade_isr_handle) {
|
||||
esp_intr_free(s_ledc_fade_isr_handle);
|
||||
s_ledc_fade_isr_handle = NULL;
|
||||
}
|
||||
int i;
|
||||
for (i = 0; i < LEDC_CHANNEL_MAX; i++) {
|
||||
if (s_ledc_fade_rec[i].ledc_fade_sem) {
|
||||
xSemaphoreHandle sem_tmp = s_ledc_fade_rec[i].ledc_fade_sem;
|
||||
s_ledc_fade_rec[i].ledc_fade_sem = NULL;
|
||||
vSemaphoreDelete(sem_tmp);
|
||||
}
|
||||
if (s_ledc_fade_rec[i].ledc_fade_mux) {
|
||||
xSemaphoreHandle mux_tmp = s_ledc_fade_rec[i].ledc_fade_mux;
|
||||
s_ledc_fade_rec[i].ledc_fade_mux = NULL;
|
||||
vSemaphoreDelete(mux_tmp);
|
||||
}
|
||||
}
|
||||
free(s_ledc_fade_rec);
|
||||
s_ledc_fade_rec = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
esp_err_t ledc_fade_start(ledc_channel_t channel, ledc_fade_mode_t wait_done)
|
||||
{
|
||||
LEDC_CHECK(s_ledc_fade_rec != NULL, LEDC_FADE_SERVICE_ERR_STR, ESP_ERR_INVALID_STATE);
|
||||
LEDC_CHECK(wait_done < LEDC_FADE_MAX, LEDC_FADE_MODE_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
int speed_mode = s_ledc_fade_rec[channel].speed_mode;
|
||||
xSemaphoreTake(s_ledc_fade_rec[channel].ledc_fade_mux, portMAX_DELAY);
|
||||
if (wait_done == LEDC_FADE_WAIT_DONE) {
|
||||
s_ledc_fade_rec[channel].mode = LEDC_FADE_WAIT_DONE;
|
||||
ledc_update_duty(speed_mode, channel);
|
||||
xSemaphoreTake(s_ledc_fade_rec[channel].ledc_fade_sem, portMAX_DELAY);
|
||||
} else {
|
||||
s_ledc_fade_rec[channel].mode = LEDC_FADE_NO_WAIT;
|
||||
ledc_update_duty(speed_mode, channel);
|
||||
}
|
||||
xSemaphoreGive(s_ledc_fade_rec[channel].ledc_fade_mux);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
Reference in New Issue
Block a user