CircuitPython PWM

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

On Gemma, you get two PWMs, D0 and D2. Actually, you get a third, but that's on the L LED). D1/A0 has true analog out but does not have PWM!

Don't forget you have to update your CircuitPython firmware to 2.1 to get this support!

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.

So, LED can use timer 0 or timer 4, but will default to the lowest timer. If you want to use all three, define D0's and D2's PWM objects first! Then you can change the LED pin's frequency

Pin name

Timers Available


Timer #0


Timer #0


Timer #0 and Timer #4

Both D0 and D2 are on the same timer so if you want to use both at the same time, they MUST be the same frequency!

PWM Output with Fixed Frequency

This sketch demonstrates how to create two PWM outputs on each pin.

The frequency for D2 and D0 must be the same (1000 hz) but you can vary the duty cycle between the two!

import pulseio
import time
import board

pwm0 = pulseio.PWMOut(board.D0, frequency=1000, duty_cycle=0)
pwm2 = pulseio.PWMOut(board.D2, frequency=1000, duty_cycle=0)

led = pulseio.PWMOut(board.L, frequency=5000, duty_cycle=0)

while True:
    for i in range(100):
        # PWM D0 from low to high duty cycle
        pwm0.duty_cycle = int(i * 65535 / 100)
        # PWM D2 from high to low
        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 Gemma, both PWM outputs are on a single timer, so you can only have one variable frequency output - but it can be on either pin

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.59.09 PM Published on 2017-07-26 at 06.08.30 PM