1 /* LEDC (LED Controller) fade example
2 
3    This example code is in the Public Domain (or CC0 licensed, at your option.)
4 
5    Unless required by applicable law or agreed to in writing, this
6    software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
7    CONDITIONS OF ANY KIND, either express or implied.
8 */
9 #include <stdio.h>
10 #include "freertos/FreeRTOS.h"
11 #include "freertos/task.h"
12 #include "driver/ledc.h"
13 #include "esp_err.h"
14 #include "freertos/FreeRTOS.h"
15 #include "freertos/semphr.h"
16 
17 /*
18  * About this example
19  *
20  * 1. Start with initializing LEDC module:
21  *    a. Set the timer of LEDC first, this determines the frequency
22  *       and resolution of PWM.
23  *    b. Then set the LEDC channel you want to use,
24  *       and bind with one of the timers.
25  *
26  * 2. You need first to install a default fade function,
27  *    then you can use fade APIs.
28  *
29  * 3. You can also set a target duty directly without fading.
30  *
31  * 4. This example uses GPIO18/19/4/5 as LEDC output,
32  *    and it will change the duty repeatedly.
33  *
34  * 5. GPIO18/19 are from high speed channel group.
35  *    GPIO4/5 are from low speed channel group.
36  *
37  */
38 #if CONFIG_IDF_TARGET_ESP32
39 #define LEDC_HS_TIMER          LEDC_TIMER_0
40 #define LEDC_HS_MODE           LEDC_HIGH_SPEED_MODE
41 #define LEDC_HS_CH0_GPIO       (18)
42 #define LEDC_HS_CH0_CHANNEL    LEDC_CHANNEL_0
43 #define LEDC_HS_CH1_GPIO       (19)
44 #define LEDC_HS_CH1_CHANNEL    LEDC_CHANNEL_1
45 #endif
46 #define LEDC_LS_TIMER          LEDC_TIMER_1
47 #define LEDC_LS_MODE           LEDC_LOW_SPEED_MODE
48 #if !CONFIG_IDF_TARGET_ESP32
49 #define LEDC_LS_CH0_GPIO       (18)
50 #define LEDC_LS_CH0_CHANNEL    LEDC_CHANNEL_0
51 #define LEDC_LS_CH1_GPIO       (19)
52 #define LEDC_LS_CH1_CHANNEL    LEDC_CHANNEL_1
53 #endif
54 #define LEDC_LS_CH2_GPIO       (4)
55 #define LEDC_LS_CH2_CHANNEL    LEDC_CHANNEL_2
56 #define LEDC_LS_CH3_GPIO       (5)
57 #define LEDC_LS_CH3_CHANNEL    LEDC_CHANNEL_3
58 
59 #define LEDC_TEST_CH_NUM       (4)
60 #define LEDC_TEST_DUTY         (4000)
61 #define LEDC_TEST_FADE_TIME    (3000)
62 
63 /*
64  * This callback function will be called when fade operation has ended
65  * Use callback only if you are aware it is being called inside an ISR
66  * Otherwise, you can use a semaphore to unblock tasks
67  */
cb_ledc_fade_end_event(const ledc_cb_param_t * param,void * user_arg)68 static bool cb_ledc_fade_end_event(const ledc_cb_param_t *param, void *user_arg)
69 {
70     portBASE_TYPE taskAwoken = pdFALSE;
71 
72     if (param->event == LEDC_FADE_END_EVT) {
73         SemaphoreHandle_t counting_sem = (SemaphoreHandle_t) user_arg;
74         xSemaphoreGiveFromISR(counting_sem, &taskAwoken);
75     }
76 
77     return (taskAwoken == pdTRUE);
78 }
79 
app_main(void)80 void app_main(void)
81 {
82     int ch;
83 
84     /*
85      * Prepare and set configuration of timers
86      * that will be used by LED Controller
87      */
88     ledc_timer_config_t ledc_timer = {
89         .duty_resolution = LEDC_TIMER_13_BIT, // resolution of PWM duty
90         .freq_hz = 5000,                      // frequency of PWM signal
91         .speed_mode = LEDC_LS_MODE,           // timer mode
92         .timer_num = LEDC_LS_TIMER,            // timer index
93         .clk_cfg = LEDC_AUTO_CLK,              // Auto select the source clock
94     };
95     // Set configuration of timer0 for high speed channels
96     ledc_timer_config(&ledc_timer);
97 #ifdef CONFIG_IDF_TARGET_ESP32
98     // Prepare and set configuration of timer1 for low speed channels
99     ledc_timer.speed_mode = LEDC_HS_MODE;
100     ledc_timer.timer_num = LEDC_HS_TIMER;
101     ledc_timer_config(&ledc_timer);
102 #endif
103     /*
104      * Prepare individual configuration
105      * for each channel of LED Controller
106      * by selecting:
107      * - controller's channel number
108      * - output duty cycle, set initially to 0
109      * - GPIO number where LED is connected to
110      * - speed mode, either high or low
111      * - timer servicing selected channel
112      *   Note: if different channels use one timer,
113      *         then frequency and bit_num of these channels
114      *         will be the same
115      */
116     ledc_channel_config_t ledc_channel[LEDC_TEST_CH_NUM] = {
117 #if CONFIG_IDF_TARGET_ESP32
118         {
119             .channel    = LEDC_HS_CH0_CHANNEL,
120             .duty       = 0,
121             .gpio_num   = LEDC_HS_CH0_GPIO,
122             .speed_mode = LEDC_HS_MODE,
123             .hpoint     = 0,
124             .timer_sel  = LEDC_HS_TIMER,
125             .flags.output_invert = 0
126         },
127         {
128             .channel    = LEDC_HS_CH1_CHANNEL,
129             .duty       = 0,
130             .gpio_num   = LEDC_HS_CH1_GPIO,
131             .speed_mode = LEDC_HS_MODE,
132             .hpoint     = 0,
133             .timer_sel  = LEDC_HS_TIMER,
134             .flags.output_invert = 0
135         },
136 #else
137         {
138             .channel    = LEDC_LS_CH0_CHANNEL,
139             .duty       = 0,
140             .gpio_num   = LEDC_LS_CH0_GPIO,
141             .speed_mode = LEDC_LS_MODE,
142             .hpoint     = 0,
143             .timer_sel  = LEDC_LS_TIMER,
144             .flags.output_invert = 0
145         },
146         {
147             .channel    = LEDC_LS_CH1_CHANNEL,
148             .duty       = 0,
149             .gpio_num   = LEDC_LS_CH1_GPIO,
150             .speed_mode = LEDC_LS_MODE,
151             .hpoint     = 0,
152             .timer_sel  = LEDC_LS_TIMER,
153             .flags.output_invert = 0
154         },
155 #endif
156         {
157             .channel    = LEDC_LS_CH2_CHANNEL,
158             .duty       = 0,
159             .gpio_num   = LEDC_LS_CH2_GPIO,
160             .speed_mode = LEDC_LS_MODE,
161             .hpoint     = 0,
162             .timer_sel  = LEDC_LS_TIMER,
163             .flags.output_invert = 1
164         },
165         {
166             .channel    = LEDC_LS_CH3_CHANNEL,
167             .duty       = 0,
168             .gpio_num   = LEDC_LS_CH3_GPIO,
169             .speed_mode = LEDC_LS_MODE,
170             .hpoint     = 0,
171             .timer_sel  = LEDC_LS_TIMER,
172             .flags.output_invert = 1
173         },
174     };
175 
176     // Set LED Controller with previously prepared configuration
177     for (ch = 0; ch < LEDC_TEST_CH_NUM; ch++) {
178         ledc_channel_config(&ledc_channel[ch]);
179     }
180 
181     // Initialize fade service.
182     ledc_fade_func_install(0);
183     ledc_cbs_t callbacks = {
184         .fade_cb = cb_ledc_fade_end_event
185     };
186     SemaphoreHandle_t counting_sem = xSemaphoreCreateCounting(LEDC_TEST_CH_NUM, 0);
187 
188     for (ch = 0; ch < LEDC_TEST_CH_NUM; ch++) {
189         ledc_cb_register(ledc_channel[ch].speed_mode, ledc_channel[ch].channel, &callbacks, (void *) counting_sem);
190     }
191 
192     while (1) {
193         printf("1. LEDC fade up to duty = %d\n", LEDC_TEST_DUTY);
194         for (ch = 0; ch < LEDC_TEST_CH_NUM; ch++) {
195             ledc_set_fade_with_time(ledc_channel[ch].speed_mode,
196                     ledc_channel[ch].channel, LEDC_TEST_DUTY, LEDC_TEST_FADE_TIME);
197             ledc_fade_start(ledc_channel[ch].speed_mode,
198                     ledc_channel[ch].channel, LEDC_FADE_NO_WAIT);
199         }
200 
201         for (int i = 0; i < LEDC_TEST_CH_NUM; i++) {
202             xSemaphoreTake(counting_sem, portMAX_DELAY);
203         }
204 
205         printf("2. LEDC fade down to duty = 0\n");
206         for (ch = 0; ch < LEDC_TEST_CH_NUM; ch++) {
207             ledc_set_fade_with_time(ledc_channel[ch].speed_mode,
208                     ledc_channel[ch].channel, 0, LEDC_TEST_FADE_TIME);
209             ledc_fade_start(ledc_channel[ch].speed_mode,
210                     ledc_channel[ch].channel, LEDC_FADE_NO_WAIT);
211         }
212 
213         for (int i = 0; i < LEDC_TEST_CH_NUM; i++) {
214             xSemaphoreTake(counting_sem, portMAX_DELAY);
215         }
216 
217         printf("3. LEDC set duty = %d without fade\n", LEDC_TEST_DUTY);
218         for (ch = 0; ch < LEDC_TEST_CH_NUM; ch++) {
219             ledc_set_duty(ledc_channel[ch].speed_mode, ledc_channel[ch].channel, LEDC_TEST_DUTY);
220             ledc_update_duty(ledc_channel[ch].speed_mode, ledc_channel[ch].channel);
221         }
222         vTaskDelay(1000 / portTICK_PERIOD_MS);
223 
224         printf("4. LEDC set duty = 0 without fade\n");
225         for (ch = 0; ch < LEDC_TEST_CH_NUM; ch++) {
226             ledc_set_duty(ledc_channel[ch].speed_mode, ledc_channel[ch].channel, 0);
227             ledc_update_duty(ledc_channel[ch].speed_mode, ledc_channel[ch].channel);
228         }
229         vTaskDelay(1000 / portTICK_PERIOD_MS);
230     }
231 }
232