Skip to content

Commit f1988b3

Browse files
committed
mimxrt1011: pwmout: Add prescaler, fix duty_cycle=65535
1 parent 90103e8 commit f1988b3

File tree

2 files changed

+43
-14
lines changed

2 files changed

+43
-14
lines changed

ports/mimxrt10xx/common-hal/pwmio/PWMOut.c

Lines changed: 42 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,21 @@ void pwmout_reset(void) {
149149

150150
#define PWM_SRC_CLK_FREQ CLOCK_GetFreq(kCLOCK_IpgClk)
151151

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+
152167
pwmout_result_t common_hal_pwmio_pwmout_construct(pwmio_pwmout_obj_t *self,
153168
const mcu_pin_obj_t *pin,
154169
uint16_t duty,
@@ -196,16 +211,16 @@ pwmout_result_t common_hal_pwmio_pwmout_construct(pwmio_pwmout_obj_t *self,
196211
// pwmConfig.reloadLogic = kPWM_ReloadPwmFullCycle;
197212
pwmConfig.enableDebugMode = true;
198213

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);
202215

203-
if (frequency == 0 || frequency > PWM_SRC_CLK_FREQ/2) {
216+
if (self->pulse_count == 0) {
204217
return PWMOUT_INVALID_FREQUENCY;
205218
}
206219

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;
209224
}
210225

211226
pwm_signal_param_t pwmSignal = {
@@ -228,7 +243,6 @@ pwmout_result_t common_hal_pwmio_pwmout_construct(pwmio_pwmout_obj_t *self,
228243

229244
PWM_StartTimer(self->pwm->pwm, 1 << self->pwm->submodule);
230245

231-
self->pulse_count = PWM_SRC_CLK_FREQ/frequency;
232246

233247
common_hal_pwmio_pwmout_set_duty_cycle(self, duty);
234248

@@ -253,7 +267,11 @@ void common_hal_pwmio_pwmout_set_duty_cycle(pwmio_pwmout_obj_t *self, uint16_t d
253267
// * it works in integer percents
254268
// * it can't set the "X" duty cycle
255269
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+
}
257275
switch (self->pwm->channel) {
258276
case kPWM_PwmX:
259277
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
271289
}
272290

273291
uint16_t common_hal_pwmio_pwmout_get_duty_cycle(pwmio_pwmout_obj_t *self) {
292+
if (self->duty_cycle == 65535) {
293+
return 65535;
294+
}
274295
return ((uint32_t)self->duty_scaled * 65535 + 65535/2) / self->pulse_count;
275296
}
276297

277298
void common_hal_pwmio_pwmout_set_frequency(pwmio_pwmout_obj_t *self,
278299
uint32_t frequency) {
279300

280-
if (frequency > PWM_SRC_CLK_FREQ/2) {
301+
int pulse_count = calculate_pulse_count(frequency, &self->prescaler);
302+
if (pulse_count == 0) {
281303
mp_raise_ValueError(translate("Invalid PWM frequency"));
282304
}
283305

284-
if (PWM_SRC_CLK_FREQ / frequency >= 65536) {
285-
mp_raise_ValueError(translate("Invalid PWM frequency"));
286-
}
306+
self->pulse_count = pulse_count;
287307

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;
289315
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
290318
common_hal_pwmio_pwmout_set_duty_cycle(self, self->duty_cycle);
291319
}
292320

293321
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);
295323
}
296324

297325
bool common_hal_pwmio_pwmout_get_variable_frequency(pwmio_pwmout_obj_t *self) {

ports/mimxrt10xx/common-hal/pwmio/PWMOut.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ typedef struct {
3737
const mcu_pin_obj_t *pin;
3838
const mcu_pwm_obj_t *pwm;
3939
bool variable_frequency;
40+
uint8_t prescaler;
4041
uint16_t duty_cycle, duty_scaled, pulse_count;
4142
} pwmio_pwmout_obj_t;
4243

0 commit comments

Comments
 (0)