/* 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 #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "driver/ledc.h" #include "esp_err.h" #include "freertos/FreeRTOS.h" #include "freertos/semphr.h" /* * 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. * */ #if CONFIG_IDF_TARGET_ESP32 #define LEDC_HS_TIMER LEDC_TIMER_0 #define LEDC_HS_MODE LEDC_HIGH_SPEED_MODE #define LEDC_HS_CH0_GPIO (18) #define LEDC_HS_CH0_CHANNEL LEDC_CHANNEL_0 #define LEDC_HS_CH1_GPIO (19) #define LEDC_HS_CH1_CHANNEL LEDC_CHANNEL_1 #endif #define LEDC_LS_TIMER LEDC_TIMER_1 #define LEDC_LS_MODE LEDC_LOW_SPEED_MODE #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) #define LEDC_LS_CH1_CHANNEL LEDC_CHANNEL_1 #endif #define LEDC_LS_CH2_GPIO (4) #define LEDC_LS_CH2_CHANNEL LEDC_CHANNEL_2 #define LEDC_LS_CH3_GPIO (5) #define LEDC_LS_CH3_CHANNEL LEDC_CHANNEL_3 #define LEDC_TEST_CH_NUM (4) #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; /* * Prepare and set configuration of timers * that will be used by LED Controller */ ledc_timer_config_t ledc_timer = { .duty_resolution = LEDC_TIMER_13_BIT, // resolution of PWM duty .freq_hz = 5000, // frequency of PWM signal .speed_mode = LEDC_LS_MODE, // timer mode .timer_num = LEDC_LS_TIMER, // timer index .clk_cfg = LEDC_AUTO_CLK, // Auto select the source clock }; // Set configuration of timer0 for high speed channels ledc_timer_config(&ledc_timer); #ifdef CONFIG_IDF_TARGET_ESP32 // Prepare and set configuration of timer1 for low speed channels ledc_timer.speed_mode = LEDC_HS_MODE; ledc_timer.timer_num = LEDC_HS_TIMER; ledc_timer_config(&ledc_timer); #endif /* * 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: 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] = { #if CONFIG_IDF_TARGET_ESP32 { .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, .flags.output_invert = 0 }, { .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, .flags.output_invert = 0 }, #else { .channel = LEDC_LS_CH0_CHANNEL, .duty = 0, .gpio_num = LEDC_LS_CH0_GPIO, .speed_mode = LEDC_LS_MODE, .hpoint = 0, .timer_sel = LEDC_LS_TIMER, .flags.output_invert = 0 }, { .channel = LEDC_LS_CH1_CHANNEL, .duty = 0, .gpio_num = LEDC_LS_CH1_GPIO, .speed_mode = LEDC_LS_MODE, .hpoint = 0, .timer_sel = LEDC_LS_TIMER, .flags.output_invert = 0 }, #endif { .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, .flags.output_invert = 1 }, { .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, .flags.output_invert = 1 }, }; // 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); 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); 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); ledc_fade_start(ledc_channel[ch].speed_mode, ledc_channel[ch].channel, LEDC_FADE_NO_WAIT); } 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++) { ledc_set_fade_with_time(ledc_channel[ch].speed_mode, 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); } 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++) { 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); } }