1
- // Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
1
+ // Copyright 2015-2023 Espressif Systems (Shanghai) PTE LTD
2
2
//
3
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
4
// you may not use this file except in compliance with the License.
@@ -37,33 +37,19 @@ typedef struct {
37
37
int used_channels : LEDC_CHANNELS ; // Used channels as a bits
38
38
} ledc_periph_t ;
39
39
40
- /*
41
- * LEDC Chan to Group/Channel/Timer Mapping
42
- ** ledc: 0 => Group: 0, Channel: 0, Timer: 0
43
- ** ledc: 1 => Group: 0, Channel: 1, Timer: 0
44
- ** ledc: 2 => Group: 0, Channel: 2, Timer: 1
45
- ** ledc: 3 => Group: 0, Channel: 3, Timer: 1
46
- ** ledc: 4 => Group: 0, Channel: 4, Timer: 2
47
- ** ledc: 5 => Group: 0, Channel: 5, Timer: 2
48
- ** ledc: 6 => Group: 0, Channel: 6, Timer: 3
49
- ** ledc: 7 => Group: 0, Channel: 7, Timer: 3
50
- ** ledc: 8 => Group: 1, Channel: 0, Timer: 0
51
- ** ledc: 9 => Group: 1, Channel: 1, Timer: 0
52
- ** ledc: 10 => Group: 1, Channel: 2, Timer: 1
53
- ** ledc: 11 => Group: 1, Channel: 3, Timer: 1
54
- ** ledc: 12 => Group: 1, Channel: 4, Timer: 2
55
- ** ledc: 13 => Group: 1, Channel: 5, Timer: 2
56
- ** ledc: 14 => Group: 1, Channel: 6, Timer: 3
57
- ** ledc: 15 => Group: 1, Channel: 7, Timer: 3
58
- */
59
-
60
40
ledc_periph_t ledc_handle ;
61
41
42
+ static bool fade_initialized = false;
43
+
62
44
static bool ledcDetachBus (void * bus ){
63
- ledc_channel_handle_t handle = (ledc_channel_handle_t )bus ;
45
+ ledc_channel_handle_t * handle = (ledc_channel_handle_t * )bus ;
64
46
ledc_handle .used_channels &= ~(1UL << handle -> channel );
65
47
pinMatrixOutDetach (handle -> pin , false, false);
66
48
free (handle );
49
+ if (ledc_handle .used_channels == 0 ){
50
+ ledc_fade_func_uninstall ();
51
+ fade_initialized = false;
52
+ }
67
53
return true;
68
54
}
69
55
@@ -77,7 +63,7 @@ bool ledcAttach(uint8_t pin, uint32_t freq, uint8_t resolution)
77
63
}
78
64
79
65
perimanSetBusDeinit (ESP32_BUS_TYPE_LEDC , ledcDetachBus );
80
- ledc_channel_handle_t bus = (ledc_channel_handle_t )perimanGetPinBus (pin , ESP32_BUS_TYPE_LEDC );
66
+ ledc_channel_handle_t * bus = (ledc_channel_handle_t * )perimanGetPinBus (pin , ESP32_BUS_TYPE_LEDC );
81
67
if (bus != NULL && !perimanSetPinBus (pin , ESP32_BUS_TYPE_INIT , NULL )){
82
68
return false;
83
69
}
@@ -111,12 +97,14 @@ bool ledcAttach(uint8_t pin, uint32_t freq, uint8_t resolution)
111
97
};
112
98
ledc_channel_config (& ledc_channel );
113
99
114
- ledc_channel_handle_t handle = malloc (sizeof (ledc_channel_handle_t ));
115
-
116
- handle -> pin = pin ,
117
- handle -> channel = channel ,
118
- handle -> channel_resolution = resolution ,
100
+ ledc_channel_handle_t * handle = (ledc_channel_handle_t * )malloc (sizeof (ledc_channel_handle_t ));
119
101
102
+ handle -> pin = pin ;
103
+ handle -> channel = channel ;
104
+ handle -> channel_resolution = resolution ;
105
+ #ifndef SOC_LEDC_SUPPORT_FADE_STOP
106
+ handle -> lock = NULL ;
107
+ #endif
120
108
ledc_handle .used_channels |= 1UL << channel ;
121
109
122
110
if (!perimanSetPinBus (pin , ESP32_BUS_TYPE_LEDC , (void * )handle )){
@@ -128,7 +116,7 @@ bool ledcAttach(uint8_t pin, uint32_t freq, uint8_t resolution)
128
116
}
129
117
bool ledcWrite (uint8_t pin , uint32_t duty )
130
118
{
131
- ledc_channel_handle_t bus = (ledc_channel_handle_t )perimanGetPinBus (pin , ESP32_BUS_TYPE_LEDC );
119
+ ledc_channel_handle_t * bus = (ledc_channel_handle_t * )perimanGetPinBus (pin , ESP32_BUS_TYPE_LEDC );
132
120
if (bus != NULL ){
133
121
134
122
uint8_t group = (bus -> channel /8 ), channel = (bus -> channel %8 );
@@ -150,7 +138,7 @@ bool ledcWrite(uint8_t pin, uint32_t duty)
150
138
151
139
uint32_t ledcRead (uint8_t pin )
152
140
{
153
- ledc_channel_handle_t bus = (ledc_channel_handle_t )perimanGetPinBus (pin , ESP32_BUS_TYPE_LEDC );
141
+ ledc_channel_handle_t * bus = (ledc_channel_handle_t * )perimanGetPinBus (pin , ESP32_BUS_TYPE_LEDC );
154
142
if (bus != NULL ){
155
143
156
144
uint8_t group = (bus -> channel /8 ), channel = (bus -> channel %8 );
@@ -161,7 +149,7 @@ uint32_t ledcRead(uint8_t pin)
161
149
162
150
uint32_t ledcReadFreq (uint8_t pin )
163
151
{
164
- ledc_channel_handle_t bus = (ledc_channel_handle_t )perimanGetPinBus (pin , ESP32_BUS_TYPE_LEDC );
152
+ ledc_channel_handle_t * bus = (ledc_channel_handle_t * )perimanGetPinBus (pin , ESP32_BUS_TYPE_LEDC );
165
153
if (bus != NULL ){
166
154
if (!ledcRead (pin )){
167
155
return 0 ;
@@ -175,7 +163,7 @@ uint32_t ledcReadFreq(uint8_t pin)
175
163
176
164
uint32_t ledcWriteTone (uint8_t pin , uint32_t freq )
177
165
{
178
- ledc_channel_handle_t bus = (ledc_channel_handle_t )perimanGetPinBus (pin , ESP32_BUS_TYPE_LEDC );
166
+ ledc_channel_handle_t * bus = (ledc_channel_handle_t * )perimanGetPinBus (pin , ESP32_BUS_TYPE_LEDC );
179
167
if (bus != NULL ){
180
168
181
169
if (!freq ){
@@ -222,7 +210,7 @@ uint32_t ledcWriteNote(uint8_t pin, note_t note, uint8_t octave){
222
210
223
211
bool ledcDetach (uint8_t pin )
224
212
{
225
- ledc_channel_handle_t bus = (ledc_channel_handle_t )perimanGetPinBus (pin , ESP32_BUS_TYPE_LEDC );
213
+ ledc_channel_handle_t * bus = (ledc_channel_handle_t * )perimanGetPinBus (pin , ESP32_BUS_TYPE_LEDC );
226
214
if (bus != NULL ){
227
215
// will call ledcDetachBus
228
216
return perimanSetPinBus (pin , ESP32_BUS_TYPE_INIT , NULL );
@@ -234,7 +222,7 @@ bool ledcDetach(uint8_t pin)
234
222
235
223
uint32_t ledcChangeFrequency (uint8_t pin , uint32_t freq , uint8_t resolution )
236
224
{
237
- ledc_channel_handle_t bus = (ledc_channel_handle_t )perimanGetPinBus (pin , ESP32_BUS_TYPE_LEDC );
225
+ ledc_channel_handle_t * bus = (ledc_channel_handle_t * )perimanGetPinBus (pin , ESP32_BUS_TYPE_LEDC );
238
226
if (bus != NULL ){
239
227
240
228
if (resolution > LEDC_MAX_BIT_WIDTH ){
@@ -262,12 +250,113 @@ uint32_t ledcChangeFrequency(uint8_t pin, uint32_t freq, uint8_t resolution)
262
250
return 0 ;
263
251
}
264
252
253
+ static IRAM_ATTR bool ledcFnWrapper (const ledc_cb_param_t * param , void * user_arg )
254
+ {
255
+ if (param -> event == LEDC_FADE_END_EVT ) {
256
+ ledc_channel_handle_t * bus = (ledc_channel_handle_t * )user_arg ;
257
+ #ifndef SOC_LEDC_SUPPORT_FADE_STOP
258
+ portBASE_TYPE xTaskWoken = 0 ;
259
+ xSemaphoreGiveFromISR (bus -> lock , & xTaskWoken );
260
+ #endif
261
+ if (bus -> fn ) {
262
+ if (bus -> arg ){
263
+ ((voidFuncPtrArg )bus -> fn )(bus -> arg );
264
+ } else {
265
+ bus -> fn ();
266
+ }
267
+ }
268
+ }
269
+ return true;
270
+ }
271
+
272
+ static bool ledcFadeConfig (uint8_t pin , uint32_t start_duty , uint32_t target_duty , int max_fade_time_ms , void (* userFunc )(void * ), void * arg ){
273
+ ledc_channel_handle_t * bus = (ledc_channel_handle_t * )perimanGetPinBus (pin , ESP32_BUS_TYPE_LEDC );
274
+ if (bus != NULL ){
275
+
276
+ #ifndef SOC_LEDC_SUPPORT_FADE_STOP
277
+ #if !CONFIG_DISABLE_HAL_LOCKS
278
+ if (bus -> lock == NULL ){
279
+ bus -> lock = xSemaphoreCreateBinary ();
280
+ if (bus -> lock == NULL ){
281
+ log_e ("xSemaphoreCreateBinary failed" );
282
+ return false;
283
+ }
284
+ xSemaphoreGive (bus -> lock );
285
+ }
286
+ //acquire lock
287
+ if (xSemaphoreTake (bus -> lock , 0 ) != pdTRUE ){
288
+ log_e ("LEDC Fade is still running on pin %u! SoC does not support stopping fade." , pin );
289
+ return false;
290
+ }
291
+ #endif
292
+ #endif
293
+ uint8_t group = (bus -> channel /8 ), channel = (bus -> channel %8 );
294
+
295
+ // Initialize fade service.
296
+ if (!fade_initialized ){
297
+ ledc_fade_func_install (0 );
298
+ fade_initialized = true;
299
+ }
300
+
301
+ bus -> fn = (voidFuncPtr )userFunc ;
302
+ bus -> arg = arg ;
303
+
304
+ ledc_cbs_t callbacks = {
305
+ .fade_cb = ledcFnWrapper
306
+ };
307
+ ledc_cb_register (group , channel , & callbacks , (void * ) bus );
308
+
309
+ //Fixing if all bits in resolution is set = LEDC FULL ON
310
+ uint32_t max_duty = (1 << bus -> channel_resolution ) - 1 ;
311
+
312
+ if ((target_duty == max_duty ) && (max_duty != 1 )){
313
+ target_duty = max_duty + 1 ;
314
+ }
315
+ else if ((start_duty == max_duty ) && (max_duty != 1 )){
316
+ start_duty = max_duty + 1 ;
317
+ }
318
+
319
+ #if SOC_LEDC_SUPPORT_FADE_STOP
320
+ ledc_fade_stop (group , channel );
321
+ #endif
322
+
323
+ if (ledc_set_duty_and_update (group , channel , start_duty , 0 ) != ESP_OK ){
324
+ log_e ("ledc_set_duty_and_update failed" );
325
+ return false;
326
+ }
327
+ // Wait for LEDCs next PWM cycle to update duty (~ 1-2 ms)
328
+ while (ledc_get_duty (group ,channel ) != start_duty );
329
+
330
+ if (ledc_set_fade_time_and_start (group , channel , target_duty , max_fade_time_ms , LEDC_FADE_NO_WAIT ) != ESP_OK ){
331
+ log_e ("ledc_set_fade_time_and_start failed" );
332
+ return false;
333
+ }
334
+ }
335
+ else {
336
+ log_e ("Pin %u is not attached to LEDC. Call ledcAttach first!" , pin );
337
+ return false;
338
+ }
339
+ return true;
340
+ }
341
+
342
+ bool ledcFade (uint8_t pin , uint32_t start_duty , uint32_t target_duty , int max_fade_time_ms ){
343
+ return ledcFadeConfig (pin , start_duty , target_duty , max_fade_time_ms , NULL , NULL );
344
+ }
345
+
346
+ bool ledcFadeWithInterrupt (uint8_t pin , uint32_t start_duty , uint32_t target_duty , int max_fade_time_ms , voidFuncPtr userFunc ){
347
+ return ledcFadeConfig (pin , start_duty , target_duty , max_fade_time_ms , (voidFuncPtrArg )userFunc , NULL );
348
+ }
349
+
350
+ bool ledcFadeWithInterruptArg (uint8_t pin , uint32_t start_duty , uint32_t target_duty , int max_fade_time_ms , void (* userFunc )(void * ), void * arg ){
351
+ return ledcFadeConfig (pin , start_duty , target_duty , max_fade_time_ms , userFunc , arg );
352
+ }
353
+
265
354
static uint8_t analog_resolution = 8 ;
266
355
static int analog_frequency = 1000 ;
267
356
void analogWrite (uint8_t pin , int value ) {
268
357
// Use ledc hardware for internal pins
269
358
if (pin < SOC_GPIO_PIN_COUNT ) {
270
- ledc_channel_handle_t bus = (ledc_channel_handle_t )perimanGetPinBus (pin , ESP32_BUS_TYPE_LEDC );
359
+ ledc_channel_handle_t * bus = (ledc_channel_handle_t * )perimanGetPinBus (pin , ESP32_BUS_TYPE_LEDC );
271
360
if (bus == NULL && perimanSetPinBus (pin , ESP32_BUS_TYPE_INIT , NULL )){
272
361
if (ledcAttach (pin , analog_frequency , analog_resolution ) == 0 ){
273
362
log_e ("analogWrite setup failed (freq = %u, resolution = %u). Try setting different resolution or frequency" );
0 commit comments