mirror of
https://github.com/espressif/ESP8266_RTOS_SDK.git
synced 2025-05-22 01:27:11 +08:00
feature(ledc):add ledc about esp8266
This commit is contained in:
@ -48,7 +48,8 @@ else()
|
||||
"driver/spi.c"
|
||||
"driver/uart.c"
|
||||
"driver/ir_tx.c"
|
||||
"driver/ir_rx.c")
|
||||
"driver/ir_rx.c"
|
||||
"driver/ledc.c")
|
||||
|
||||
set(include_dirs "include" "include/driver")
|
||||
|
||||
|
317
components/esp8266/driver/ledc.c
Normal file
317
components/esp8266/driver/ledc.c
Normal file
@ -0,0 +1,317 @@
|
||||
// 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.
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "esp_err.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/ledc.h"
|
||||
#include "driver/pwm.h"
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "freertos/task.h"
|
||||
|
||||
#define LEDC_PRIORITY (2)
|
||||
#define LEDC_CHANNEL_MAX (8)
|
||||
#define LEDC_STEP_TIME (10)
|
||||
#define LEDC_FLAG_ON (1)
|
||||
#define LEDC_FLAG_OFF (0)
|
||||
#define LEDC_TASK_STACK_DEPTH (1024)
|
||||
|
||||
static const char* LEDC_TAG = "ledc";
|
||||
|
||||
#define LEDC_CHECK(a, str, ret) \
|
||||
if (!(a)) { \
|
||||
ESP_LOGE(LEDC_TAG, "%s:%d (%s):%s", __FILE__, __LINE__, __FUNCTION__, str); \
|
||||
return (ret); \
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
ledc_channel_t channel_num; // Channel
|
||||
uint32_t duty_p; // Duty at present
|
||||
uint32_t duty; // Duty what we want to
|
||||
uint32_t step_duty; // Duty/10ms means every 10ms change step_duty
|
||||
uint32_t step_01duty; // 0.1 of the duty value
|
||||
uint32_t step_001duty; // 0.01 of the duty value
|
||||
uint32_t gpio_num;//gpio pins
|
||||
int16_t phase; //init phase
|
||||
int fade_time; // Time to duty by fade
|
||||
} ledc_obj_t;
|
||||
|
||||
QueueHandle_t channel_queue;
|
||||
static ledc_obj_t *p_ledc_obj[LEDC_CHANNEL_MAX] = { 0 };
|
||||
static uint8_t ledc_usr_channel_max = 0; //This is to allocate some channels according to the channel used by the user
|
||||
static uint32_t ledc_period;
|
||||
|
||||
/**
|
||||
* @brief set down ledc duty by step
|
||||
*
|
||||
* @param channel set channel to change duty
|
||||
* @param flag tells the caller whether the set duty cycle has been reached
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
*/
|
||||
static esp_err_t ledc_fade_down(ledc_channel_t channel, uint8_t* flag);
|
||||
|
||||
/**
|
||||
* @brief set up ledc duty by step
|
||||
*
|
||||
* @param channel set channel to change duty
|
||||
* @param flag tells the caller whether the set duty cycle has been reached
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
*/
|
||||
static esp_err_t ledc_fade_up(ledc_channel_t channel, uint8_t* flag);
|
||||
|
||||
esp_err_t ledc_timer_config(const ledc_timer_config_t* timer_conf)
|
||||
{
|
||||
// Just freq_hz is useful
|
||||
// Hz to period
|
||||
LEDC_CHECK(timer_conf != NULL, "time_conf error", ESP_ERR_INVALID_ARG);
|
||||
|
||||
ledc_period = 1000000 / timer_conf->freq_hz;
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
// The difference between the current duty cycle and the target duty cycle
|
||||
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);
|
||||
|
||||
p_ledc_obj[ledc_channel]->channel_num = ledc_channel;
|
||||
p_ledc_obj[ledc_channel]->duty = ledc_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);
|
||||
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);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t ledc_update_duty(ledc_mode_t speed_mode, ledc_channel_t ledc_channel)
|
||||
{
|
||||
// send the queue
|
||||
LEDC_CHECK(ledc_channel < LEDC_CHANNEL_MAX, "ledc_channel error", ESP_ERR_INVALID_ARG);
|
||||
|
||||
uint8_t ret = xQueueSend(channel_queue, &ledc_channel, 0);
|
||||
if (ret != pdPASS) {
|
||||
ESP_LOGE(LEDC_TAG, "xQueueSend err\r\n");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t ledc_set_fade_with_time(ledc_mode_t speed_mode, ledc_channel_t ledc_channel, uint32_t ledc_duty, int ledc_fade_time)
|
||||
{
|
||||
// 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);
|
||||
|
||||
p_ledc_obj[ledc_channel]->channel_num = ledc_channel;
|
||||
p_ledc_obj[ledc_channel]->duty = ledc_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));
|
||||
|
||||
p_ledc_obj[ledc_channel]->step_duty = duty_value / (ledc_fade_time / LEDC_STEP_TIME);
|
||||
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;
|
||||
|
||||
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);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t ledc_fade_start(ledc_mode_t speed_mode, ledc_channel_t ledc_channel, ledc_fade_mode_t fade_mode)
|
||||
{
|
||||
LEDC_CHECK(ledc_channel < LEDC_CHANNEL_MAX, "ledc_channel error", ESP_ERR_INVALID_ARG);
|
||||
|
||||
esp_err_t ret;
|
||||
ret = ledc_update_duty(speed_mode, ledc_channel);
|
||||
if (ret == ESP_FAIL) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
if (fade_mode == LEDC_FADE_WAIT_DONE) {
|
||||
vTaskDelay(p_ledc_obj[ledc_channel]->fade_time / portTICK_PERIOD_MS);
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t ledc_channel_config(const ledc_channel_config_t* ledc_conf)
|
||||
{
|
||||
LEDC_CHECK(ledc_conf != NULL, "ledc_conf error", ESP_ERR_INVALID_ARG);
|
||||
LEDC_CHECK( ledc_conf->duty <= ledc_period, "ledc_duty error", ESP_ERR_INVALID_ARG);
|
||||
|
||||
if (p_ledc_obj[ledc_usr_channel_max] == NULL){
|
||||
p_ledc_obj[ledc_usr_channel_max] = (ledc_obj_t *)calloc(1, sizeof(ledc_obj_t));
|
||||
if (p_ledc_obj[ledc_usr_channel_max] == NULL){
|
||||
ESP_LOGE(LEDC_TAG, "LEDC driver malloc error");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
}
|
||||
p_ledc_obj[ledc_usr_channel_max]->gpio_num = ledc_conf->gpio_num;
|
||||
p_ledc_obj[ledc_usr_channel_max]->duty = ledc_conf->duty;
|
||||
ledc_usr_channel_max++;
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t ledc_fade_up(ledc_channel_t channel, uint8_t* flag)
|
||||
{
|
||||
LEDC_CHECK(flag != NULL, "flag error", ESP_ERR_INVALID_ARG);
|
||||
LEDC_CHECK(channel < LEDC_CHANNEL_MAX, "ledc_channel error", ESP_ERR_INVALID_ARG);
|
||||
|
||||
static uint8_t i[LEDC_CHANNEL_MAX] = { 0 };
|
||||
uint32_t duty_value = 0;
|
||||
|
||||
duty_value = (i[channel] % 10 == 5 ? p_ledc_obj[channel]->step_duty + p_ledc_obj[channel]->step_01duty : p_ledc_obj[channel]->step_duty);
|
||||
duty_value += (i[channel] == 50 ? p_ledc_obj[channel]->step_001duty : 0);
|
||||
|
||||
if (p_ledc_obj[channel]->duty_p < p_ledc_obj[channel]->duty) {
|
||||
if (p_ledc_obj[channel]->duty_p + duty_value > p_ledc_obj[channel]->duty) {
|
||||
p_ledc_obj[channel]->duty_p = p_ledc_obj[channel]->duty;
|
||||
} else {
|
||||
p_ledc_obj[channel]->duty_p += duty_value;
|
||||
}
|
||||
pwm_set_duty(channel, p_ledc_obj[channel]->duty_p);
|
||||
pwm_start();
|
||||
i[channel]++;
|
||||
if (i[channel] == 100) {
|
||||
i[channel] = 0;
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
esp_err_t ledc_fade_down(ledc_channel_t channel, uint8_t* flag)
|
||||
{
|
||||
LEDC_CHECK(flag != NULL, "flag error", ESP_ERR_INVALID_ARG);
|
||||
LEDC_CHECK(channel < LEDC_CHANNEL_MAX, "ledc_channel error", ESP_ERR_INVALID_ARG);
|
||||
|
||||
static uint8_t i[LEDC_CHANNEL_MAX] = { 0 };
|
||||
uint32_t duty_value = 0;
|
||||
|
||||
duty_value = (i[channel] % 10 == 5 ? p_ledc_obj[channel]->step_duty + p_ledc_obj[channel]->step_01duty : p_ledc_obj[channel]->step_duty);
|
||||
duty_value += (i[channel] == 50 ? p_ledc_obj[channel]->step_001duty : 0);
|
||||
|
||||
if (p_ledc_obj[channel]->duty_p > p_ledc_obj[channel]->duty) {
|
||||
// it is more smart than 'p_ledc_obj[channel].duty_p - p_ledc_obj[channel].step_duty < p_ledc_obj[channel].duty'
|
||||
if (p_ledc_obj[channel]->duty_p < p_ledc_obj[channel]->duty + duty_value) {
|
||||
p_ledc_obj[channel]->duty_p = p_ledc_obj[channel]->duty;
|
||||
} else {
|
||||
p_ledc_obj[channel]->duty_p -= duty_value;
|
||||
}
|
||||
pwm_set_duty(channel, p_ledc_obj[channel]->duty_p);
|
||||
pwm_start();
|
||||
i[channel]++;
|
||||
if (i[channel] == 100) {
|
||||
i[channel] = 0;
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
// Complete message queue reception while changing duty cycle
|
||||
static void ledc_task(void* pvParameters)
|
||||
{
|
||||
ledc_channel_t channel;
|
||||
uint8_t i;
|
||||
uint8_t flag[LEDC_CHANNEL_MAX] = { 0 };
|
||||
|
||||
while (1) {
|
||||
|
||||
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++) {
|
||||
if (flag[i] == LEDC_FLAG_ON) {
|
||||
if (p_ledc_obj[i]->duty_p < p_ledc_obj[i]->duty) {
|
||||
ledc_fade_up(i, &flag[i]);
|
||||
} else {
|
||||
ledc_fade_down(i, &flag[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
xTaskResumeAll();
|
||||
vTaskDelay(LEDC_STEP_TIME / portTICK_PERIOD_MS);
|
||||
}
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
esp_err_t ledc_fade_func_install(int intr_alloc_flags)
|
||||
{
|
||||
int16_t ledc_phase[LEDC_CHANNEL_MAX] = {0};
|
||||
uint32_t ledc_duty[LEDC_CHANNEL_MAX] = {0};
|
||||
uint32_t ledc_gpio_num[LEDC_CHANNEL_MAX] = {0};
|
||||
|
||||
for (int i = 0; i < ledc_usr_channel_max; i++){
|
||||
ledc_gpio_num[i] = p_ledc_obj[i]->gpio_num;
|
||||
ledc_duty[i] = p_ledc_obj[i]->duty;
|
||||
}
|
||||
|
||||
LEDC_CHECK(ledc_usr_channel_max < LEDC_CHANNEL_MAX, "flag error", ESP_ERR_INVALID_ARG);
|
||||
pwm_init(ledc_period, ledc_duty, ledc_usr_channel_max, ledc_gpio_num);
|
||||
ESP_LOGI(LEDC_TAG, "ledc_usr_channel_max:%d", ledc_usr_channel_max);
|
||||
for (int i = 0; i < ledc_usr_channel_max; i++) {
|
||||
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) {
|
||||
ESP_LOGE(LEDC_TAG, "xQueueCreate err\r\n");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
xTaskCreate(ledc_task, "ledc_task", LEDC_TASK_STACK_DEPTH, NULL, LEDC_PRIORITY, NULL);
|
||||
|
||||
return pwm_start();
|
||||
}
|
||||
|
||||
esp_err_t ledc_fade_func_uninstall(void)
|
||||
{
|
||||
for (int i = 0; i < ledc_usr_channel_max; i++){
|
||||
free(p_ledc_obj[i]);
|
||||
p_ledc_obj[i] = NULL;
|
||||
}
|
||||
return pwm_stop(0x00);
|
||||
}
|
208
components/esp8266/include/driver/ledc.h
Normal file
208
components/esp8266/include/driver/ledc.h
Normal file
@ -0,0 +1,208 @@
|
||||
// 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#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 {
|
||||
LEDC_HIGH_SPEED_MODE = 0, /*!< LEDC high speed speed_mode */
|
||||
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_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 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_t timer_num; /*!< The timer source of channel (0 - 3) */
|
||||
uint32_t freq_hz; /*!< LEDC timer frequency (100Hz ~ 1KHz) */
|
||||
} ledc_timer_config_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; /*!< Invalid parameter, compatible with esp32 API. Configure interrupt, 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; /*!< Invalid parameter, compatible with esp32 API. Configure interrupt,Fade interrupt enable or Fade interrupt disable */
|
||||
ledc_timer_t timer_sel; /*!< Invalid parameter, compatible with esp32 API. 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; /*!< Invalid parameter, compatible with esp32 API.LEDC channel hpoint value, the max value is 0xfffff */
|
||||
} ledc_channel_config_t;
|
||||
|
||||
/**
|
||||
* @brief set ledc duty
|
||||
*
|
||||
* @param speed_mode unnecessary parameters, just for code unity
|
||||
* @param ledc_channel ledc channel num
|
||||
* @param ledc_duty set the ledc duty you want
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
*/
|
||||
esp_err_t ledc_set_duty(ledc_mode_t speed_mode, ledc_channel_t ledc_channel, uint32_t ledc_duty);
|
||||
|
||||
/**
|
||||
* @brief update ledc duty
|
||||
*
|
||||
* @param speed_mode unnecessary parameters, just for code unity
|
||||
* @param ledc_channel ledc channel num
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_FAIL IO error
|
||||
*/
|
||||
esp_err_t ledc_update_duty(ledc_mode_t speed_mode, ledc_channel_t ledc_channel);
|
||||
|
||||
/**
|
||||
* @brief set ledc duty by fade
|
||||
*
|
||||
* @param speed_mode unnecessary parameters, just for code unity
|
||||
* @param ledc_channel ledc channel num
|
||||
* @param ledc_duty set ledc duty
|
||||
* @param ledc_fade_time set ledc fade time
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
*/
|
||||
esp_err_t ledc_set_fade_with_time(ledc_mode_t speed_mode, ledc_channel_t ledc_channel, uint32_t ledc_duty, int ledc_fade_time);
|
||||
|
||||
/**
|
||||
* @brief start change ledc duty by fade
|
||||
* @param speed_mode unnecessary parameters, just for code unity
|
||||
* @param ledc_channel ledc channel num
|
||||
* @param fade_mode set fade mode, for example set LEDC_FADE_NO_WAIT means LEDC fade function will return immediately
|
||||
* set LEDC_FADE_WAIT_DONE means LEDC fade function will block until fading to the target duty
|
||||
*
|
||||
*@return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_FAIL IO error
|
||||
*/
|
||||
esp_err_t ledc_fade_start(ledc_mode_t speed_mode, ledc_channel_t ledc_channel, ledc_fade_mode_t fade_mode);
|
||||
|
||||
/**
|
||||
* @brief LEDC channel configuration
|
||||
* Configure LEDC channel with the given channel/output gpio_num/interrupt/source timer/frequency(Hz)/LEDC duty resolution
|
||||
*
|
||||
* @param ledc_conf Pointer of LEDC channel configure struct
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
*/
|
||||
esp_err_t ledc_channel_config(const ledc_channel_config_t* ledc_conf);
|
||||
|
||||
/**
|
||||
* @brief LEDC timer configuration
|
||||
* Configure LEDC timer with the given source timer/frequency(Hz)/duty_resolution
|
||||
*
|
||||
* @param timer_conf Pointer of LEDC timer configure struct
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
*/
|
||||
esp_err_t ledc_timer_config(const ledc_timer_config_t* timer_conf);
|
||||
|
||||
/**
|
||||
* @brief Install LEDC fade function. This function will occupy interrupt of LEDC module.
|
||||
* @param intr_alloc_flags unnecessary parameters, just for code unity, maybe will be used later
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_STATE Fade function already installed.
|
||||
*/
|
||||
esp_err_t ledc_fade_func_install(int intr_alloc_flags);
|
||||
|
||||
/**
|
||||
* @brief Uninstall LEDC fade function.
|
||||
*
|
||||
*/
|
||||
esp_err_t ledc_fade_func_uninstall(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
6
examples/peripherals/ledc/CMakeLists.txt
Normal file
6
examples/peripherals/ledc/CMakeLists.txt
Normal file
@ -0,0 +1,6 @@
|
||||
# The following four lines of boilerplate have to be in your project's CMakeLists
|
||||
# in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(ledc)
|
9
examples/peripherals/ledc/Makefile
Normal file
9
examples/peripherals/ledc/Makefile
Normal file
@ -0,0 +1,9 @@
|
||||
#
|
||||
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
|
||||
# project subdirectory.
|
||||
#
|
||||
|
||||
PROJECT_NAME := ledc
|
||||
|
||||
include $(IDF_PATH)/make/project.mk
|
||||
|
85
examples/peripherals/ledc/README.md
Normal file
85
examples/peripherals/ledc/README.md
Normal file
@ -0,0 +1,85 @@
|
||||
# _ledc Example_
|
||||
|
||||
- Ledc is implemented by pwm, and this example will show you how to use ledc module by running four channels, but this is only designed to be compatible with the ESP32 ledc interface, many parameters are actually invalid.
|
||||
- Observe ledc signal with logic analyzer or oscilloscope.
|
||||
- Since ledc is based on PWM, using ledc will occupy PWM channel.
|
||||
- Since the step value of the gradient is 10ms, there may be an error of about 10ms between different channels.
|
||||
|
||||
## Pin assignment
|
||||
|
||||
* GPIO13 is assigned as the LEDC_HS_CH0_GPIO .
|
||||
* GPIO14 is assigned as the LEDC_HS_CH1_GPIO .
|
||||
* GPIO15 is assigned as the LEDC_HS_CH2_GPIO .
|
||||
* GPIO12 is assigned as the LEDC_HS_CH3_GPIO .
|
||||
|
||||
## How to use example
|
||||
|
||||
### Hardware Required
|
||||
|
||||
- Connection:
|
||||
- Connect the ledc channel to a logic analyzer or oscilloscope.
|
||||
|
||||
### Configure the project
|
||||
|
||||
```
|
||||
make menuconfig
|
||||
```
|
||||
|
||||
- Set serial port under Serial Flasher Options.
|
||||
|
||||
### Build and Flash
|
||||
|
||||
Build the project and flash it to the board, then run monitor tool to view serial output:
|
||||
|
||||
```
|
||||
make -j4 flash monitor
|
||||
```
|
||||
|
||||
(To exit the serial monitor, type `Ctrl-]`.)
|
||||
|
||||
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
|
||||
|
||||
## Example Output
|
||||
|
||||
```
|
||||
|
||||
I (497) gpio: GPIO[12]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0
|
||||
I (507) gpio: GPIO[13]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0
|
||||
I (517) gpio: GPIO[14]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0
|
||||
I (527) gpio: GPIO[15]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0
|
||||
I (547) pwm: --- PWM v3.2
|
||||
|
||||
I (547) ledc: ledc_channel_max:4
|
||||
|
||||
I (557) ledc: gpio:13
|
||||
|
||||
I (567) ledc: gpio:14
|
||||
|
||||
I (567) ledc: gpio:15
|
||||
|
||||
I (567) ledc: gpio:12
|
||||
|
||||
I (577) main: 1. LEDC fade up to duty = 980
|
||||
|
||||
I (587) ledc: channel_num = 0 | duty = 980; duty_p = 0 | step_duty = 3 | step_01duty = 2 | step_001duty = 6
|
||||
|
||||
I (597) ledc: channel_num = 1 | duty = 980; duty_p = 0 | step_duty = 3 | step_01duty = 2 | step_001duty = 6
|
||||
|
||||
I (617) ledc: channel_num = 2 | duty = 980; duty_p = 0 | step_duty = 3 | step_01duty = 2 | step_001duty = 6
|
||||
|
||||
I (637) ledc: channel_num = 3 | duty = 980; duty_p = 0 | step_duty = 3 | step_01duty = 2 | step_001duty = 6
|
||||
|
||||
I (647) ledc: channel0 is start
|
||||
I (657) ledc: channel1 is start
|
||||
I (657) ledc: channel2 is start
|
||||
I (667) ledc: channel3 is start
|
||||
I (3677) ledc: channel0 is end
|
||||
I (3677) ledc: channel1 is end
|
||||
I (3677) ledc: channel2 is end
|
||||
I (3677) ledc: channel3 is end
|
||||
|
||||
```
|
||||
|
||||
- WAVE FORM:
|
||||
|
||||

|
3
examples/peripherals/ledc/main/CMakeLists.txt
Normal file
3
examples/peripherals/ledc/main/CMakeLists.txt
Normal file
@ -0,0 +1,3 @@
|
||||
set(COMPONENT_SRCS "ledc_example_main.c")
|
||||
|
||||
register_component()
|
3
examples/peripherals/ledc/main/component.mk
Normal file
3
examples/peripherals/ledc/main/component.mk
Normal file
@ -0,0 +1,3 @@
|
||||
#
|
||||
# Main Makefile. This is basically the same as a component makefile.
|
||||
#
|
131
examples/peripherals/ledc/main/ledc_example_main.c
Normal file
131
examples/peripherals/ledc/main/ledc_example_main.c
Normal file
@ -0,0 +1,131 @@
|
||||
// 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.
|
||||
|
||||
#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"
|
||||
|
||||
#define LEDC_HS_CH0_GPIO (13)
|
||||
#define LEDC_HS_CH1_GPIO (14)
|
||||
#define LEDC_LS_CH2_GPIO (15)
|
||||
#define LEDC_LS_CH3_GPIO (12)
|
||||
|
||||
#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_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";
|
||||
|
||||
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)
|
||||
};
|
||||
// Set configuration of timer0 for high speed channels
|
||||
ledc_timer_config(&ledc_timer);
|
||||
|
||||
/*
|
||||
* Prepare individual configuration
|
||||
* for each channel of LED Controller
|
||||
* by selecting:
|
||||
* - controller's channel number
|
||||
* - output duty cycle, set initially to 0
|
||||
* - 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
|
||||
*/
|
||||
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 },
|
||||
};
|
||||
|
||||
// Set LED Controller with previously prepared configuration
|
||||
for (ch = 0; ch < LEDC_TEST_CH_NUM; ch++) {
|
||||
ledc_channel_config(&ledc_channel[ch]);
|
||||
}
|
||||
|
||||
// Initialize fade service.
|
||||
ledc_fade_func_install(0);
|
||||
|
||||
while (1) {
|
||||
ESP_LOGI(TAG, "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_fade_start(ledc_channel[ch].speed_mode,
|
||||
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");
|
||||
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_fade_start(ledc_channel[ch].speed_mode,
|
||||
ledc_channel[ch].channel, LEDC_FADE_NO_WAIT);
|
||||
}
|
||||
vTaskDelay(LEDC_TEST_FADE_TIME / portTICK_PERIOD_MS);
|
||||
vTaskDelay(LEDC_TEST_FADE_TIME / portTICK_PERIOD_MS);
|
||||
}
|
||||
}
|
BIN
examples/peripherals/ledc/wave.png
Normal file
BIN
examples/peripherals/ledc/wave.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
Reference in New Issue
Block a user