@@ -56,7 +56,7 @@ static bool find_matching_timer(uint8_t speed_mode, uint32_t freq, uint8_t resol
5656 peripheral_bus_type_t type = perimanGetPinBusType (i );
5757 if (type == ESP32_BUS_TYPE_LEDC ) {
5858 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 ) {
59+ if (bus != NULL && (bus -> channel / SOC_LEDC_CHANNEL_NUM ) == speed_mode && bus -> freq_hz == freq && bus -> channel_resolution == resolution ) {
6060 log_d ("Found matching timer %u for freq=%u, resolution=%u" , bus -> timer_num , freq , resolution );
6161 * timer_num = bus -> timer_num ;
6262 return true;
@@ -78,7 +78,7 @@ static bool find_free_timer(uint8_t speed_mode, uint8_t *timer_num) {
7878 peripheral_bus_type_t type = perimanGetPinBusType (i );
7979 if (type == ESP32_BUS_TYPE_LEDC ) {
8080 ledc_channel_handle_t * bus = (ledc_channel_handle_t * )perimanGetPinBus (i , ESP32_BUS_TYPE_LEDC );
81- if (bus != NULL && (bus -> channel / 8 ) == speed_mode ) {
81+ if (bus != NULL && (bus -> channel / SOC_LEDC_CHANNEL_NUM ) == speed_mode ) {
8282 log_d ("Timer %u is in use by channel %u" , bus -> timer_num , bus -> channel );
8383 used_timers |= (1 << bus -> timer_num );
8484 }
@@ -110,7 +110,7 @@ static void remove_channel_from_timer(uint8_t speed_mode, uint8_t timer_num, uin
110110 peripheral_bus_type_t type = perimanGetPinBusType (i );
111111 if (type == ESP32_BUS_TYPE_LEDC ) {
112112 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 ) {
113+ if (bus != NULL && (bus -> channel / SOC_LEDC_CHANNEL_NUM ) == speed_mode && bus -> timer_num == timer_num && bus -> channel != channel ) {
114114 log_d ("Timer %u is still in use by channel %u" , timer_num , bus -> channel );
115115 timer_in_use = true;
116116 break ;
@@ -168,8 +168,8 @@ static bool ledcDetachBus(void *bus) {
168168 }
169169 pinMatrixOutDetach (handle -> pin , false, false);
170170 if (!channel_found ) {
171- uint8_t group = (handle -> channel / 8 );
172- remove_channel_from_timer (group , handle -> timer_num , handle -> channel % 8 );
171+ uint8_t group = (handle -> channel / SOC_LEDC_CHANNEL_NUM );
172+ remove_channel_from_timer (group , handle -> timer_num , handle -> channel % SOC_LEDC_CHANNEL_NUM );
173173 ledc_handle .used_channels &= ~(1UL << handle -> channel );
174174 }
175175 free (handle );
@@ -206,21 +206,21 @@ bool ledcAttachChannel(uint8_t pin, uint32_t freq, uint8_t resolution, uint8_t c
206206 return false;
207207 }
208208
209- uint8_t group = (channel / 8 );
209+ uint8_t group = (channel / SOC_LEDC_CHANNEL_NUM );
210210 uint8_t timer = 0 ;
211211 bool channel_used = ledc_handle .used_channels & (1UL << channel );
212212
213213 if (channel_used ) {
214214 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 ) {
215+ if (ledc_set_pin (pin , group , channel % SOC_LEDC_CHANNEL_NUM ) != ESP_OK ) {
216216 log_e ("Attaching pin to already used channel failed!" );
217217 return false;
218218 }
219219 } else {
220220 // Find a timer with matching frequency and resolution, or a free timer
221221 if (!find_matching_timer (group , freq , resolution , & timer )) {
222222 if (!find_free_timer (group , & timer )) {
223- log_e ("No free timers available for speed mode %u" , group );
223+ log_w ("No free timers available for speed mode %u" , group );
224224 return false;
225225 }
226226
@@ -239,12 +239,12 @@ bool ledcAttachChannel(uint8_t pin, uint32_t freq, uint8_t resolution, uint8_t c
239239 }
240240 }
241241
242- uint32_t duty = ledc_get_duty (group , (channel % 8 ));
242+ uint32_t duty = ledc_get_duty (group , (channel % SOC_LEDC_CHANNEL_NUM ));
243243
244244 ledc_channel_config_t ledc_channel ;
245245 memset ((void * )& ledc_channel , 0 , sizeof (ledc_channel_config_t ));
246246 ledc_channel .speed_mode = group ;
247- ledc_channel .channel = (channel % 8 );
247+ ledc_channel .channel = (channel % SOC_LEDC_CHANNEL_NUM );
248248 ledc_channel .timer_sel = timer ;
249249 ledc_channel .intr_type = LEDC_INTR_DISABLE ;
250250 ledc_channel .gpio_num = pin ;
@@ -291,14 +291,36 @@ bool ledcAttach(uint8_t pin, uint32_t freq, uint8_t resolution) {
291291 }
292292 uint8_t channel = __builtin_ctz (free_channel ); // Convert the free_channel bit to channel number
293293
294- return ledcAttachChannel (pin , freq , resolution , channel );
294+ // Try the first available channel
295+ if (ledcAttachChannel (pin , freq , resolution , channel )) {
296+ return true;
297+ }
298+
299+ #ifdef SOC_LEDC_SUPPORT_HS_MODE
300+ // If first attempt failed and HS mode is supported, try to find a free channel in group 1
301+ if ((channel / SOC_LEDC_CHANNEL_NUM ) == 0 ) { // First attempt was in group 0
302+ log_d ("LEDC: Group 0 channel %u failed, trying to find a free channel in group 1" , channel );
303+ // Find free channels specifically in group 1
304+ uint32_t group1_mask = ((1UL << SOC_LEDC_CHANNEL_NUM ) - 1 ) << SOC_LEDC_CHANNEL_NUM ;
305+ int group1_free_channel = (~ledc_handle .used_channels ) & group1_mask ;
306+ if (group1_free_channel != 0 ) {
307+ uint8_t group1_channel = __builtin_ctz (group1_free_channel );
308+ if (ledcAttachChannel (pin , freq , resolution , group1_channel )) {
309+ return true;
310+ }
311+ }
312+ }
313+ #endif
314+
315+ log_e ("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 share its timer." , freq , resolution );
316+ return false;
295317}
296318
297319bool ledcWrite (uint8_t pin , uint32_t duty ) {
298320 ledc_channel_handle_t * bus = (ledc_channel_handle_t * )perimanGetPinBus (pin , ESP32_BUS_TYPE_LEDC );
299321 if (bus != NULL ) {
300322
301- uint8_t group = (bus -> channel / 8 ), channel = (bus -> channel % 8 );
323+ uint8_t group = (bus -> channel / SOC_LEDC_CHANNEL_NUM ), channel = (bus -> channel % SOC_LEDC_CHANNEL_NUM );
302324
303325 //Fixing if all bits in resolution is set = LEDC FULL ON
304326 uint32_t max_duty = (1 << bus -> channel_resolution ) - 1 ;
@@ -307,8 +329,14 @@ bool ledcWrite(uint8_t pin, uint32_t duty) {
307329 duty = max_duty + 1 ;
308330 }
309331
310- ledc_set_duty (group , channel , duty );
311- ledc_update_duty (group , channel );
332+ if (ledc_set_duty (group , channel , duty ) != ESP_OK ) {
333+ log_e ("ledc_set_duty failed" );
334+ return false;
335+ }
336+ if (ledc_update_duty (group , channel ) != ESP_OK ) {
337+ log_e ("ledc_update_duty failed" );
338+ return false;
339+ }
312340
313341 return true;
314342 }
@@ -321,7 +349,11 @@ bool ledcWriteChannel(uint8_t channel, uint32_t duty) {
321349 log_e ("Channel %u is not available (maximum %u) or not used!" , channel , LEDC_CHANNELS );
322350 return false;
323351 }
324- uint8_t group = (channel / 8 ), timer = ((channel / 2 ) % 4 );
352+ uint8_t group = (channel / SOC_LEDC_CHANNEL_NUM );
353+ ledc_timer_t timer ;
354+
355+ // Get the actual timer being used by this channel
356+ ledc_ll_get_channel_timer (LEDC_LL_GET_HW (), group , (channel % SOC_LEDC_CHANNEL_NUM ), & timer );
325357
326358 //Fixing if all bits in resolution is set = LEDC FULL ON
327359 uint32_t resolution = 0 ;
@@ -333,8 +365,14 @@ bool ledcWriteChannel(uint8_t channel, uint32_t duty) {
333365 duty = max_duty + 1 ;
334366 }
335367
336- ledc_set_duty (group , channel , duty );
337- ledc_update_duty (group , channel );
368+ if (ledc_set_duty (group , channel , duty ) != ESP_OK ) {
369+ log_e ("ledc_set_duty failed" );
370+ return false;
371+ }
372+ if (ledc_update_duty (group , channel ) != ESP_OK ) {
373+ log_e ("ledc_update_duty failed" );
374+ return false;
375+ }
338376
339377 return true;
340378}
@@ -343,7 +381,7 @@ uint32_t ledcRead(uint8_t pin) {
343381 ledc_channel_handle_t * bus = (ledc_channel_handle_t * )perimanGetPinBus (pin , ESP32_BUS_TYPE_LEDC );
344382 if (bus != NULL ) {
345383
346- uint8_t group = (bus -> channel / 8 ), channel = (bus -> channel % 8 );
384+ uint8_t group = (bus -> channel / SOC_LEDC_CHANNEL_NUM ), channel = (bus -> channel % SOC_LEDC_CHANNEL_NUM );
347385 return ledc_get_duty (group , channel );
348386 }
349387 return 0 ;
@@ -355,8 +393,8 @@ uint32_t ledcReadFreq(uint8_t pin) {
355393 if (!ledcRead (pin )) {
356394 return 0 ;
357395 }
358- uint8_t group = (bus -> channel / 8 ), timer = (( bus -> channel / 2 ) % 4 );
359- return ledc_get_freq (group , timer );
396+ uint8_t group = (bus -> channel / SOC_LEDC_CHANNEL_NUM );
397+ return ledc_get_freq (group , bus -> timer_num );
360398 }
361399 return 0 ;
362400}
@@ -370,12 +408,12 @@ uint32_t ledcWriteTone(uint8_t pin, uint32_t freq) {
370408 return 0 ;
371409 }
372410
373- uint8_t group = (bus -> channel / 8 ), timer = (( bus -> channel / 2 ) % 4 );
411+ uint8_t group = (bus -> channel / SOC_LEDC_CHANNEL_NUM );
374412
375413 ledc_timer_config_t ledc_timer ;
376414 memset ((void * )& ledc_timer , 0 , sizeof (ledc_timer_config_t ));
377415 ledc_timer .speed_mode = group ;
378- ledc_timer .timer_num = timer ;
416+ ledc_timer .timer_num = bus -> timer_num ;
379417 ledc_timer .duty_resolution = 10 ;
380418 ledc_timer .freq_hz = freq ;
381419 ledc_timer .clk_cfg = clock_source ;
@@ -386,7 +424,7 @@ uint32_t ledcWriteTone(uint8_t pin, uint32_t freq) {
386424 }
387425 bus -> channel_resolution = 10 ;
388426
389- uint32_t res_freq = ledc_get_freq (group , timer );
427+ uint32_t res_freq = ledc_get_freq (group , bus -> timer_num );
390428 ledcWrite (pin , 0x1FF );
391429 return res_freq ;
392430 }
@@ -427,12 +465,12 @@ uint32_t ledcChangeFrequency(uint8_t pin, uint32_t freq, uint8_t resolution) {
427465 log_e ("LEDC pin %u - resolution is zero or it is too big (maximum %u)" , pin , LEDC_MAX_BIT_WIDTH );
428466 return 0 ;
429467 }
430- uint8_t group = (bus -> channel / 8 ), timer = (( bus -> channel / 2 ) % 4 );
468+ uint8_t group = (bus -> channel / SOC_LEDC_CHANNEL_NUM );
431469
432470 ledc_timer_config_t ledc_timer ;
433471 memset ((void * )& ledc_timer , 0 , sizeof (ledc_timer_config_t ));
434472 ledc_timer .speed_mode = group ;
435- ledc_timer .timer_num = timer ;
473+ ledc_timer .timer_num = bus -> timer_num ;
436474 ledc_timer .duty_resolution = resolution ;
437475 ledc_timer .freq_hz = freq ;
438476 ledc_timer .clk_cfg = clock_source ;
@@ -442,7 +480,7 @@ uint32_t ledcChangeFrequency(uint8_t pin, uint32_t freq, uint8_t resolution) {
442480 return 0 ;
443481 }
444482 bus -> channel_resolution = resolution ;
445- return ledc_get_freq (group , timer );
483+ return ledc_get_freq (group , bus -> timer_num );
446484 }
447485 return 0 ;
448486}
@@ -453,12 +491,12 @@ bool ledcOutputInvert(uint8_t pin, bool out_invert) {
453491 gpio_set_level (pin , out_invert );
454492
455493#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 );
494+ esp_rom_gpio_connect_out_signal (pin , LEDC_LS_SIG_OUT_PAD_OUT0_IDX + ((bus -> channel ) % SOC_LEDC_CHANNEL_NUM ), out_invert , 0 );
457495#else
458496#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 );
497+ esp_rom_gpio_connect_out_signal (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 );
460498#else
461- esp_rom_gpio_connect_out_signal (pin , LEDC_LS_SIG_OUT0_IDX + ((bus -> channel ) % 8 ), out_invert , 0 );
499+ esp_rom_gpio_connect_out_signal (pin , LEDC_LS_SIG_OUT0_IDX + ((bus -> channel ) % SOC_LEDC_CHANNEL_NUM ), out_invert , 0 );
462500#endif
463501#endif // ifdef CONFIG_IDF_TARGET_ESP32P4
464502 return true;
@@ -505,7 +543,7 @@ static bool ledcFadeConfig(uint8_t pin, uint32_t start_duty, uint32_t target_dut
505543 }
506544#endif
507545#endif
508- uint8_t group = (bus -> channel / 8 ), channel = (bus -> channel % 8 );
546+ uint8_t group = (bus -> channel / SOC_LEDC_CHANNEL_NUM ), channel = (bus -> channel % SOC_LEDC_CHANNEL_NUM );
509547
510548 // Initialize fade service.
511549 if (!fade_initialized ) {
0 commit comments