kopia lustrzana https://github.com/espressif/esp-idf
ledc: Add a callback for LEDC fade end
This commit adds a feature where users can register a callback that is called when an LEDC fade completes.pull/7365/head
rodzic
16057d6c8b
commit
9d098cc9bd
|
@ -24,6 +24,38 @@ extern "C" {
|
|||
|
||||
typedef intr_handle_t ledc_isr_handle_t;
|
||||
|
||||
/**
|
||||
* @brief LEDC callback event type
|
||||
*/
|
||||
typedef enum {
|
||||
LEDC_FADE_END_EVT /**< LEDC fade end event */
|
||||
} ledc_cb_event_t;
|
||||
|
||||
/**
|
||||
* @brief LEDC callback parameter
|
||||
*/
|
||||
typedef struct {
|
||||
ledc_cb_event_t event; /**< Event name */
|
||||
uint32_t speed_mode; /**< Speed mode of the LEDC channel group */
|
||||
uint32_t channel; /**< LEDC channel (0 - LEDC_CHANNEL_MAX-1) */
|
||||
uint32_t duty; /**< LEDC current duty of the channel, the range of duty is [0, (2**duty_resolution) - 1] */
|
||||
} ledc_cb_param_t;
|
||||
|
||||
/**
|
||||
* @brief Type of LEDC event callback
|
||||
* @param param LEDC callback parameter
|
||||
* @param user_arg User registered data
|
||||
*/
|
||||
typedef bool (* ledc_cb_t)(const ledc_cb_param_t *param, void *user_arg);
|
||||
|
||||
/**
|
||||
* @brief Group of supported LEDC callbacks
|
||||
* @note The callbacks are all running under ISR environment
|
||||
*/
|
||||
typedef struct {
|
||||
ledc_cb_t fade_cb; /**< LEDC fade_end callback function */
|
||||
} ledc_cbs_t;
|
||||
|
||||
/**
|
||||
* @brief LEDC channel configuration
|
||||
* Configure LEDC channel with the given channel/output gpio_num/interrupt/source timer/frequency(Hz)/LEDC duty resolution
|
||||
|
@ -57,7 +89,7 @@ esp_err_t ledc_timer_config(const ledc_timer_config_t* timer_conf);
|
|||
* control one LEDC channel in different tasks at the same time.
|
||||
* A thread-safe version of API is ledc_set_duty_and_update
|
||||
* @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode.
|
||||
* @param channel LEDC channel (0-7), select from ledc_channel_t
|
||||
* @param channel LEDC channel (0 - LEDC_CHANNEL_MAX-1), select from ledc_channel_t
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
|
@ -72,7 +104,7 @@ esp_err_t ledc_update_duty(ledc_mode_t speed_mode, ledc_channel_t channel);
|
|||
*
|
||||
* @param gpio_num The LEDC output gpio
|
||||
* @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode.
|
||||
* @param ledc_channel LEDC channel (0-7), select from ledc_channel_t
|
||||
* @param ledc_channel LEDC channel (0 - LEDC_CHANNEL_MAX-1), select from ledc_channel_t
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
|
@ -85,7 +117,7 @@ esp_err_t ledc_set_pin(int gpio_num, ledc_mode_t speed_mode, ledc_channel_t ledc
|
|||
* Disable LEDC output, and set idle level
|
||||
*
|
||||
* @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode.
|
||||
* @param channel LEDC channel (0-7), select from ledc_channel_t
|
||||
* @param channel LEDC channel (0 - LEDC_CHANNEL_MAX-1), select from ledc_channel_t
|
||||
* @param idle_level Set output idle level after LEDC stops.
|
||||
*
|
||||
* @return
|
||||
|
@ -129,8 +161,8 @@ uint32_t ledc_get_freq(ledc_mode_t speed_mode, ledc_timer_t timer_num);
|
|||
* @note If a fade operation is running in progress on that channel, the driver would not allow it to be stopped.
|
||||
* Other duty operations will have to wait until the fade operation has finished.
|
||||
* @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode.
|
||||
* @param channel LEDC channel (0-7), select from ledc_channel_t
|
||||
* @param duty Set the LEDC duty, the range of duty setting is [0, (2**duty_resolution)]
|
||||
* @param channel LEDC channel (0 - LEDC_CHANNEL_MAX-1), select from ledc_channel_t
|
||||
* @param duty Set the LEDC duty, the range of duty setting is [0, (2**duty_resolution) - 1]
|
||||
* @param hpoint Set the LEDC hpoint value(max: 0xfffff)
|
||||
*
|
||||
* @return
|
||||
|
@ -143,7 +175,7 @@ esp_err_t ledc_set_duty_with_hpoint(ledc_mode_t speed_mode, ledc_channel_t chann
|
|||
* @brief LEDC get hpoint value, the counter value when the output is set high level.
|
||||
*
|
||||
* @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode.
|
||||
* @param channel LEDC channel (0-7), select from ledc_channel_t
|
||||
* @param channel LEDC channel (0 - LEDC_CHANNEL_MAX-1), select from ledc_channel_t
|
||||
* @return
|
||||
* - LEDC_ERR_VAL if parameter error
|
||||
* - Others Current hpoint value of LEDC channel
|
||||
|
@ -160,8 +192,8 @@ int ledc_get_hpoint(ledc_mode_t speed_mode, ledc_channel_t channel);
|
|||
* @note If a fade operation is running in progress on that channel, the driver would not allow it to be stopped.
|
||||
* Other duty operations will have to wait until the fade operation has finished.
|
||||
* @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode.
|
||||
* @param channel LEDC channel (0-7), select from ledc_channel_t
|
||||
* @param duty Set the LEDC duty, the range of duty setting is [0, (2**duty_resolution)]
|
||||
* @param channel LEDC channel (0 - LEDC_CHANNEL_MAX-1), select from ledc_channel_t
|
||||
* @param duty Set the LEDC duty, the range of duty setting is [0, (2**duty_resolution) - 1]
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
|
@ -173,7 +205,7 @@ esp_err_t ledc_set_duty(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t
|
|||
* @brief LEDC get duty
|
||||
*
|
||||
* @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode.
|
||||
* @param channel LEDC channel (0-7), select from ledc_channel_t
|
||||
* @param channel LEDC channel (0 - LEDC_CHANNEL_MAX-1), select from ledc_channel_t
|
||||
*
|
||||
* @return
|
||||
* - LEDC_ERR_DUTY if parameter error
|
||||
|
@ -187,8 +219,8 @@ uint32_t ledc_get_duty(ledc_mode_t speed_mode, ledc_channel_t channel);
|
|||
* @note If a fade operation is running in progress on that channel, the driver would not allow it to be stopped.
|
||||
* Other duty operations will have to wait until the fade operation has finished.
|
||||
* @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode.
|
||||
* @param channel LEDC channel (0-7), select from ledc_channel_t
|
||||
* @param duty Set the start of the gradient duty, the range of duty setting is [0, (2**duty_resolution)]
|
||||
* @param channel LEDC channel (0 - LEDC_CHANNEL_MAX-1), select from ledc_channel_t
|
||||
* @param duty Set the start of the gradient duty, the range of duty setting is [0, (2**duty_resolution) - 1]
|
||||
* @param fade_direction Set the direction of the gradient
|
||||
* @param step_num Set the number of the gradient
|
||||
* @param duty_cycle_num Set how many LEDC tick each time the gradient lasts
|
||||
|
@ -274,7 +306,7 @@ 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 channel group with specified speed mode. Note that not all targets support high speed mode.
|
||||
* @param channel LEDC channel index (0-7), select from ledc_channel_t
|
||||
* @param channel LEDC channel index (0 - LEDC_CHANNEL_MAX-1), select from ledc_channel_t
|
||||
* @param timer_sel LEDC timer index (0-3), select from ledc_timer_t
|
||||
*
|
||||
* @return
|
||||
|
@ -293,7 +325,7 @@ esp_err_t ledc_bind_channel_timer(ledc_mode_t speed_mode, ledc_channel_t channel
|
|||
* @note If a fade operation is running in progress on that channel, the driver would not allow it to be stopped.
|
||||
* Other duty operations will have to wait until the fade operation has finished.
|
||||
* @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode. ,
|
||||
* @param channel LEDC channel index (0-7), select from ledc_channel_t
|
||||
* @param channel LEDC channel index (0 - LEDC_CHANNEL_MAX-1), select from ledc_channel_t
|
||||
* @param target_duty Target duty of fading [0, (2**duty_resolution) - 1]
|
||||
* @param scale Controls the increase or decrease step scale.
|
||||
* @param cycle_num increase or decrease the duty every cycle_num cycles
|
||||
|
@ -316,8 +348,8 @@ esp_err_t ledc_set_fade_with_step(ledc_mode_t speed_mode, ledc_channel_t channel
|
|||
* @note If a fade operation is running in progress on that channel, the driver would not allow it to be stopped.
|
||||
* Other duty operations will have to wait until the fade operation has finished.
|
||||
* @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode. ,
|
||||
* @param channel LEDC channel index (0-7), select from ledc_channel_t
|
||||
* @param target_duty Target duty of fading.( 0 - (2 ** duty_resolution - 1)))
|
||||
* @param channel LEDC channel index (0 - LEDC_CHANNEL_MAX-1), select from ledc_channel_t
|
||||
* @param target_duty Target duty of fading [0, (2**duty_resolution) - 1]
|
||||
* @param max_fade_time_ms The maximum time of the fading ( ms ).
|
||||
*
|
||||
* @return
|
||||
|
@ -368,8 +400,8 @@ esp_err_t ledc_fade_start(ledc_mode_t speed_mode, ledc_channel_t channel, ledc_f
|
|||
* Other duty operations will have to wait until the fade operation has finished.
|
||||
*
|
||||
* @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode.
|
||||
* @param channel LEDC channel (0-7), select from ledc_channel_t
|
||||
* @param duty Set the LEDC duty, the range of duty setting is [0, (2**duty_resolution)]
|
||||
* @param channel LEDC channel (0 - LEDC_CHANNEL_MAX-1), select from ledc_channel_t
|
||||
* @param duty Set the LEDC duty, the range of duty setting is [0, (2**duty_resolution) - 1]
|
||||
* @param hpoint Set the LEDC hpoint value(max: 0xfffff)
|
||||
*
|
||||
*/
|
||||
|
@ -381,8 +413,8 @@ esp_err_t ledc_set_duty_and_update(ledc_mode_t speed_mode, ledc_channel_t channe
|
|||
* @note If a fade operation is running in progress on that channel, the driver would not allow it to be stopped.
|
||||
* Other duty operations will have to wait until the fade operation has finished.
|
||||
* @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode.
|
||||
* @param channel LEDC channel index (0-7), select from ledc_channel_t
|
||||
* @param target_duty Target duty of fading.( 0 - (2 ** duty_resolution - 1)))
|
||||
* @param channel LEDC channel index (0 - LEDC_CHANNEL_MAX-1), select from ledc_channel_t
|
||||
* @param target_duty Target duty of fading [0, (2**duty_resolution) - 1]
|
||||
* @param max_fade_time_ms The maximum time of the fading ( ms ).
|
||||
* @param fade_mode choose blocking or non-blocking mode
|
||||
* @return
|
||||
|
@ -399,7 +431,7 @@ esp_err_t ledc_set_fade_time_and_start(ledc_mode_t speed_mode, ledc_channel_t ch
|
|||
* @note If a fade operation is running in progress on that channel, the driver would not allow it to be stopped.
|
||||
* Other duty operations will have to wait until the fade operation has finished.
|
||||
* @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode.
|
||||
* @param channel LEDC channel index (0-7), select from ledc_channel_t
|
||||
* @param channel LEDC channel index (0 - LEDC_CHANNEL_MAX-1), select from ledc_channel_t
|
||||
* @param target_duty Target duty of fading [0, (2**duty_resolution) - 1]
|
||||
* @param scale Controls the increase or decrease step scale.
|
||||
* @param cycle_num increase or decrease the duty every cycle_num cycles
|
||||
|
@ -414,3 +446,18 @@ esp_err_t ledc_set_fade_step_and_start(ledc_mode_t speed_mode, ledc_channel_t ch
|
|||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief LEDC callback registration function
|
||||
* @note The callback is called from an ISR, it must never attempt to block, and any FreeRTOS API called must be ISR capable.
|
||||
* @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode.
|
||||
* @param channel LEDC channel index (0 - LEDC_CHANNEL_MAX-1), select from ledc_channel_t
|
||||
* @param cbs Group of LEDC callback functions
|
||||
* @param user_arg user registered data for the callback function
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_STATE Fade function not installed.
|
||||
* - ESP_FAIL Fade function init error
|
||||
*/
|
||||
esp_err_t ledc_cb_register(ledc_mode_t speed_mode, ledc_channel_t channel, ledc_cbs_t *cbs, void *user_arg);
|
||||
|
|
|
@ -37,6 +37,8 @@ typedef struct {
|
|||
#if CONFIG_SPIRAM_USE_MALLOC
|
||||
StaticQueue_t ledc_fade_sem_storage;
|
||||
#endif
|
||||
ledc_cb_t ledc_fade_callback;
|
||||
void *cb_user_arg;
|
||||
} ledc_fade_t;
|
||||
|
||||
typedef struct {
|
||||
|
@ -551,6 +553,7 @@ static inline void ledc_calc_fade_end_channel(uint32_t *fade_end_status, uint32_
|
|||
|
||||
void IRAM_ATTR ledc_fade_isr(void* arg)
|
||||
{
|
||||
bool cb_yield = false;
|
||||
portBASE_TYPE HPTaskAwoken = pdFALSE;
|
||||
uint32_t speed_mode = 0;
|
||||
uint32_t channel = 0;
|
||||
|
@ -576,17 +579,21 @@ void IRAM_ATTR ledc_fade_isr(void* arg)
|
|||
|
||||
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) {
|
||||
if (duty_cur == duty_tar || scale == 0) {
|
||||
xSemaphoreGiveFromISR(s_ledc_fade_rec[speed_mode][channel]->ledc_fade_sem, &HPTaskAwoken);
|
||||
|
||||
ledc_cb_param_t param = {
|
||||
.event = LEDC_FADE_END_EVT,
|
||||
.speed_mode = speed_mode,
|
||||
.channel = channel,
|
||||
.duty = duty_cur
|
||||
};
|
||||
ledc_cb_t fade_cb = s_ledc_fade_rec[speed_mode][channel]->ledc_fade_callback;
|
||||
if (fade_cb) {
|
||||
cb_yield |= fade_cb(¶m, s_ledc_fade_rec[speed_mode][channel]->cb_user_arg);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
int cycle = s_ledc_fade_rec[speed_mode][channel]->cycle_num;
|
||||
|
@ -618,6 +625,9 @@ void IRAM_ATTR ledc_fade_isr(void* arg)
|
|||
portEXIT_CRITICAL(&ledc_spinlock);
|
||||
}
|
||||
}
|
||||
if (HPTaskAwoken == pdTRUE || cb_yield) {
|
||||
portYIELD_FROM_ISR();
|
||||
}
|
||||
}
|
||||
|
||||
static esp_err_t ledc_fade_channel_deinit(ledc_mode_t speed_mode, ledc_channel_t channel)
|
||||
|
@ -825,6 +835,17 @@ void ledc_fade_func_uninstall(void)
|
|||
return;
|
||||
}
|
||||
|
||||
esp_err_t ledc_cb_register(ledc_mode_t speed_mode, ledc_channel_t channel, ledc_cbs_t *cbs, void *user_arg)
|
||||
{
|
||||
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);
|
||||
LEDC_CHECK(ledc_fade_channel_init_check(speed_mode, channel) == ESP_OK , LEDC_FADE_INIT_ERROR_STR, ESP_FAIL);
|
||||
s_ledc_fade_rec[speed_mode][channel]->ledc_fade_callback = cbs->fade_cb;
|
||||
s_ledc_fade_rec[speed_mode][channel]->cb_user_arg = user_arg;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* The functions below are thread-safe version of APIs for duty and fade control.
|
||||
* These APIs can be called from different tasks.
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
#include "freertos/task.h"
|
||||
#include "driver/ledc.h"
|
||||
#include "esp_err.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/semphr.h"
|
||||
|
||||
/*
|
||||
* About this example
|
||||
|
@ -43,7 +45,7 @@
|
|||
#endif
|
||||
#define LEDC_LS_TIMER LEDC_TIMER_1
|
||||
#define LEDC_LS_MODE LEDC_LOW_SPEED_MODE
|
||||
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32C3
|
||||
#if !CONFIG_IDF_TARGET_ESP32
|
||||
#define LEDC_LS_CH0_GPIO (18)
|
||||
#define LEDC_LS_CH0_CHANNEL LEDC_CHANNEL_0
|
||||
#define LEDC_LS_CH1_GPIO (19)
|
||||
|
@ -58,6 +60,23 @@
|
|||
#define LEDC_TEST_DUTY (4000)
|
||||
#define LEDC_TEST_FADE_TIME (3000)
|
||||
|
||||
/*
|
||||
* This callback function will be called when fade operation has ended
|
||||
* Use callback only if you are aware it is being called inside an ISR
|
||||
* Otherwise, you can use a semaphore to unblock tasks
|
||||
*/
|
||||
static bool cb_ledc_fade_end_event(const ledc_cb_param_t *param, void *user_arg)
|
||||
{
|
||||
portBASE_TYPE taskAwoken = pdFALSE;
|
||||
|
||||
if (param->event == LEDC_FADE_END_EVT) {
|
||||
SemaphoreHandle_t counting_sem = (SemaphoreHandle_t) user_arg;
|
||||
xSemaphoreGiveFromISR(counting_sem, &taskAwoken);
|
||||
}
|
||||
|
||||
return (taskAwoken == pdTRUE);
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
int ch;
|
||||
|
@ -114,7 +133,7 @@ void app_main(void)
|
|||
.timer_sel = LEDC_HS_TIMER,
|
||||
.flags.output_invert = 0
|
||||
},
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32C3
|
||||
#else
|
||||
{
|
||||
.channel = LEDC_LS_CH0_CHANNEL,
|
||||
.duty = 0,
|
||||
|
@ -161,6 +180,14 @@ void app_main(void)
|
|||
|
||||
// Initialize fade service.
|
||||
ledc_fade_func_install(0);
|
||||
ledc_cbs_t callbacks = {
|
||||
.fade_cb = cb_ledc_fade_end_event
|
||||
};
|
||||
SemaphoreHandle_t counting_sem = xSemaphoreCreateCounting(LEDC_TEST_CH_NUM, 0);
|
||||
|
||||
for (ch = 0; ch < LEDC_TEST_CH_NUM; ch++) {
|
||||
ledc_cb_register(ledc_channel[ch].speed_mode, ledc_channel[ch].channel, &callbacks, (void *) counting_sem);
|
||||
}
|
||||
|
||||
while (1) {
|
||||
printf("1. LEDC fade up to duty = %d\n", LEDC_TEST_DUTY);
|
||||
|
@ -170,7 +197,10 @@ void app_main(void)
|
|||
ledc_fade_start(ledc_channel[ch].speed_mode,
|
||||
ledc_channel[ch].channel, LEDC_FADE_NO_WAIT);
|
||||
}
|
||||
vTaskDelay(LEDC_TEST_FADE_TIME / portTICK_PERIOD_MS);
|
||||
|
||||
for (int i = 0; i < LEDC_TEST_CH_NUM; i++) {
|
||||
xSemaphoreTake(counting_sem, portMAX_DELAY);
|
||||
}
|
||||
|
||||
printf("2. LEDC fade down to duty = 0\n");
|
||||
for (ch = 0; ch < LEDC_TEST_CH_NUM; ch++) {
|
||||
|
@ -179,7 +209,10 @@ void app_main(void)
|
|||
ledc_fade_start(ledc_channel[ch].speed_mode,
|
||||
ledc_channel[ch].channel, LEDC_FADE_NO_WAIT);
|
||||
}
|
||||
vTaskDelay(LEDC_TEST_FADE_TIME / portTICK_PERIOD_MS);
|
||||
|
||||
for (int i = 0; i < LEDC_TEST_CH_NUM; i++) {
|
||||
xSemaphoreTake(counting_sem, portMAX_DELAY);
|
||||
}
|
||||
|
||||
printf("3. LEDC set duty = %d without fade\n", LEDC_TEST_DUTY);
|
||||
for (ch = 0; ch < LEDC_TEST_CH_NUM; ch++) {
|
||||
|
|
Ładowanie…
Reference in New Issue