@@ -249,34 +249,41 @@ extern void common_hal_pwmio_pwmout_set_duty_cycle(pwmio_pwmout_obj_t *self, uin
249249 // Track it here so that if frequency is changed we can use this value to recalculate the
250250 // proper duty cycle.
251251 // See https://github.com/adafruit/circuitpython/issues/2086 for more details
252-
253252 self -> duty_cycle = duty ;
253+
254254 const pin_timer_t * t = self -> timer ;
255255 if (t -> is_tc ) {
256256 uint16_t adjusted_duty = tc_periods [t -> index ] * duty / 0xffff ;
257- if (adjusted_duty == 0 && duty != 0 ) {
258- adjusted_duty = 1 ; // prevent rounding down to 0
259- }
260257 #ifdef SAMD21
261258 tc_insts [t -> index ]-> COUNT16 .CC [t -> wave_output ].reg = adjusted_duty ;
262259 #endif
263260 #ifdef SAM_D5X_E5X
264261 Tc * tc = tc_insts [t -> index ];
262+ while (tc -> COUNT16 .SYNCBUSY .bit .CC1 != 0 ) {
263+ }
265264 tc -> COUNT16 .CCBUF [1 ].reg = adjusted_duty ;
266265 #endif
267266 } else {
268267 uint32_t adjusted_duty = ((uint64_t )tcc_periods [t -> index ]) * duty / 0xffff ;
269- if (adjusted_duty == 0 && duty != 0 ) {
270- adjusted_duty = 1 ; // prevent rounding down to 0
271- }
272268 uint8_t channel = tcc_channel (t );
273269 Tcc * tcc = tcc_insts [t -> index ];
270+
271+ // Write into the CC buffer register, which will be transferred to the
272+ // CC register on an UPDATE (when period is finished).
273+ // Do clock domain syncing as necessary.
274+
275+ while (tcc -> SYNCBUSY .reg != 0 ) {
276+ }
277+
278+ // Lock out double-buffering while updating the CCB value.
279+ tcc -> CTRLBSET .bit .LUPD = 1 ;
274280 #ifdef SAMD21
275281 tcc -> CCB [channel ].reg = adjusted_duty ;
276282 #endif
277283 #ifdef SAM_D5X_E5X
278284 tcc -> CCBUF [channel ].reg = adjusted_duty ;
279285 #endif
286+ tcc -> CTRLBCLR .bit .LUPD = 1 ;
280287 }
281288}
282289
0 commit comments