@@ -149,6 +149,21 @@ void pwmout_reset(void) {
149
149
150
150
#define PWM_SRC_CLK_FREQ CLOCK_GetFreq(kCLOCK_IpgClk)
151
151
152
+ static int calculate_pulse_count (uint32_t frequency , uint8_t * prescaler ) {
153
+ if (frequency > PWM_SRC_CLK_FREQ /2 ) {
154
+ return 0 ;
155
+ }
156
+ for (int shift = 0 ; shift < 8 ; shift ++ ) {
157
+ int pulse_count = PWM_SRC_CLK_FREQ /(1 <<shift )/frequency ;
158
+ if (pulse_count >= 65535 ) {
159
+ continue ;
160
+ }
161
+ * prescaler = shift ;
162
+ return pulse_count ;
163
+ }
164
+ return 0 ;
165
+ }
166
+
152
167
pwmout_result_t common_hal_pwmio_pwmout_construct (pwmio_pwmout_obj_t * self ,
153
168
const mcu_pin_obj_t * pin ,
154
169
uint16_t duty ,
@@ -196,16 +211,16 @@ pwmout_result_t common_hal_pwmio_pwmout_construct(pwmio_pwmout_obj_t *self,
196
211
// pwmConfig.reloadLogic = kPWM_ReloadPwmFullCycle;
197
212
pwmConfig .enableDebugMode = true;
198
213
199
- if (PWM_Init (self -> pwm -> pwm , self -> pwm -> submodule , & pwmConfig ) == kStatus_Fail ) {
200
- return PWMOUT_INVALID_PIN ;
201
- }
214
+ self -> pulse_count = calculate_pulse_count (frequency , & self -> prescaler );
202
215
203
- if (frequency == 0 || frequency > PWM_SRC_CLK_FREQ / 2 ) {
216
+ if (self -> pulse_count == 0 ) {
204
217
return PWMOUT_INVALID_FREQUENCY ;
205
218
}
206
219
207
- if (PWM_SRC_CLK_FREQ / frequency >= 65536 ) {
208
- return PWMOUT_INVALID_FREQUENCY ;
220
+ pwmConfig .prescale = self -> prescaler ;
221
+
222
+ if (PWM_Init (self -> pwm -> pwm , self -> pwm -> submodule , & pwmConfig ) == kStatus_Fail ) {
223
+ return PWMOUT_INVALID_PIN ;
209
224
}
210
225
211
226
pwm_signal_param_t pwmSignal = {
@@ -228,7 +243,6 @@ pwmout_result_t common_hal_pwmio_pwmout_construct(pwmio_pwmout_obj_t *self,
228
243
229
244
PWM_StartTimer (self -> pwm -> pwm , 1 << self -> pwm -> submodule );
230
245
231
- self -> pulse_count = PWM_SRC_CLK_FREQ /frequency ;
232
246
233
247
common_hal_pwmio_pwmout_set_duty_cycle (self , duty );
234
248
@@ -253,7 +267,11 @@ void common_hal_pwmio_pwmout_set_duty_cycle(pwmio_pwmout_obj_t *self, uint16_t d
253
267
// * it works in integer percents
254
268
// * it can't set the "X" duty cycle
255
269
self -> duty_cycle = duty ;
256
- self -> duty_scaled = ((uint32_t )duty * self -> pulse_count + self -> pulse_count /2 ) / 65535 ;
270
+ if (duty == 65535 ) {
271
+ self -> duty_scaled = self -> pulse_count + 1 ;
272
+ } else {
273
+ self -> duty_scaled = ((uint32_t )duty * self -> pulse_count + self -> pulse_count /2 ) / 65535 ;
274
+ }
257
275
switch (self -> pwm -> channel ) {
258
276
case kPWM_PwmX :
259
277
self -> pwm -> pwm -> SM [self -> pwm -> submodule ].VAL0 = 0 ;
@@ -271,27 +289,37 @@ void common_hal_pwmio_pwmout_set_duty_cycle(pwmio_pwmout_obj_t *self, uint16_t d
271
289
}
272
290
273
291
uint16_t common_hal_pwmio_pwmout_get_duty_cycle (pwmio_pwmout_obj_t * self ) {
292
+ if (self -> duty_cycle == 65535 ) {
293
+ return 65535 ;
294
+ }
274
295
return ((uint32_t )self -> duty_scaled * 65535 + 65535 /2 ) / self -> pulse_count ;
275
296
}
276
297
277
298
void common_hal_pwmio_pwmout_set_frequency (pwmio_pwmout_obj_t * self ,
278
299
uint32_t frequency ) {
279
300
280
- if (frequency > PWM_SRC_CLK_FREQ /2 ) {
301
+ int pulse_count = calculate_pulse_count (frequency , & self -> prescaler );
302
+ if (pulse_count == 0 ) {
281
303
mp_raise_ValueError (translate ("Invalid PWM frequency" ));
282
304
}
283
305
284
- if (PWM_SRC_CLK_FREQ / frequency >= 65536 ) {
285
- mp_raise_ValueError (translate ("Invalid PWM frequency" ));
286
- }
306
+ self -> pulse_count = pulse_count ;
287
307
288
- self -> pulse_count = PWM_SRC_CLK_FREQ /frequency ;
308
+ // a small glitch can occur when adjusting the prescaler, from the setting
309
+ // of CTRL just below to the setting of the Ldok register in
310
+ // set_duty_cycle.
311
+ uint32_t reg = self -> pwm -> pwm -> SM [self -> pwm -> submodule ].CTRL ;
312
+ reg &= ~(PWM_CTRL_PRSC_MASK );
313
+ reg |= PWM_CTRL_PRSC (self -> prescaler );
314
+ self -> pwm -> pwm -> SM [self -> pwm -> submodule ].CTRL = reg ;
289
315
self -> pwm -> pwm -> SM [self -> pwm -> submodule ].VAL1 = self -> pulse_count ;
316
+
317
+ // we need to recalculate the duty cycle. As a side effect of this
290
318
common_hal_pwmio_pwmout_set_duty_cycle (self , self -> duty_cycle );
291
319
}
292
320
293
321
uint32_t common_hal_pwmio_pwmout_get_frequency (pwmio_pwmout_obj_t * self ) {
294
- return PWM_SRC_CLK_FREQ /self -> pulse_count ;
322
+ return PWM_SRC_CLK_FREQ /self -> pulse_count /( 1 << self -> prescaler ) ;
295
323
}
296
324
297
325
bool common_hal_pwmio_pwmout_get_variable_frequency (pwmio_pwmout_obj_t * self ) {
0 commit comments