Skip to content

Commit 7150245

Browse files
committed
feat(ledc): Enhance LEDC auto channel/timer selection for multi-group support
1 parent d71135e commit 7150245

File tree

1 file changed

+68
-30
lines changed

1 file changed

+68
-30
lines changed

cores/esp32/esp32-hal-ledc.c

Lines changed: 68 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -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

297319
bool 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

Comments
 (0)