@@ -45,6 +45,96 @@ typedef struct {
45
45
46
46
ledc_periph_t ledc_handle = {0 };
47
47
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 ) {
60
+ if (bus -> freq_hz == freq && bus -> channel_resolution == resolution ) {
61
+ log_d ("Found matching timer %u for freq=%u, resolution=%u" , bus -> timer_num , freq , resolution );
62
+ * timer_num = bus -> timer_num ;
63
+ return true;
64
+ }
65
+ }
66
+ }
67
+ }
68
+ log_d ("No matching timer found for freq=%u, resolution=%u" , freq , resolution );
69
+ return false;
70
+ }
71
+
72
+ // Helper function to find an unused timer
73
+ static bool find_free_timer (uint8_t speed_mode , uint8_t * timer_num ) {
74
+ // Check which timers are in use
75
+ uint8_t used_timers = 0 ;
76
+ for (uint8_t i = 0 ; i < SOC_GPIO_PIN_COUNT ; i ++ ) {
77
+ if (!perimanPinIsValid (i )) {
78
+ continue ;
79
+ }
80
+ peripheral_bus_type_t type = perimanGetPinBusType (i );
81
+ if (type == ESP32_BUS_TYPE_LEDC ) {
82
+ ledc_channel_handle_t * bus = (ledc_channel_handle_t * )perimanGetPinBus (i , ESP32_BUS_TYPE_LEDC );
83
+ if (bus != NULL && (bus -> channel / 8 ) == speed_mode ) {
84
+ log_d ("Timer %u is in use by channel %u" , bus -> timer_num , bus -> channel );
85
+ used_timers |= (1 << bus -> timer_num );
86
+ }
87
+ }
88
+ }
89
+
90
+ // Find first unused timer
91
+ for (uint8_t i = 0 ; i < SOC_LEDC_TIMER_NUM ; i ++ ) {
92
+ if (!(used_timers & (1 << i ))) {
93
+ log_d ("Found free timer %u" , i );
94
+ * timer_num = i ;
95
+ return true;
96
+ }
97
+ }
98
+ log_e ("No free timers available" );
99
+ return false;
100
+ }
101
+
102
+ // Helper function to remove a channel from a timer and clear timer if no channels are using it
103
+ static void remove_channel_from_timer (uint8_t speed_mode , uint8_t timer_num , uint8_t channel ) {
104
+ log_d ("Removing channel %u from timer %u in speed_mode %u" , channel , timer_num , speed_mode );
105
+
106
+ // Check if any other channels are using this timer
107
+ bool timer_in_use = false;
108
+ for (uint8_t i = 0 ; i < SOC_GPIO_PIN_COUNT ; i ++ ) {
109
+ if (!perimanPinIsValid (i )) {
110
+ continue ;
111
+ }
112
+ peripheral_bus_type_t type = perimanGetPinBusType (i );
113
+ if (type == ESP32_BUS_TYPE_LEDC ) {
114
+ ledc_channel_handle_t * bus = (ledc_channel_handle_t * )perimanGetPinBus (i , ESP32_BUS_TYPE_LEDC );
115
+ if (bus != NULL && (bus -> channel / 8 ) == speed_mode &&
116
+ bus -> timer_num == timer_num && bus -> channel != channel ) {
117
+ log_d ("Timer %u is still in use by channel %u" , timer_num , bus -> channel );
118
+ timer_in_use = true;
119
+ break ;
120
+ }
121
+ }
122
+ }
123
+
124
+ if (!timer_in_use ) {
125
+ log_d ("No other channels using timer %u, deconfiguring timer" , timer_num );
126
+ // Stop the timer
127
+ ledc_timer_pause (speed_mode , timer_num );
128
+ // Deconfigure the timer
129
+ ledc_timer_config_t ledc_timer ;
130
+ memset ((void * )& ledc_timer , 0 , sizeof (ledc_timer_config_t ));
131
+ ledc_timer .speed_mode = speed_mode ;
132
+ ledc_timer .timer_num = timer_num ;
133
+ ledc_timer .deconfigure = true;
134
+ ledc_timer_config (& ledc_timer );
135
+ }
136
+ }
137
+
48
138
static bool fade_initialized = false;
49
139
50
140
static ledc_clk_cfg_t clock_source = LEDC_DEFAULT_CLK ;
@@ -81,6 +171,8 @@ static bool ledcDetachBus(void *bus) {
81
171
}
82
172
pinMatrixOutDetach (handle -> pin , false, false);
83
173
if (!channel_found ) {
174
+ uint8_t group = (handle -> channel / 8 );
175
+ remove_channel_from_timer (group , handle -> timer_num , handle -> channel % 8 );
84
176
ledc_handle .used_channels &= ~(1UL << handle -> channel );
85
177
}
86
178
free (handle );
@@ -117,26 +209,37 @@ bool ledcAttachChannel(uint8_t pin, uint32_t freq, uint8_t resolution, uint8_t c
117
209
return false;
118
210
}
119
211
120
- uint8_t group = (channel / 8 ), timer = ((channel / 2 ) % 4 );
212
+ uint8_t group = (channel / 8 );
213
+ uint8_t timer ;
121
214
bool channel_used = ledc_handle .used_channels & (1UL << channel );
215
+
122
216
if (channel_used ) {
123
217
log_i ("Channel %u is already set up, given frequency and resolution will be ignored" , channel );
124
218
if (ledc_set_pin (pin , group , channel % 8 ) != ESP_OK ) {
125
219
log_e ("Attaching pin to already used channel failed!" );
126
220
return false;
127
221
}
128
222
} 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 ;
136
-
137
- if (ledc_timer_config (& ledc_timer ) != ESP_OK ) {
138
- log_e ("ledc setup failed!" );
139
- return false;
223
+ // Find a timer with matching frequency and resolution, or a free timer
224
+ if (!find_matching_timer (group , freq , resolution , & timer )) {
225
+ if (!find_free_timer (group , & timer )) {
226
+ log_e ("No free timers available for speed mode %u" , group );
227
+ return false;
228
+ }
229
+
230
+ // Configure the timer if we're using a new one
231
+ ledc_timer_config_t ledc_timer ;
232
+ memset ((void * )& ledc_timer , 0 , sizeof (ledc_timer_config_t ));
233
+ ledc_timer .speed_mode = group ;
234
+ ledc_timer .timer_num = timer ;
235
+ ledc_timer .duty_resolution = resolution ;
236
+ ledc_timer .freq_hz = freq ;
237
+ ledc_timer .clk_cfg = clock_source ;
238
+
239
+ if (ledc_timer_config (& ledc_timer ) != ESP_OK ) {
240
+ log_e ("ledc setup failed!" );
241
+ return false;
242
+ }
140
243
}
141
244
142
245
uint32_t duty = ledc_get_duty (group , (channel % 8 ));
@@ -157,6 +260,8 @@ bool ledcAttachChannel(uint8_t pin, uint32_t freq, uint8_t resolution, uint8_t c
157
260
ledc_channel_handle_t * handle = (ledc_channel_handle_t * )malloc (sizeof (ledc_channel_handle_t ));
158
261
handle -> pin = pin ;
159
262
handle -> channel = channel ;
263
+ handle -> timer_num = timer ;
264
+ handle -> freq_hz = freq ;
160
265
#ifndef SOC_LEDC_SUPPORT_FADE_STOP
161
266
handle -> lock = NULL ;
162
267
#endif
0 commit comments