Description
CircuitPython version
Adafruit CircuitPython 8.0.2 on 2023-02-14; Adafruit Feather M4 Express with samd51j19
Code/REPL
# SPDX-FileCopyrightText: 2018 Kattni Rembor for Adafruit Industries
#
# SPDX-License-Identifier: MIT
"""CircuitPython Essentials: PWM with Fixed Frequency example."""
import time
import board
import pwmio
# LED setup for most CircuitPython boards:
led = pwmio.PWMOut(board.LED, frequency=5000, duty_cycle=0)
while True:
t0 = time.monotonic()
for i in range(100):
# PWM LED up and down
if i < 50:
led.duty_cycle = int(i * 2 * 65535 / 100) # Up
else:
led.duty_cycle = 65535 - int((i - 50) * 2 * 65535 / 100) # Down
#time.sleep(0.01)
print(f"accumulated average duty_cycle set time: {time.monotonic() - t0:0.3f} sec")
Behavior
100 iterations with a PWM frequency of 5000 Hz:
accumulated duty_cycle set time: 0.020 sec
100 iterations with a PWM frequency of 50 Hz:
accumulated duty_cycle set time: 2.004 sec
Description
The delay is approximately equal to the period of the PWM frequency. The delay is noticeable at lower frequencies such as those used for servo and DC motor control.
Although not confirmed (somewhat beyond my skill set), it might be that the SAMD51 timer used for PWM is not being operated in its double-buffered CC (Compare Channel) register mode. Instead it may be waiting to load the CC register when the timer count is at its ZERO value rather than loading the CC buffer register and returning to the calling module. (reference: Microchip SAM D5x/E5x Family Data Sheet , DS60001507E, pp 1719-1721)
If possible, the desired operation would be to load the new PWM duty_cycle value and immediately return to the calling code, allowing the SAMD51's timer hardware to self-synchronize rather than cause a blocking delay condition.
Changing to a double-buffered approach may also benefit asyncio
-based code.