@@ -40,45 +40,57 @@ typedef struct _esp32_pwm_obj_t {
40
40
gpio_num_t pin ;
41
41
uint8_t active ;
42
42
uint8_t channel ;
43
+ uint8_t timer ;
43
44
} esp32_pwm_obj_t ;
44
45
45
46
// Which channel has which GPIO pin assigned?
46
47
// (-1 if not assigned)
47
48
STATIC int chan_gpio [LEDC_CHANNEL_MAX ];
48
49
50
+ // Which channel has which timer assigned?
51
+ // (-1 if not assigned)
52
+ STATIC int chan_timer [LEDC_CHANNEL_MAX ];
53
+
54
+ // List of timer configs
55
+ STATIC ledc_timer_config_t timers [LEDC_TIMER_MAX ];
56
+
49
57
// Params for PW operation
50
58
// 5khz
51
59
#define PWFREQ (5000)
52
60
// High speed mode
53
61
#define PWMODE (LEDC_HIGH_SPEED_MODE)
54
62
// 10-bit resolution (compatible with esp8266 PWM)
55
63
#define PWRES (LEDC_TIMER_10_BIT)
56
- // Timer 1
57
- #define PWTIMER (LEDC_TIMER_1)
58
64
59
65
// Config of timer upon which we run all PWM'ed GPIO pins
60
66
STATIC bool pwm_inited = false;
61
- STATIC ledc_timer_config_t timer_cfg = {
62
- .duty_resolution = PWRES ,
63
- .freq_hz = PWFREQ ,
64
- .speed_mode = PWMODE ,
65
- .timer_num = PWTIMER
66
- };
67
67
68
68
STATIC void pwm_init (void ) {
69
69
70
70
// Initial condition: no channels assigned
71
71
for (int x = 0 ; x < LEDC_CHANNEL_MAX ; ++ x ) {
72
72
chan_gpio [x ] = -1 ;
73
+ chan_timer [x ] = -1 ;
73
74
}
74
75
75
- // Init with default timer params
76
- ledc_timer_config (& timer_cfg );
76
+ // Initial condition: no timers assigned
77
+ for (int x = 0 ; x < LEDC_TIMER_MAX ; ++ x ) {
78
+ timers [x ].duty_resolution = PWRES ;
79
+ // unset timer is -1
80
+ timers [x ].freq_hz = -1 ;
81
+ timers [x ].speed_mode = PWMODE ;
82
+ timers [x ].timer_num = x ;
83
+ }
77
84
}
78
85
79
- STATIC int set_freq (int newval ) {
80
- int ores = timer_cfg .duty_resolution ;
81
- int oval = timer_cfg .freq_hz ;
86
+ STATIC int set_freq (int newval , ledc_timer_config_t * timer ) {
87
+ int ores = timer -> duty_resolution ;
88
+ int oval = timer -> freq_hz ;
89
+
90
+ // If already set, do nothing
91
+ if (newval == oval ) {
92
+ return 1 ;
93
+ }
82
94
83
95
// Find the highest bit resolution for the requested frequency
84
96
if (newval <= 0 ) {
@@ -95,16 +107,39 @@ STATIC int set_freq(int newval) {
95
107
}
96
108
97
109
// Configure the new resolution and frequency
98
- timer_cfg . duty_resolution = res ;
99
- timer_cfg . freq_hz = newval ;
100
- if (ledc_timer_config (& timer_cfg ) != ESP_OK ) {
101
- timer_cfg . duty_resolution = ores ;
102
- timer_cfg . freq_hz = oval ;
110
+ timer -> duty_resolution = res ;
111
+ timer -> freq_hz = newval ;
112
+ if (ledc_timer_config (timer ) != ESP_OK ) {
113
+ timer -> duty_resolution = ores ;
114
+ timer -> freq_hz = oval ;
103
115
return 0 ;
104
116
}
105
117
return 1 ;
106
118
}
107
119
120
+ STATIC int found_timer (int freq ) {
121
+ int timer_found = -1 ;
122
+ int timer ;
123
+ // Find a free PWM Timer using the same freq
124
+ for (timer = 0 ; timer < LEDC_TIMER_MAX ; ++ timer ) {
125
+ if (timers [timer ].freq_hz == freq ) {
126
+ break ;
127
+ }
128
+ if ((timer_found == -1 ) && (timers [timer ].freq_hz == -1 )) {
129
+ timer_found = timer ;
130
+ }
131
+ }
132
+ if (timer >= LEDC_TIMER_MAX ) {
133
+ if (timer_found == -1 ) {
134
+ timer = -1 ;
135
+ } else {
136
+ timer = timer_found ;
137
+ }
138
+ }
139
+
140
+ return timer ;
141
+ }
142
+
108
143
/******************************************************************************/
109
144
110
145
// MicroPython bindings for PWM
@@ -113,7 +148,7 @@ STATIC void esp32_pwm_print(const mp_print_t *print, mp_obj_t self_in, mp_print_
113
148
esp32_pwm_obj_t * self = MP_OBJ_TO_PTR (self_in );
114
149
mp_printf (print , "PWM(%u" , self -> pin );
115
150
if (self -> active ) {
116
- mp_printf (print , ", freq=%u, duty=%u" , timer_cfg .freq_hz ,
151
+ mp_printf (print , ", freq=%u, duty=%u" , timers [ self -> timer ] .freq_hz ,
117
152
ledc_get_duty (PWMODE , self -> channel ));
118
153
}
119
154
mp_printf (print , ")" );
@@ -151,38 +186,48 @@ STATIC void esp32_pwm_init_helper(esp32_pwm_obj_t *self,
151
186
}
152
187
self -> channel = channel ;
153
188
189
+ int timer ;
190
+ int freq = args [ARG_freq ].u_int ;
191
+
192
+ if (freq == -1 ) {
193
+ freq = PWFREQ ;
194
+ }
195
+
196
+ timer = found_timer (freq );
197
+
198
+ if (timer == -1 ) {
199
+ mp_raise_ValueError (MP_ERROR_TEXT ("out of PWM timers" ));
200
+ }
201
+ self -> timer = timer ;
202
+ chan_timer [channel ] = timer ;
203
+
154
204
// New PWM assignment
155
205
self -> active = 1 ;
156
206
if (chan_gpio [channel ] == -1 ) {
157
207
ledc_channel_config_t cfg = {
158
208
.channel = channel ,
159
- .duty = (1 << timer_cfg .duty_resolution ) / 2 ,
209
+ .duty = (1 << timers [ timer ] .duty_resolution ) / 2 ,
160
210
.gpio_num = self -> pin ,
161
211
.intr_type = LEDC_INTR_DISABLE ,
162
212
.speed_mode = PWMODE ,
163
- .timer_sel = PWTIMER ,
213
+ .timer_sel = timer ,
164
214
};
165
215
if (ledc_channel_config (& cfg ) != ESP_OK ) {
166
216
mp_raise_msg_varg (& mp_type_ValueError , MP_ERROR_TEXT ("PWM not supported on pin %d" ), self -> pin );
167
217
}
168
218
chan_gpio [channel ] = self -> pin ;
169
219
}
170
220
171
- // Maybe change PWM timer
172
- int tval = args [ARG_freq ].u_int ;
173
- if (tval != -1 ) {
174
- if (tval != timer_cfg .freq_hz ) {
175
- if (!set_freq (tval )) {
176
- mp_raise_msg_varg (& mp_type_ValueError , MP_ERROR_TEXT ("bad frequency %d" ), tval );
177
- }
178
- }
221
+ // Set timer frequency
222
+ if (!set_freq (freq , & timers [timer ])) {
223
+ mp_raise_msg_varg (& mp_type_ValueError , MP_ERROR_TEXT ("bad frequency %d" ), freq );
179
224
}
180
225
181
226
// Set duty cycle?
182
227
int dval = args [ARG_duty ].u_int ;
183
228
if (dval != -1 ) {
184
229
dval &= ((1 << PWRES ) - 1 );
185
- dval >>= PWRES - timer_cfg .duty_resolution ;
230
+ dval >>= PWRES - timers [ timer ] .duty_resolution ;
186
231
ledc_set_duty (PWMODE , channel , dval );
187
232
ledc_update_duty (PWMODE , channel );
188
233
}
@@ -229,6 +274,7 @@ STATIC mp_obj_t esp32_pwm_deinit(mp_obj_t self_in) {
229
274
if ((chan >= 0 ) && (chan < LEDC_CHANNEL_MAX )) {
230
275
// Mark it unused, and tell the hardware to stop routing
231
276
chan_gpio [chan ] = -1 ;
277
+ chan_timer [chan ] = -1 ;
232
278
ledc_stop (PWMODE , chan , 0 );
233
279
self -> active = 0 ;
234
280
self -> channel = -1 ;
@@ -239,14 +285,51 @@ STATIC mp_obj_t esp32_pwm_deinit(mp_obj_t self_in) {
239
285
STATIC MP_DEFINE_CONST_FUN_OBJ_1 (esp32_pwm_deinit_obj , esp32_pwm_deinit );
240
286
241
287
STATIC mp_obj_t esp32_pwm_freq (size_t n_args , const mp_obj_t * args ) {
288
+ esp32_pwm_obj_t * self = MP_OBJ_TO_PTR (args [0 ]);
242
289
if (n_args == 1 ) {
243
290
// get
244
- return MP_OBJ_NEW_SMALL_INT (timer_cfg .freq_hz );
291
+ return MP_OBJ_NEW_SMALL_INT (timers [ self -> timer ] .freq_hz );
245
292
}
246
293
247
294
// set
248
295
int tval = mp_obj_get_int (args [1 ]);
249
- if (!set_freq (tval )) {
296
+
297
+ // If the timer is no longer used, clean it
298
+ int old_timer = self -> timer ;
299
+
300
+ bool used = false;
301
+ int i ;
302
+ for (i = 0 ; i < LEDC_CHANNEL_MAX ; ++ i ) {
303
+ if (i != self -> channel && chan_timer [i ] == old_timer ) {
304
+ used = true;
305
+ break ;
306
+ }
307
+ }
308
+
309
+ // If timer is not used, clean it
310
+ if (!used ) {
311
+ ledc_timer_pause (PWMODE , old_timer );
312
+
313
+ // Flag it unused
314
+ timers [old_timer ].freq_hz = -1 ;
315
+ }
316
+
317
+ // Check if a timer already use the new freq, or grab a new one
318
+ int new_timer = found_timer (tval );
319
+
320
+ if (new_timer == -1 ) {
321
+ mp_raise_ValueError (MP_ERROR_TEXT ("out of PWM timers" ));
322
+ }
323
+
324
+ self -> timer = new_timer ;
325
+ chan_timer [self -> channel ] = new_timer ;
326
+
327
+
328
+ if (ledc_bind_channel_timer (PWMODE , self -> channel , new_timer ) != ESP_OK ) {
329
+ mp_raise_msg_varg (& mp_type_ValueError , MP_ERROR_TEXT ("Failed to bind timer to channel" ));
330
+ }
331
+
332
+ if (!set_freq (tval , & timers [new_timer ])) {
250
333
mp_raise_msg_varg (& mp_type_ValueError , MP_ERROR_TEXT ("bad frequency %d" ), tval );
251
334
}
252
335
return mp_const_none ;
@@ -261,14 +344,14 @@ STATIC mp_obj_t esp32_pwm_duty(size_t n_args, const mp_obj_t *args) {
261
344
if (n_args == 1 ) {
262
345
// get
263
346
duty = ledc_get_duty (PWMODE , self -> channel );
264
- duty <<= PWRES - timer_cfg .duty_resolution ;
347
+ duty <<= PWRES - timers [ self -> timer ] .duty_resolution ;
265
348
return MP_OBJ_NEW_SMALL_INT (duty );
266
349
}
267
350
268
351
// set
269
352
duty = mp_obj_get_int (args [1 ]);
270
353
duty &= ((1 << PWRES ) - 1 );
271
- duty >>= PWRES - timer_cfg .duty_resolution ;
354
+ duty >>= PWRES - timers [ self -> timer ] .duty_resolution ;
272
355
ledc_set_duty (PWMODE , self -> channel , duty );
273
356
ledc_update_duty (PWMODE , self -> channel );
274
357
0 commit comments