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