feature(ledc): Redefine duty

This commit is contained in:
chenzhengwei
2019-10-10 15:33:22 +08:00
committed by dongheng
parent 2fa4782599
commit 046ba744fa
3 changed files with 162 additions and 87 deletions

View File

@ -33,6 +33,7 @@
#define LEDC_FLAG_ON (1)
#define LEDC_FLAG_OFF (0)
#define LEDC_TASK_STACK_DEPTH (1024)
#define LEDC_MAX_DUTY (8196)
static const char* LEDC_TAG = "ledc";
@ -96,13 +97,14 @@ esp_err_t ledc_timer_config(const ledc_timer_config_t* timer_conf)
esp_err_t ledc_set_duty(ledc_mode_t speed_mode, ledc_channel_t ledc_channel, uint32_t ledc_duty)
{
LEDC_CHECK(ledc_channel < LEDC_CHANNEL_MAX, "ledc_channel error", ESP_ERR_INVALID_ARG);
LEDC_CHECK(ledc_duty <= ledc_period, "ledc_duty error", ESP_ERR_INVALID_ARG);
LEDC_CHECK(ledc_period * ledc_duty / LEDC_MAX_DUTY <= ledc_period, "ledc_duty error", ESP_ERR_INVALID_ARG);
p_ledc_obj[ledc_channel]->channel_num = ledc_channel;
p_ledc_obj[ledc_channel]->duty = ledc_duty;
p_ledc_obj[ledc_channel]->duty = ledc_period * ledc_duty / LEDC_MAX_DUTY;
pwm_get_duty(ledc_channel, &p_ledc_obj[ledc_channel]->duty_p);
p_ledc_obj[ledc_channel]->step_duty = (p_ledc_obj[ledc_channel]->duty_p > p_ledc_obj[ledc_channel]->duty ? p_ledc_obj[ledc_channel]->duty_p - p_ledc_obj[ledc_channel]->duty : p_ledc_obj[ledc_channel]->duty - p_ledc_obj[ledc_channel]->duty_p);
//The duty print value for this channel is duty/period(Program internal value), corresponding to duty/ledc_max_duty
ESP_LOGI(LEDC_TAG, "channel_num = %d | duty = %d; duty_p = %d | step_duty = %d;",
p_ledc_obj[ledc_channel]->channel_num, p_ledc_obj[ledc_channel]->duty,
p_ledc_obj[ledc_channel]->duty_p, p_ledc_obj[ledc_channel]->step_duty);
@ -128,10 +130,10 @@ esp_err_t ledc_set_fade_with_time(ledc_mode_t speed_mode, ledc_channel_t ledc_ch
{
// For porting, speed_mode is not used
LEDC_CHECK(ledc_channel < LEDC_CHANNEL_MAX, "ledc_channel error", ESP_ERR_INVALID_ARG);
LEDC_CHECK(ledc_duty <= ledc_period, "ledc_duty error", ESP_ERR_INVALID_ARG);
LEDC_CHECK(ledc_period * ledc_duty / LEDC_MAX_DUTY <= ledc_period, "ledc_duty error", ESP_ERR_INVALID_ARG);
p_ledc_obj[ledc_channel]->channel_num = ledc_channel;
p_ledc_obj[ledc_channel]->duty = ledc_duty;
p_ledc_obj[ledc_channel]->duty = ledc_period * ledc_duty / LEDC_MAX_DUTY;
p_ledc_obj[ledc_channel]->fade_time = ledc_fade_time;
pwm_get_duty(ledc_channel, &p_ledc_obj[ledc_channel]->duty_p);
uint32_t duty_value = (p_ledc_obj[ledc_channel]->duty_p > p_ledc_obj[ledc_channel]->duty ? (p_ledc_obj[ledc_channel]->duty_p - p_ledc_obj[ledc_channel]->duty) : (p_ledc_obj[ledc_channel]->duty - p_ledc_obj[ledc_channel]->duty_p));
@ -140,6 +142,7 @@ esp_err_t ledc_set_fade_with_time(ledc_mode_t speed_mode, ledc_channel_t ledc_ch
p_ledc_obj[ledc_channel]->step_01duty = duty_value * 10 / (ledc_fade_time / LEDC_STEP_TIME) % 10;
p_ledc_obj[ledc_channel]->step_001duty = duty_value * 100 / (ledc_fade_time / LEDC_STEP_TIME) % 10;
//The duty print value for this channel is duty/period(Program internal value), corresponding to duty/ledc_max_duty
ESP_LOGI(LEDC_TAG, "channel_num = %d | duty = %d; duty_p = %d | step_duty = %d | step_01duty = %d | step_001duty = %d",
p_ledc_obj[ledc_channel]->channel_num, p_ledc_obj[ledc_channel]->duty,
p_ledc_obj[ledc_channel]->duty_p, p_ledc_obj[ledc_channel]->step_duty, p_ledc_obj[ledc_channel]->step_01duty, p_ledc_obj[ledc_channel]->step_001duty);
@ -176,7 +179,7 @@ esp_err_t ledc_channel_config(const ledc_channel_config_t* ledc_conf)
}
}
p_ledc_obj[ledc_usr_channel_max]->gpio_num = ledc_conf->gpio_num;
p_ledc_obj[ledc_usr_channel_max]->duty = ledc_conf->duty;
p_ledc_obj[ledc_usr_channel_max]->duty = ledc_period * ledc_conf->duty / LEDC_MAX_DUTY;
ledc_usr_channel_max++;
return ESP_OK;
@ -208,7 +211,6 @@ esp_err_t ledc_fade_up(ledc_channel_t channel, uint8_t* flag)
}
if (p_ledc_obj[channel]->duty_p == p_ledc_obj[channel]->duty) {
*flag = LEDC_FLAG_OFF;
ESP_LOGI(LEDC_TAG, "channel%d is end", channel);
}
return ESP_OK;
@ -241,7 +243,6 @@ esp_err_t ledc_fade_down(ledc_channel_t channel, uint8_t* flag)
}
if (p_ledc_obj[channel]->duty_p == p_ledc_obj[channel]->duty) {
*flag = LEDC_FLAG_OFF;
ESP_LOGI(LEDC_TAG, "channel%d is end", channel);
}
return ESP_OK;
@ -258,7 +259,6 @@ static void ledc_task(void* pvParameters)
while (pdTRUE == xQueueReceive(channel_queue, &channel, 0)) {
flag[channel] = LEDC_FLAG_ON;
ESP_LOGI(LEDC_TAG, "channel%d is start", channel);
}
vTaskSuspendAll();
for (i = 0; i < ledc_usr_channel_max; i++) {
@ -294,7 +294,6 @@ esp_err_t ledc_fade_func_install(int intr_alloc_flags)
ESP_LOGI(LEDC_TAG, "gpio:%d", ledc_gpio_num[i]);
}
pwm_set_phases(ledc_phase);
channel_queue = xQueueCreate(ledc_usr_channel_max, sizeof(uint8_t));
if (channel_queue == 0) {
@ -315,3 +314,25 @@ esp_err_t ledc_fade_func_uninstall(void)
}
return pwm_stop(0x00);
}
esp_err_t ledc_stop(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t idle_level)
{
LEDC_CHECK(idle_level == 0 || idle_level == 1, "idle_level error", ESP_ERR_INVALID_ARG);
static uint32_t stop_level_mask = 0x0;
if (idle_level == 0){
stop_level_mask = stop_level_mask | 0x1 << channel;
}
else if (idle_level == 1){
stop_level_mask = stop_level_mask & ~(0x1 << channel);
}
pwm_stop(stop_level_mask);
return ESP_OK;
}
int periph_module_enable(int none)
{
return ESP_OK;
}

View File

@ -18,6 +18,8 @@
extern "C" {
#endif
#include "esp_err.h"
#define PERIPH_LEDC_MODULE (0)
#define LEDC_APB_CLK_HZ (APB_CLK_FREQ)
#define LEDC_REF_CLK_HZ (1*1000000)
#define LEDC_ERR_DUTY (0xFFFFFFFF)
@ -91,6 +93,7 @@ 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 (100Hz ~ 1KHz) */
@ -203,6 +206,25 @@ esp_err_t ledc_fade_func_install(int intr_alloc_flags);
*/
esp_err_t ledc_fade_func_uninstall(void);
/**
* @brief LEDC stop.
* Disable LEDC output, and set idle level
*
* @param speed_mode Select the LEDC speed_mode, high-speed mode and low-speed mode
* @param channel LEDC channel (0-7), select from ledc_channel_t
* @param idle_level Set output idle level after LEDC stops.
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t ledc_stop(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t idle_level);
/**
* it is an empty function
*/
int periph_module_enable(int none);
#ifdef __cplusplus
}
#endif

View File

@ -1,64 +1,76 @@
// Copyright 2018-2025 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.
/* LEDC (LED Controller) fade example
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#include "freertos/task.h"
#include "esp_err.h"
#include "esp_log.h"
#include "driver/ledc.h"
#include "esp_err.h"
#define LEDC_HS_CH0_GPIO (13)
#define LEDC_HS_CH1_GPIO (14)
#define LEDC_LS_CH2_GPIO (15)
#define LEDC_LS_CH3_GPIO (12)
/*
* About this example
*
* 1. Start with initializing LEDC module:
* a. Set the timer of LEDC first, this determines the frequency
* and resolution of PWM.
* b. Then set the LEDC channel you want to use,
* and bind with one of the timers.
*
* 2. You need first to install a default fade function,
* then you can use fade APIs.
*
* 3. You can also set a target duty directly without fading.
*
* 4. This example uses GPIO18/19/4/5 as LEDC output,
* and it will change the duty repeatedly.
*
* 5. GPIO18/19 are from high speed channel group.
* GPIO4/5 are from low speed channel group.
*
*/
#define LEDC_HS_TIMER LEDC_TIMER_0
#define LEDC_HS_MODE LEDC_HIGH_SPEED_MODE
#define LEDC_HS_CH0_GPIO (12)
#define LEDC_HS_CH0_CHANNEL LEDC_CHANNEL_0
#define LEDC_HS_CH1_GPIO (14)
#define LEDC_HS_CH1_CHANNEL LEDC_CHANNEL_1
#define LEDC_HS_CH0_CHANNEL LEDC_CHANNEL_0
#define LEDC_HS_CH1_CHANNEL LEDC_CHANNEL_1
#define LEDC_LS_CH2_CHANNEL LEDC_CHANNEL_2
#define LEDC_LS_CH3_CHANNEL LEDC_CHANNEL_3
#define LEDC_LS_TIMER LEDC_TIMER_1
#define LEDC_LS_MODE LEDC_LOW_SPEED_MODE
#define LEDC_LS_CH2_GPIO (4)
#define LEDC_LS_CH2_CHANNEL LEDC_CHANNEL_2
#define LEDC_LS_CH3_GPIO (15)
#define LEDC_LS_CH3_CHANNEL LEDC_CHANNEL_3
#define LEDC_TEST_CH_NUM (4)
#define LEDC_TEST_FREQ (1000) //1KHz
#define LEDC_TEST_DUTY (900) //duty = LEDC_TEST_DUTY / LEDC_TEST_PERIOD & LEDC_TEST_PERIOD = 1,000,000 / LEDC_TEST_FREQ
#define LEDC_TEST_FADE_TIME (3000)
static const char* TAG = "main";
#define LEDC_TEST_CH_NUM (4)
#define LEDC_TEST_DUTY (4096)
#define LEDC_TEST_FADE_TIME (3000)
void app_main()
{
int ch;
/*
* Prepare and set configuration of timers
* that will be used by LED Controller
*/
ledc_timer_config_t ledc_timer = {
.duty_resolution = LEDC_TIMER_1_BIT, // resolution of PWM duty(Invalid parameter, compatible with esp32 API)
.freq_hz = LEDC_TEST_FREQ, // frequency of PWM signal
.speed_mode = 0, // timer mode (Invalid parameter, compatible with esp32 API)
.timer_num = 0 // timer index (Invalid parameter, compatible with esp32 API)
.duty_resolution = LEDC_TIMER_13_BIT, // resolution of PWM duty
.freq_hz = 5000, // frequency of PWM signal
.speed_mode = LEDC_HS_MODE, // timer mode
.timer_num = LEDC_HS_TIMER // timer index
};
// Set configuration of timer0 for high speed channels
ledc_timer_config(&ledc_timer);
// Prepare and set configuration of timer1 for low speed channels
ledc_timer.speed_mode = LEDC_LS_MODE;
ledc_timer.timer_num = LEDC_LS_TIMER;
ledc_timer_config(&ledc_timer);
/*
* Prepare individual configuration
* for each channel of LED Controller
@ -68,31 +80,43 @@ void app_main()
* - GPIO number where LED is connected to
* - speed mode, either high or low
* - timer servicing selected channel
* Note: Speed_mode and timer_sel are only compatible with esp32,
* but it is not required in esp8266, so it can be set to 0 when
* using esp8266
* Note: if different channels use one timer,
* then frequency and bit_num of these channels
* will be the same
*/
ledc_channel_config_t ledc_channel[LEDC_TEST_CH_NUM] = {
{ .channel = LEDC_HS_CH0_CHANNEL,
.duty = 0,
.gpio_num = LEDC_HS_CH0_GPIO,
.speed_mode = 0,
.timer_sel = 0 },
{ .channel = LEDC_HS_CH1_CHANNEL,
.duty = 0,
.gpio_num = LEDC_HS_CH1_GPIO,
.speed_mode = 0,
.timer_sel = 0 },
{ .channel = LEDC_LS_CH2_CHANNEL,
.duty = 0,
.gpio_num = LEDC_LS_CH2_GPIO,
.speed_mode = 0,
.timer_sel = 0 },
{ .channel = LEDC_LS_CH3_CHANNEL,
.duty = 0,
.gpio_num = LEDC_LS_CH3_GPIO,
.speed_mode = 0,
.timer_sel = 0 },
{
.channel = LEDC_HS_CH0_CHANNEL,
.duty = 0,
.gpio_num = LEDC_HS_CH0_GPIO,
.speed_mode = LEDC_HS_MODE,
.hpoint = 0,
.timer_sel = LEDC_HS_TIMER
},
{
.channel = LEDC_HS_CH1_CHANNEL,
.duty = 0,
.gpio_num = LEDC_HS_CH1_GPIO,
.speed_mode = LEDC_HS_MODE,
.hpoint = 0,
.timer_sel = LEDC_HS_TIMER
},
{
.channel = LEDC_LS_CH2_CHANNEL,
.duty = 0,
.gpio_num = LEDC_LS_CH2_GPIO,
.speed_mode = LEDC_LS_MODE,
.hpoint = 0,
.timer_sel = LEDC_LS_TIMER
},
{
.channel = LEDC_LS_CH3_CHANNEL,
.duty = 0,
.gpio_num = LEDC_LS_CH3_GPIO,
.speed_mode = LEDC_LS_MODE,
.hpoint = 0,
.timer_sel = LEDC_LS_TIMER
},
};
// Set LED Controller with previously prepared configuration
@ -104,28 +128,36 @@ void app_main()
ledc_fade_func_install(0);
while (1) {
ESP_LOGI(TAG, "1. LEDC fade up to duty = %d\n", LEDC_TEST_DUTY);
printf("1. LEDC fade up to duty = %d\n", LEDC_TEST_DUTY);
for (ch = 0; ch < LEDC_TEST_CH_NUM; ch++) {
ledc_set_fade_with_time(ledc_channel[ch].speed_mode,
ledc_channel[ch].channel, LEDC_TEST_DUTY, LEDC_TEST_FADE_TIME);
}
for (ch = 0; ch < LEDC_TEST_CH_NUM; ch++) {
ledc_channel[ch].channel, LEDC_TEST_DUTY, LEDC_TEST_FADE_TIME);
ledc_fade_start(ledc_channel[ch].speed_mode,
ledc_channel[ch].channel, LEDC_FADE_NO_WAIT);
ledc_channel[ch].channel, LEDC_FADE_NO_WAIT);
}
vTaskDelay(LEDC_TEST_FADE_TIME / portTICK_PERIOD_MS);
vTaskDelay(LEDC_TEST_FADE_TIME / portTICK_PERIOD_MS);
ESP_LOGI(TAG, "2. LEDC fade down to duty = 0\n");
printf("2. LEDC fade down to duty = 0\n");
for (ch = 0; ch < LEDC_TEST_CH_NUM; ch++) {
ledc_set_fade_with_time(ledc_channel[ch].speed_mode,
ledc_channel[ch].channel, 0, LEDC_TEST_FADE_TIME);
}
for (ch = 0; ch < LEDC_TEST_CH_NUM; ch++) {
ledc_channel[ch].channel, 0, LEDC_TEST_FADE_TIME);
ledc_fade_start(ledc_channel[ch].speed_mode,
ledc_channel[ch].channel, LEDC_FADE_NO_WAIT);
ledc_channel[ch].channel, LEDC_FADE_NO_WAIT);
}
vTaskDelay(LEDC_TEST_FADE_TIME / portTICK_PERIOD_MS);
vTaskDelay(LEDC_TEST_FADE_TIME / portTICK_PERIOD_MS);
printf("3. LEDC set duty = %d without fade\n", LEDC_TEST_DUTY);
for (ch = 0; ch < LEDC_TEST_CH_NUM; ch++) {
ledc_set_duty(ledc_channel[ch].speed_mode, ledc_channel[ch].channel, LEDC_TEST_DUTY);
ledc_update_duty(ledc_channel[ch].speed_mode, ledc_channel[ch].channel);
}
vTaskDelay(1000 / portTICK_PERIOD_MS);
printf("4. LEDC set duty = 0 without fade\n");
for (ch = 0; ch < LEDC_TEST_CH_NUM; ch++) {
ledc_set_duty(ledc_channel[ch].speed_mode, ledc_channel[ch].channel, 0);
ledc_update_duty(ledc_channel[ch].speed_mode, ledc_channel[ch].channel);
}
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
}