22
22
#include "soc/gpio_sig_map.h"
23
23
#include "esp_rom_gpio.h"
24
24
#include "hal/ledc_ll.h"
25
+ #if SOC_LEDC_GAMMA_CURVE_FADE_SUPPORTED
26
+ #include <math.h>
27
+ #endif
25
28
26
29
#ifdef SOC_LEDC_SUPPORT_HS_MODE
27
30
#define LEDC_CHANNELS (SOC_LEDC_CHANNEL_NUM << 1)
@@ -56,7 +59,7 @@ static bool find_matching_timer(uint8_t speed_mode, uint32_t freq, uint8_t resol
56
59
peripheral_bus_type_t type = perimanGetPinBusType (i );
57
60
if (type == ESP32_BUS_TYPE_LEDC ) {
58
61
ledc_channel_handle_t * bus = (ledc_channel_handle_t * )perimanGetPinBus (i , ESP32_BUS_TYPE_LEDC );
59
- if (bus != NULL && (bus -> channel / 8 ) == speed_mode && bus -> freq_hz == freq && bus -> channel_resolution == resolution ) {
62
+ if (bus != NULL && (bus -> channel / SOC_LEDC_CHANNEL_NUM ) == speed_mode && bus -> freq_hz == freq && bus -> channel_resolution == resolution ) {
60
63
log_d ("Found matching timer %u for freq=%u, resolution=%u" , bus -> timer_num , freq , resolution );
61
64
* timer_num = bus -> timer_num ;
62
65
return true;
@@ -78,7 +81,7 @@ static bool find_free_timer(uint8_t speed_mode, uint8_t *timer_num) {
78
81
peripheral_bus_type_t type = perimanGetPinBusType (i );
79
82
if (type == ESP32_BUS_TYPE_LEDC ) {
80
83
ledc_channel_handle_t * bus = (ledc_channel_handle_t * )perimanGetPinBus (i , ESP32_BUS_TYPE_LEDC );
81
- if (bus != NULL && (bus -> channel / 8 ) == speed_mode ) {
84
+ if (bus != NULL && (bus -> channel / SOC_LEDC_CHANNEL_NUM ) == speed_mode ) {
82
85
log_d ("Timer %u is in use by channel %u" , bus -> timer_num , bus -> channel );
83
86
used_timers |= (1 << bus -> timer_num );
84
87
}
@@ -110,7 +113,7 @@ static void remove_channel_from_timer(uint8_t speed_mode, uint8_t timer_num, uin
110
113
peripheral_bus_type_t type = perimanGetPinBusType (i );
111
114
if (type == ESP32_BUS_TYPE_LEDC ) {
112
115
ledc_channel_handle_t * bus = (ledc_channel_handle_t * )perimanGetPinBus (i , ESP32_BUS_TYPE_LEDC );
113
- if (bus != NULL && (bus -> channel / 8 ) == speed_mode && bus -> timer_num == timer_num && bus -> channel != channel ) {
116
+ if (bus != NULL && (bus -> channel / SOC_LEDC_CHANNEL_NUM ) == speed_mode && bus -> timer_num == timer_num && bus -> channel != channel ) {
114
117
log_d ("Timer %u is still in use by channel %u" , timer_num , bus -> channel );
115
118
timer_in_use = true;
116
119
break ;
@@ -168,8 +171,8 @@ static bool ledcDetachBus(void *bus) {
168
171
}
169
172
pinMatrixOutDetach (handle -> pin , false, false);
170
173
if (!channel_found ) {
171
- uint8_t group = (handle -> channel / 8 );
172
- remove_channel_from_timer (group , handle -> timer_num , handle -> channel % 8 );
174
+ uint8_t group = (handle -> channel / SOC_LEDC_CHANNEL_NUM );
175
+ remove_channel_from_timer (group , handle -> timer_num , handle -> channel % SOC_LEDC_CHANNEL_NUM );
173
176
ledc_handle .used_channels &= ~(1UL << handle -> channel );
174
177
}
175
178
free (handle );
@@ -206,21 +209,21 @@ bool ledcAttachChannel(uint8_t pin, uint32_t freq, uint8_t resolution, uint8_t c
206
209
return false;
207
210
}
208
211
209
- uint8_t group = (channel / 8 );
212
+ uint8_t group = (channel / SOC_LEDC_CHANNEL_NUM );
210
213
uint8_t timer = 0 ;
211
214
bool channel_used = ledc_handle .used_channels & (1UL << channel );
212
215
213
216
if (channel_used ) {
214
217
log_i ("Channel %u is already set up, given frequency and resolution will be ignored" , channel );
215
- if (ledc_set_pin (pin , group , channel % 8 ) != ESP_OK ) {
218
+ if (ledc_set_pin (pin , group , channel % SOC_LEDC_CHANNEL_NUM ) != ESP_OK ) {
216
219
log_e ("Attaching pin to already used channel failed!" );
217
220
return false;
218
221
}
219
222
} else {
220
223
// Find a timer with matching frequency and resolution, or a free timer
221
224
if (!find_matching_timer (group , freq , resolution , & timer )) {
222
225
if (!find_free_timer (group , & timer )) {
223
- log_e ("No free timers available for speed mode %u" , group );
226
+ log_w ("No free timers available for speed mode %u" , group );
224
227
return false;
225
228
}
226
229
@@ -239,12 +242,12 @@ bool ledcAttachChannel(uint8_t pin, uint32_t freq, uint8_t resolution, uint8_t c
239
242
}
240
243
}
241
244
242
- uint32_t duty = ledc_get_duty (group , (channel % 8 ));
245
+ uint32_t duty = ledc_get_duty (group , (channel % SOC_LEDC_CHANNEL_NUM ));
243
246
244
247
ledc_channel_config_t ledc_channel ;
245
248
memset ((void * )& ledc_channel , 0 , sizeof (ledc_channel_config_t ));
246
249
ledc_channel .speed_mode = group ;
247
- ledc_channel .channel = (channel % 8 );
250
+ ledc_channel .channel = (channel % SOC_LEDC_CHANNEL_NUM );
248
251
ledc_channel .timer_sel = timer ;
249
252
ledc_channel .intr_type = LEDC_INTR_DISABLE ;
250
253
ledc_channel .gpio_num = pin ;
@@ -274,7 +277,7 @@ bool ledcAttachChannel(uint8_t pin, uint32_t freq, uint8_t resolution, uint8_t c
274
277
ledc_handle .used_channels |= 1UL << channel ;
275
278
}
276
279
277
- if (!perimanSetPinBus (pin , ESP32_BUS_TYPE_LEDC , (void * )handle , group , channel )) {
280
+ if (!perimanSetPinBus (pin , ESP32_BUS_TYPE_LEDC , (void * )handle , channel , timer )) {
278
281
ledcDetachBus ((void * )handle );
279
282
return false;
280
283
}
@@ -291,14 +294,40 @@ bool ledcAttach(uint8_t pin, uint32_t freq, uint8_t resolution) {
291
294
}
292
295
uint8_t channel = __builtin_ctz (free_channel ); // Convert the free_channel bit to channel number
293
296
294
- return ledcAttachChannel (pin , freq , resolution , channel );
297
+ // Try the first available channel
298
+ if (ledcAttachChannel (pin , freq , resolution , channel )) {
299
+ return true;
300
+ }
301
+
302
+ #ifdef SOC_LEDC_SUPPORT_HS_MODE
303
+ // If first attempt failed and HS mode is supported, try to find a free channel in group 1
304
+ if ((channel / SOC_LEDC_CHANNEL_NUM ) == 0 ) { // First attempt was in group 0
305
+ log_d ("LEDC: Group 0 channel %u failed, trying to find a free channel in group 1" , channel );
306
+ // Find free channels specifically in group 1
307
+ uint32_t group1_mask = ((1UL << SOC_LEDC_CHANNEL_NUM ) - 1 ) << SOC_LEDC_CHANNEL_NUM ;
308
+ int group1_free_channel = (~ledc_handle .used_channels ) & group1_mask ;
309
+ if (group1_free_channel != 0 ) {
310
+ uint8_t group1_channel = __builtin_ctz (group1_free_channel );
311
+ if (ledcAttachChannel (pin , freq , resolution , group1_channel )) {
312
+ return true;
313
+ }
314
+ }
315
+ }
316
+ #endif
317
+
318
+ log_e (
319
+ "No free timers available for freq=%u, resolution=%u. To attach a new channel, use the same frequency and resolution as an already attached channel to "
320
+ "share its timer." ,
321
+ freq , resolution
322
+ );
323
+ return false;
295
324
}
296
325
297
326
bool ledcWrite (uint8_t pin , uint32_t duty ) {
298
327
ledc_channel_handle_t * bus = (ledc_channel_handle_t * )perimanGetPinBus (pin , ESP32_BUS_TYPE_LEDC );
299
328
if (bus != NULL ) {
300
329
301
- uint8_t group = (bus -> channel / 8 ), channel = (bus -> channel % 8 );
330
+ uint8_t group = (bus -> channel / SOC_LEDC_CHANNEL_NUM ), channel = (bus -> channel % SOC_LEDC_CHANNEL_NUM );
302
331
303
332
//Fixing if all bits in resolution is set = LEDC FULL ON
304
333
uint32_t max_duty = (1 << bus -> channel_resolution ) - 1 ;
@@ -307,8 +336,14 @@ bool ledcWrite(uint8_t pin, uint32_t duty) {
307
336
duty = max_duty + 1 ;
308
337
}
309
338
310
- ledc_set_duty (group , channel , duty );
311
- ledc_update_duty (group , channel );
339
+ if (ledc_set_duty (group , channel , duty ) != ESP_OK ) {
340
+ log_e ("ledc_set_duty failed" );
341
+ return false;
342
+ }
343
+ if (ledc_update_duty (group , channel ) != ESP_OK ) {
344
+ log_e ("ledc_update_duty failed" );
345
+ return false;
346
+ }
312
347
313
348
return true;
314
349
}
@@ -321,7 +356,11 @@ bool ledcWriteChannel(uint8_t channel, uint32_t duty) {
321
356
log_e ("Channel %u is not available (maximum %u) or not used!" , channel , LEDC_CHANNELS );
322
357
return false;
323
358
}
324
- uint8_t group = (channel / 8 ), timer = ((channel / 2 ) % 4 );
359
+ uint8_t group = (channel / SOC_LEDC_CHANNEL_NUM );
360
+ ledc_timer_t timer ;
361
+
362
+ // Get the actual timer being used by this channel
363
+ ledc_ll_get_channel_timer (LEDC_LL_GET_HW (), group , (channel % SOC_LEDC_CHANNEL_NUM ), & timer );
325
364
326
365
//Fixing if all bits in resolution is set = LEDC FULL ON
327
366
uint32_t resolution = 0 ;
@@ -333,8 +372,14 @@ bool ledcWriteChannel(uint8_t channel, uint32_t duty) {
333
372
duty = max_duty + 1 ;
334
373
}
335
374
336
- ledc_set_duty (group , channel , duty );
337
- ledc_update_duty (group , channel );
375
+ if (ledc_set_duty (group , channel , duty ) != ESP_OK ) {
376
+ log_e ("ledc_set_duty failed" );
377
+ return false;
378
+ }
379
+ if (ledc_update_duty (group , channel ) != ESP_OK ) {
380
+ log_e ("ledc_update_duty failed" );
381
+ return false;
382
+ }
338
383
339
384
return true;
340
385
}
@@ -343,7 +388,7 @@ uint32_t ledcRead(uint8_t pin) {
343
388
ledc_channel_handle_t * bus = (ledc_channel_handle_t * )perimanGetPinBus (pin , ESP32_BUS_TYPE_LEDC );
344
389
if (bus != NULL ) {
345
390
346
- uint8_t group = (bus -> channel / 8 ), channel = (bus -> channel % 8 );
391
+ uint8_t group = (bus -> channel / SOC_LEDC_CHANNEL_NUM ), channel = (bus -> channel % SOC_LEDC_CHANNEL_NUM );
347
392
return ledc_get_duty (group , channel );
348
393
}
349
394
return 0 ;
@@ -355,8 +400,8 @@ uint32_t ledcReadFreq(uint8_t pin) {
355
400
if (!ledcRead (pin )) {
356
401
return 0 ;
357
402
}
358
- uint8_t group = (bus -> channel / 8 ), timer = (( bus -> channel / 2 ) % 4 );
359
- return ledc_get_freq (group , timer );
403
+ uint8_t group = (bus -> channel / SOC_LEDC_CHANNEL_NUM );
404
+ return ledc_get_freq (group , bus -> timer_num );
360
405
}
361
406
return 0 ;
362
407
}
@@ -370,12 +415,12 @@ uint32_t ledcWriteTone(uint8_t pin, uint32_t freq) {
370
415
return 0 ;
371
416
}
372
417
373
- uint8_t group = (bus -> channel / 8 ), timer = (( bus -> channel / 2 ) % 4 );
418
+ uint8_t group = (bus -> channel / SOC_LEDC_CHANNEL_NUM );
374
419
375
420
ledc_timer_config_t ledc_timer ;
376
421
memset ((void * )& ledc_timer , 0 , sizeof (ledc_timer_config_t ));
377
422
ledc_timer .speed_mode = group ;
378
- ledc_timer .timer_num = timer ;
423
+ ledc_timer .timer_num = bus -> timer_num ;
379
424
ledc_timer .duty_resolution = 10 ;
380
425
ledc_timer .freq_hz = freq ;
381
426
ledc_timer .clk_cfg = clock_source ;
@@ -386,7 +431,7 @@ uint32_t ledcWriteTone(uint8_t pin, uint32_t freq) {
386
431
}
387
432
bus -> channel_resolution = 10 ;
388
433
389
- uint32_t res_freq = ledc_get_freq (group , timer );
434
+ uint32_t res_freq = ledc_get_freq (group , bus -> timer_num );
390
435
ledcWrite (pin , 0x1FF );
391
436
return res_freq ;
392
437
}
@@ -427,12 +472,12 @@ uint32_t ledcChangeFrequency(uint8_t pin, uint32_t freq, uint8_t resolution) {
427
472
log_e ("LEDC pin %u - resolution is zero or it is too big (maximum %u)" , pin , LEDC_MAX_BIT_WIDTH );
428
473
return 0 ;
429
474
}
430
- uint8_t group = (bus -> channel / 8 ), timer = (( bus -> channel / 2 ) % 4 );
475
+ uint8_t group = (bus -> channel / SOC_LEDC_CHANNEL_NUM );
431
476
432
477
ledc_timer_config_t ledc_timer ;
433
478
memset ((void * )& ledc_timer , 0 , sizeof (ledc_timer_config_t ));
434
479
ledc_timer .speed_mode = group ;
435
- ledc_timer .timer_num = timer ;
480
+ ledc_timer .timer_num = bus -> timer_num ;
436
481
ledc_timer .duty_resolution = resolution ;
437
482
ledc_timer .freq_hz = freq ;
438
483
ledc_timer .clk_cfg = clock_source ;
@@ -442,7 +487,7 @@ uint32_t ledcChangeFrequency(uint8_t pin, uint32_t freq, uint8_t resolution) {
442
487
return 0 ;
443
488
}
444
489
bus -> channel_resolution = resolution ;
445
- return ledc_get_freq (group , timer );
490
+ return ledc_get_freq (group , bus -> timer_num );
446
491
}
447
492
return 0 ;
448
493
}
@@ -453,12 +498,14 @@ bool ledcOutputInvert(uint8_t pin, bool out_invert) {
453
498
gpio_set_level (pin , out_invert );
454
499
455
500
#ifdef CONFIG_IDF_TARGET_ESP32P4
456
- esp_rom_gpio_connect_out_signal (pin , LEDC_LS_SIG_OUT_PAD_OUT0_IDX + ((bus -> channel ) % 8 ), out_invert , 0 );
501
+ esp_rom_gpio_connect_out_signal (pin , LEDC_LS_SIG_OUT_PAD_OUT0_IDX + ((bus -> channel ) % SOC_LEDC_CHANNEL_NUM ), out_invert , 0 );
457
502
#else
458
503
#ifdef SOC_LEDC_SUPPORT_HS_MODE
459
- esp_rom_gpio_connect_out_signal (pin , ((bus -> channel / 8 == 0 ) ? LEDC_HS_SIG_OUT0_IDX : LEDC_LS_SIG_OUT0_IDX ) + ((bus -> channel ) % 8 ), out_invert , 0 );
504
+ esp_rom_gpio_connect_out_signal (
505
+ pin , ((bus -> channel / SOC_LEDC_CHANNEL_NUM == 0 ) ? LEDC_HS_SIG_OUT0_IDX : LEDC_LS_SIG_OUT0_IDX ) + ((bus -> channel ) % SOC_LEDC_CHANNEL_NUM ), out_invert , 0
506
+ );
460
507
#else
461
- esp_rom_gpio_connect_out_signal (pin , LEDC_LS_SIG_OUT0_IDX + ((bus -> channel ) % 8 ), out_invert , 0 );
508
+ esp_rom_gpio_connect_out_signal (pin , LEDC_LS_SIG_OUT0_IDX + ((bus -> channel ) % SOC_LEDC_CHANNEL_NUM ), out_invert , 0 );
462
509
#endif
463
510
#endif // ifdef CONFIG_IDF_TARGET_ESP32P4
464
511
return true;
@@ -505,7 +552,7 @@ static bool ledcFadeConfig(uint8_t pin, uint32_t start_duty, uint32_t target_dut
505
552
}
506
553
#endif
507
554
#endif
508
- uint8_t group = (bus -> channel / 8 ), channel = (bus -> channel % 8 );
555
+ uint8_t group = (bus -> channel / SOC_LEDC_CHANNEL_NUM ), channel = (bus -> channel % SOC_LEDC_CHANNEL_NUM );
509
556
510
557
// Initialize fade service.
511
558
if (!fade_initialized ) {
@@ -562,6 +609,161 @@ bool ledcFadeWithInterruptArg(uint8_t pin, uint32_t start_duty, uint32_t target_
562
609
return ledcFadeConfig (pin , start_duty , target_duty , max_fade_time_ms , userFunc , arg );
563
610
}
564
611
612
+ #ifdef SOC_LEDC_GAMMA_CURVE_FADE_SUPPORTED
613
+ // Default gamma factor for gamma correction (common value for LEDs)
614
+ static float ledcGammaFactor = 2.8 ;
615
+ // Gamma correction LUT support
616
+ static const float * ledcGammaLUT = NULL ;
617
+ static uint16_t ledcGammaLUTSize = 0 ;
618
+ // Global variable to store current resolution for gamma callback
619
+ static uint8_t ledcGammaResolution = 13 ;
620
+
621
+ bool ledcSetGammaTable (const float * gamma_table , uint16_t size ) {
622
+ if (gamma_table == NULL || size == 0 ) {
623
+ log_e ("Invalid gamma table or size" );
624
+ return false;
625
+ }
626
+ ledcGammaLUT = gamma_table ;
627
+ ledcGammaLUTSize = size ;
628
+ log_i ("Custom gamma LUT set with %u entries" , size );
629
+ return true;
630
+ }
631
+
632
+ void ledcClearGammaTable (void ) {
633
+ ledcGammaLUT = NULL ;
634
+ ledcGammaLUTSize = 0 ;
635
+ log_i ("Gamma LUT cleared, using mathematical calculation" );
636
+ }
637
+
638
+ void ledcSetGammaFactor (float factor ) {
639
+ ledcGammaFactor = factor ;
640
+ }
641
+
642
+ // Gamma correction calculator function
643
+ static uint32_t ledcGammaCorrection (uint32_t duty ) {
644
+ if (duty == 0 ) {
645
+ return 0 ;
646
+ }
647
+
648
+ uint32_t max_duty = (1U << ledcGammaResolution ) - 1 ;
649
+ if (duty >= (1U << ledcGammaResolution )) {
650
+ return max_duty ;
651
+ }
652
+
653
+ // Use LUT if provided, otherwise use mathematical calculation
654
+ if (ledcGammaLUT != NULL && ledcGammaLUTSize > 0 ) {
655
+ // LUT-based gamma correction
656
+ uint32_t lut_index = (duty * (ledcGammaLUTSize - 1 )) / max_duty ;
657
+ if (lut_index >= ledcGammaLUTSize ) {
658
+ lut_index = ledcGammaLUTSize - 1 ;
659
+ }
660
+
661
+ float corrected_normalized = ledcGammaLUT [lut_index ];
662
+ return (uint32_t )(corrected_normalized * max_duty );
663
+ } else {
664
+ // Mathematical gamma correction
665
+ double normalized = (double )duty / (1U << ledcGammaResolution );
666
+ double corrected = pow (normalized , ledcGammaFactor );
667
+ return (uint32_t )(corrected * (1U << ledcGammaResolution ));
668
+ }
669
+ }
670
+
671
+ static bool ledcFadeGammaConfig (uint8_t pin , uint32_t start_duty , uint32_t target_duty , int max_fade_time_ms , void (* userFunc )(void * ), void * arg ) {
672
+ ledc_channel_handle_t * bus = (ledc_channel_handle_t * )perimanGetPinBus (pin , ESP32_BUS_TYPE_LEDC );
673
+ if (bus != NULL ) {
674
+
675
+ #ifndef SOC_LEDC_SUPPORT_FADE_STOP
676
+ #if !CONFIG_DISABLE_HAL_LOCKS
677
+ if (bus -> lock == NULL ) {
678
+ bus -> lock = xSemaphoreCreateBinary ();
679
+ if (bus -> lock == NULL ) {
680
+ log_e ("xSemaphoreCreateBinary failed" );
681
+ return false;
682
+ }
683
+ xSemaphoreGive (bus -> lock );
684
+ }
685
+ //acquire lock
686
+ if (xSemaphoreTake (bus -> lock , 0 ) != pdTRUE ) {
687
+ log_e ("LEDC Fade is still running on pin %u! SoC does not support stopping fade." , pin );
688
+ return false;
689
+ }
690
+ #endif
691
+ #endif
692
+ uint8_t group = (bus -> channel / SOC_LEDC_CHANNEL_NUM ), channel = (bus -> channel % SOC_LEDC_CHANNEL_NUM );
693
+
694
+ // Initialize fade service.
695
+ if (!fade_initialized ) {
696
+ ledc_fade_func_install (0 );
697
+ fade_initialized = true;
698
+ }
699
+
700
+ bus -> fn = (voidFuncPtr )userFunc ;
701
+ bus -> arg = arg ;
702
+
703
+ ledc_cbs_t callbacks = {.fade_cb = ledcFnWrapper };
704
+ ledc_cb_register (group , channel , & callbacks , (void * )bus );
705
+
706
+ // Prepare gamma curve fade parameters
707
+ ledc_fade_param_config_t fade_params [SOC_LEDC_GAMMA_CURVE_FADE_RANGE_MAX ];
708
+ uint32_t actual_fade_ranges = 0 ;
709
+
710
+ // Use a moderate number of linear segments for smooth gamma curve
711
+ const uint32_t linear_fade_segments = 12 ;
712
+
713
+ // Set the global resolution for gamma correction
714
+ ledcGammaResolution = bus -> channel_resolution ;
715
+
716
+ // Fill multi-fade parameter list using ESP-IDF API
717
+ esp_err_t err = ledc_fill_multi_fade_param_list (
718
+ group , channel , start_duty , target_duty , linear_fade_segments , max_fade_time_ms , ledcGammaCorrection , SOC_LEDC_GAMMA_CURVE_FADE_RANGE_MAX , fade_params ,
719
+ & actual_fade_ranges
720
+ );
721
+
722
+ if (err != ESP_OK ) {
723
+ log_e ("ledc_fill_multi_fade_param_list failed: %s" , esp_err_to_name (err ));
724
+ return false;
725
+ }
726
+
727
+ // Apply the gamma-corrected start duty
728
+ uint32_t gamma_start_duty = ledcGammaCorrection (start_duty );
729
+
730
+ // Set multi-fade parameters
731
+ err = ledc_set_multi_fade (group , channel , gamma_start_duty , fade_params , actual_fade_ranges );
732
+ if (err != ESP_OK ) {
733
+ log_e ("ledc_set_multi_fade failed: %s" , esp_err_to_name (err ));
734
+ return false;
735
+ }
736
+
737
+ // Start the gamma curve fade
738
+ err = ledc_fade_start (group , channel , LEDC_FADE_NO_WAIT );
739
+ if (err != ESP_OK ) {
740
+ log_e ("ledc_fade_start failed: %s" , esp_err_to_name (err ));
741
+ return false;
742
+ }
743
+
744
+ log_d ("Gamma curve fade started on pin %u: %u -> %u over %dms" , pin , start_duty , target_duty , max_fade_time_ms );
745
+
746
+ } else {
747
+ log_e ("Pin %u is not attached to LEDC. Call ledcAttach first!" , pin );
748
+ return false;
749
+ }
750
+ return true;
751
+ }
752
+
753
+ bool ledcFadeGamma (uint8_t pin , uint32_t start_duty , uint32_t target_duty , int max_fade_time_ms ) {
754
+ return ledcFadeGammaConfig (pin , start_duty , target_duty , max_fade_time_ms , NULL , NULL );
755
+ }
756
+
757
+ bool ledcFadeGammaWithInterrupt (uint8_t pin , uint32_t start_duty , uint32_t target_duty , int max_fade_time_ms , voidFuncPtr userFunc ) {
758
+ return ledcFadeGammaConfig (pin , start_duty , target_duty , max_fade_time_ms , (voidFuncPtrArg )userFunc , NULL );
759
+ }
760
+
761
+ bool ledcFadeGammaWithInterruptArg (uint8_t pin , uint32_t start_duty , uint32_t target_duty , int max_fade_time_ms , void (* userFunc )(void * ), void * arg ) {
762
+ return ledcFadeGammaConfig (pin , start_duty , target_duty , max_fade_time_ms , userFunc , arg );
763
+ }
764
+
765
+ #endif /* SOC_LEDC_GAMMA_CURVE_FADE_SUPPORTED */
766
+
565
767
static uint8_t analog_resolution = 8 ;
566
768
static int analog_frequency = 1000 ;
567
769
void analogWrite (uint8_t pin , int value ) {
0 commit comments