CircuitPython PWM

As of CircuitPython 2.1 we have pulseio support for Trinket, so you can PWM LEDs, control servos, beep piezos, and manage 'pulse train' type devices like DHT22 and Infrared.

On Trinket, you get four PWMs, D0, D2, D3 and D4. Actually, you get a fifth, but that's on the D13 LED). D1/A0 has true analog out but does not have PWM!

Timer mapping

There's a limited number of timers available. But timers have many outputs. You have have two PWM outputs that share a timer but they must have the same frequency (they can vary the duty cycle just not frequency)

When you create an pulseio object, the lowest # Timer that is not already being used, will be used. For example, D13 can use timer 0 or timer 1, but will default to the lowest timer.

Also, you can only have two PWM outputs on timer 1. So if you want all the PWMs, you can put D0, D2 and D13 on timer 0 and D3 and D4 on timer 1.

Pin name

Timers available


Timer #0.0 and Timer #1.2


Timer #0.1 and Timer #1.3


Timer #1.1


Timer #1.0


Timer #0.2 and Timer #1.0

Both D3 and D4 are on the same timer so if you want to use both at the same time, they MUST be the same frequency! You can have D0 or D2 on Timer #0 so they can be a different frequency form each other but only if D3/D4 aren't being used.

Basically just keep track of which timers you are using if you want to have unique frequencies. If unique freqs are not important to you, then this doesn't matter. CircuitPython will give you an error "All timers in use" if you are trying to arrange the pins in a way that doesn't work

PWM Output with Fixed Frequency

This sketch demonstrates how to create four PWM outputs, one on each pin.

The frequency for D3 and D4 must be the same (1000 hz) but you can vary the duty cycle between the two! You can use D13, D2 and D0 on timer #0.

Timer #0 and Timer #1 can have unique frequencies, in this case we have 5 KHz for one and 1 KHz for the other.

import pulseio
import time
import board

pwm3 = pulseio.PWMOut(board.D3, frequency=1000, duty_cycle=0) # timer 1
pwm4 = pulseio.PWMOut(board.D4, frequency=1000, duty_cycle=0) # timer 1

pwm2 = pulseio.PWMOut(board.D2, frequency=5000, duty_cycle=0) # timer 0
pwm0 = pulseio.PWMOut(board.D0, frequency=5000, duty_cycle=0) # timer 0
led = pulseio.PWMOut(board.D13, frequency=5000, duty_cycle=0) # timer 0

while True:
    for i in range(100):
        # PWM D0 and D3 from low to high duty cycle
        pwm3.duty_cycle = pwm0.duty_cycle = int(i * 65535 / 100)
        # PWM D2 and D4 from high to low
        pwm4.duty_cycle = pwm2.duty_cycle = 65535 - pwm0.duty_cycle
	# PWM LED up and down
	if i < 50:
	    led.duty_cycle = int(i * 2 * 65535 / 100) # up
	    led.duty_cycle = 65535 - int((i-50) * 2 * 65535 / 100) # down

Create a PWM output with pulseio.PWMOut and pass in the pin to use, then you can set the initial frequency and also initial duty_cycle!

PWM Output with Variable Frequency

Fixed frequency outputs are great for pulsing LEDs or controlling servos. But if you want to make some beeps with a piezo, you'll need to vary the frequency.

Remember that on the Trinket, some pins share a single timer, so if you want two piezos, for example, make sure they are on two different timers

import pulseio
import time
import board

piezo = pulseio.PWMOut(board.D2, duty_cycle=0, frequency=440, variable_frequency=True)

while True:
    for f in (262, 294, 330, 349, 392, 440, 494, 523):
	piezo.frequency = f
	piezo.duty_cycle =65536//2    # on 50%
	time.sleep(0.25)              # on for 1/4 second
	piezo.duty_cycle = 0          # off
	time.sleep(0.05)              # pause between notes

If you have simpleio library installed we have a nice little helper that makes a tone for you on a piezo with a single command:

import pulseio
import time
import board
import simpleio

while True:
    for f in (262, 294, 330, 349, 392, 440, 494, 523):
	simpleio.tone(board.D2, f, 0.25)  # on for 1/4 second
	time.sleep(0.05)                  # pause between notes

As you can tell, its a lot prettier!

Last updated on 2017-12-01 at 04.45.54 PM Published on 2017-08-23 at 05.57.02 PM