Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit cbdaee6

Browse files
P-R-O-C-H-Ylucasssvazpre-commit-ci-lite[bot]
authored
feat(ledc): Improve timer management with frequency/resolution matching (#11452)
* feat(ledc): Improve timer management with frequency/resolution matching * fix(ci): Fix uninitialized timer variable warning * Update cores/esp32/esp32-hal-ledc.c Co-authored-by: Lucas Saavedra Vaz <32426024+lucasssvaz@users.noreply.github.com> * ci(pre-commit): Apply automatic fixes --------- Co-authored-by: Lucas Saavedra Vaz <32426024+lucasssvaz@users.noreply.github.com> Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
1 parent d6a76da commit cbdaee6

File tree

2 files changed

+115
-11
lines changed

2 files changed

+115
-11
lines changed

‎cores/esp32/esp32-hal-ledc.c

Lines changed: 113 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,93 @@ typedef struct {
4545

4646
ledc_periph_t ledc_handle = {0};
4747

48+
// Helper function to find a timer with matching frequency and resolution
49+
static bool find_matching_timer(uint8_t speed_mode, uint32_t freq, uint8_t resolution, uint8_t *timer_num) {
50+
log_d("Searching for timer with freq=%u, resolution=%u", freq, resolution);
51+
// Check all channels to find one with matching frequency and resolution
52+
for (uint8_t i = 0; i < SOC_GPIO_PIN_COUNT; i++) {
53+
if (!perimanPinIsValid(i)) {
54+
continue;
55+
}
56+
peripheral_bus_type_t type = perimanGetPinBusType(i);
57+
if (type == ESP32_BUS_TYPE_LEDC) {
58+
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) {
60+
log_d("Found matching timer %u for freq=%u, resolution=%u", bus->timer_num, freq, resolution);
61+
*timer_num = bus->timer_num;
62+
return true;
63+
}
64+
}
65+
}
66+
log_d("No matching timer found for freq=%u, resolution=%u", freq, resolution);
67+
return false;
68+
}
69+
70+
// Helper function to find an unused timer
71+
static bool find_free_timer(uint8_t speed_mode, uint8_t *timer_num) {
72+
// Check which timers are in use
73+
uint8_t used_timers = 0;
74+
for (uint8_t i = 0; i < SOC_GPIO_PIN_COUNT; i++) {
75+
if (!perimanPinIsValid(i)) {
76+
continue;
77+
}
78+
peripheral_bus_type_t type = perimanGetPinBusType(i);
79+
if (type == ESP32_BUS_TYPE_LEDC) {
80+
ledc_channel_handle_t *bus = (ledc_channel_handle_t *)perimanGetPinBus(i, ESP32_BUS_TYPE_LEDC);
81+
if (bus != NULL && (bus->channel / 8) == speed_mode) {
82+
log_d("Timer %u is in use by channel %u", bus->timer_num, bus->channel);
83+
used_timers |= (1 << bus->timer_num);
84+
}
85+
}
86+
}
87+
88+
// Find first unused timer
89+
for (uint8_t i = 0; i < SOC_LEDC_TIMER_NUM; i++) {
90+
if (!(used_timers & (1 << i))) {
91+
log_d("Found free timer %u", i);
92+
*timer_num = i;
93+
return true;
94+
}
95+
}
96+
log_e("No free timers available");
97+
return false;
98+
}
99+
100+
// Helper function to remove a channel from a timer and clear timer if no channels are using it
101+
static void remove_channel_from_timer(uint8_t speed_mode, uint8_t timer_num, uint8_t channel) {
102+
log_d("Removing channel %u from timer %u in speed_mode %u", channel, timer_num, speed_mode);
103+
104+
// Check if any other channels are using this timer
105+
bool timer_in_use = false;
106+
for (uint8_t i = 0; i < SOC_GPIO_PIN_COUNT; i++) {
107+
if (!perimanPinIsValid(i)) {
108+
continue;
109+
}
110+
peripheral_bus_type_t type = perimanGetPinBusType(i);
111+
if (type == ESP32_BUS_TYPE_LEDC) {
112+
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) {
114+
log_d("Timer %u is still in use by channel %u", timer_num, bus->channel);
115+
timer_in_use = true;
116+
break;
117+
}
118+
}
119+
}
120+
121+
if (!timer_in_use) {
122+
log_d("No other channels using timer %u, deconfiguring timer", timer_num);
123+
// Stop the timer
124+
ledc_timer_pause(speed_mode, timer_num);
125+
// Deconfigure the timer
126+
ledc_timer_config_t ledc_timer;
127+
memset((void *)&ledc_timer, 0, sizeof(ledc_timer_config_t));
128+
ledc_timer.speed_mode = speed_mode;
129+
ledc_timer.timer_num = timer_num;
130+
ledc_timer.deconfigure = true;
131+
ledc_timer_config(&ledc_timer);
132+
}
133+
}
134+
48135
static bool fade_initialized = false;
49136

50137
static ledc_clk_cfg_t clock_source = LEDC_DEFAULT_CLK;
@@ -81,6 +168,8 @@ static bool ledcDetachBus(void *bus) {
81168
}
82169
pinMatrixOutDetach(handle->pin, false, false);
83170
if (!channel_found) {
171+
uint8_t group = (handle->channel / 8);
172+
remove_channel_from_timer(group, handle->timer_num, handle->channel % 8);
84173
ledc_handle.used_channels &= ~(1UL << handle->channel);
85174
}
86175
free(handle);
@@ -117,26 +206,37 @@ bool ledcAttachChannel(uint8_t pin, uint32_t freq, uint8_t resolution, uint8_t c
117206
return false;
118207
}
119208

120-
uint8_t group = (channel / 8), timer = ((channel / 2) % 4);
209+
uint8_t group = (channel / 8);
210+
uint8_t timer = 0;
121211
bool channel_used = ledc_handle.used_channels & (1UL << channel);
212+
122213
if (channel_used) {
123214
log_i("Channel %u is already set up, given frequency and resolution will be ignored", channel);
124215
if (ledc_set_pin(pin, group, channel % 8) != ESP_OK) {
125216
log_e("Attaching pin to already used channel failed!");
126217
return false;
127218
}
128219
} else {
129-
ledc_timer_config_t ledc_timer;
130-
memset((void *)&ledc_timer, 0, sizeof(ledc_timer_config_t));
131-
ledc_timer.speed_mode = group;
132-
ledc_timer.timer_num = timer;
133-
ledc_timer.duty_resolution = resolution;
134-
ledc_timer.freq_hz = freq;
135-
ledc_timer.clk_cfg = clock_source;
220+
// Find a timer with matching frequency and resolution, or a free timer
221+
if (!find_matching_timer(group, freq, resolution, &timer)) {
222+
if (!find_free_timer(group, &timer)) {
223+
log_e("No free timers available for speed mode %u", group);
224+
return false;
225+
}
136226

137-
if (ledc_timer_config(&ledc_timer) != ESP_OK) {
138-
log_e("ledc setup failed!");
139-
return false;
227+
// Configure the timer if we're using a new one
228+
ledc_timer_config_t ledc_timer;
229+
memset((void *)&ledc_timer, 0, sizeof(ledc_timer_config_t));
230+
ledc_timer.speed_mode = group;
231+
ledc_timer.timer_num = timer;
232+
ledc_timer.duty_resolution = resolution;
233+
ledc_timer.freq_hz = freq;
234+
ledc_timer.clk_cfg = clock_source;
235+
236+
if (ledc_timer_config(&ledc_timer) != ESP_OK) {
237+
log_e("ledc setup failed!");
238+
return false;
239+
}
140240
}
141241

142242
uint32_t duty = ledc_get_duty(group, (channel % 8));
@@ -157,6 +257,8 @@ bool ledcAttachChannel(uint8_t pin, uint32_t freq, uint8_t resolution, uint8_t c
157257
ledc_channel_handle_t *handle = (ledc_channel_handle_t *)malloc(sizeof(ledc_channel_handle_t));
158258
handle->pin = pin;
159259
handle->channel = channel;
260+
handle->timer_num = timer;
261+
handle->freq_hz = freq;
160262
#ifndef SOC_LEDC_SUPPORT_FADE_STOP
161263
handle->lock = NULL;
162264
#endif

‎cores/esp32/esp32-hal-ledc.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ typedef struct {
5151
uint8_t pin; // Pin assigned to channel
5252
uint8_t channel; // Channel number
5353
uint8_t channel_resolution; // Resolution of channel
54+
uint8_t timer_num; // Timer number used by this channel
55+
uint32_t freq_hz; // Frequency configured for this channel
5456
voidFuncPtr fn;
5557
void *arg;
5658
#ifndef SOC_LEDC_SUPPORT_FADE_STOP

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /