@@ -45,6 +45,93 @@ 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 && 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
+
48
135
static bool fade_initialized = false;
49
136
50
137
static ledc_clk_cfg_t clock_source = LEDC_DEFAULT_CLK ;
@@ -81,6 +168,8 @@ static bool ledcDetachBus(void *bus) {
81
168
}
82
169
pinMatrixOutDetach (handle -> pin , false, false);
83
170
if (!channel_found ) {
171
+ uint8_t group = (handle -> channel / 8 );
172
+ remove_channel_from_timer (group , handle -> timer_num , handle -> channel % 8 );
84
173
ledc_handle .used_channels &= ~(1UL << handle -> channel );
85
174
}
86
175
free (handle );
@@ -117,26 +206,37 @@ bool ledcAttachChannel(uint8_t pin, uint32_t freq, uint8_t resolution, uint8_t c
117
206
return false;
118
207
}
119
208
120
- uint8_t group = (channel / 8 ), timer = ((channel / 2 ) % 4 );
209
+ uint8_t group = (channel / 8 );
210
+ uint8_t timer = 0 ;
121
211
bool channel_used = ledc_handle .used_channels & (1UL << channel );
212
+
122
213
if (channel_used ) {
123
214
log_i ("Channel %u is already set up, given frequency and resolution will be ignored" , channel );
124
215
if (ledc_set_pin (pin , group , channel % 8 ) != ESP_OK ) {
125
216
log_e ("Attaching pin to already used channel failed!" );
126
217
return false;
127
218
}
128
219
} 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
+ }
136
226
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
+ }
140
240
}
141
241
142
242
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
157
257
ledc_channel_handle_t * handle = (ledc_channel_handle_t * )malloc (sizeof (ledc_channel_handle_t ));
158
258
handle -> pin = pin ;
159
259
handle -> channel = channel ;
260
+ handle -> timer_num = timer ;
261
+ handle -> freq_hz = freq ;
160
262
#ifndef SOC_LEDC_SUPPORT_FADE_STOP
161
263
handle -> lock = NULL ;
162
264
#endif
0 commit comments