diff --git a/ports/atmel-samd/common-hal/pwmio/PWMOut.c b/ports/atmel-samd/common-hal/pwmio/PWMOut.c index fd03cab5457c..71d6f38d502a 100644 --- a/ports/atmel-samd/common-hal/pwmio/PWMOut.c +++ b/ports/atmel-samd/common-hal/pwmio/PWMOut.c @@ -249,34 +249,41 @@ extern void common_hal_pwmio_pwmout_set_duty_cycle(pwmio_pwmout_obj_t *self, uin // Track it here so that if frequency is changed we can use this value to recalculate the // proper duty cycle. // See https://github.com/adafruit/circuitpython/issues/2086 for more details - self->duty_cycle = duty; + const pin_timer_t *t = self->timer; if (t->is_tc) { uint16_t adjusted_duty = tc_periods[t->index] * duty / 0xffff; - if (adjusted_duty == 0 && duty != 0) { - adjusted_duty = 1; // prevent rounding down to 0 - } #ifdef SAMD21 tc_insts[t->index]->COUNT16.CC[t->wave_output].reg = adjusted_duty; #endif #ifdef SAM_D5X_E5X Tc *tc = tc_insts[t->index]; + while (tc->COUNT16.SYNCBUSY.bit.CC1 != 0) { + } tc->COUNT16.CCBUF[1].reg = adjusted_duty; #endif } else { uint32_t adjusted_duty = ((uint64_t)tcc_periods[t->index]) * duty / 0xffff; - if (adjusted_duty == 0 && duty != 0) { - adjusted_duty = 1; // prevent rounding down to 0 - } uint8_t channel = tcc_channel(t); Tcc *tcc = tcc_insts[t->index]; + + // Write into the CC buffer register, which will be transferred to the + // CC register on an UPDATE (when period is finished). + // Do clock domain syncing as necessary. + + while (tcc->SYNCBUSY.reg != 0) { + } + + // Lock out double-buffering while updating the CCB value. + tcc->CTRLBSET.bit.LUPD = 1; #ifdef SAMD21 tcc->CCB[channel].reg = adjusted_duty; #endif #ifdef SAM_D5X_E5X tcc->CCBUF[channel].reg = adjusted_duty; #endif + tcc->CTRLBCLR.bit.LUPD = 1; } }