Normally, you'd use DigitalInOut
to turn an LED on and off in CircuitPython. However, as a simple introduction to PIO, it can also be used to turn an LED on or off.
Here's a CircuitPython program to do just that:
# SPDX-FileCopyrightText: 2021 Jeff Epler, written for Adafruit Industries # # SPDX-License-Identifier: MIT # # Adapted from the example https://github.com/raspberrypi/pico-examples/tree/master/pio/hello_pio import time import board import rp2pio import adafruit_pioasm hello = """ .program hello loop: pull out pins, 1 ; This program uses a 'jmp' at the end to follow the example. However, ; in a many cases (including this one!) there is no jmp needed at the end ; and the default "wrap" behavior will automatically return to the "pull" ; instruction at the beginning. jmp loop """ assembled = adafruit_pioasm.assemble(hello) sm = rp2pio.StateMachine( assembled, frequency=2000, first_out_pin=board.LED, ) print("real frequency", sm.frequency) while True: sm.write(bytes((1,))) time.sleep(0.5) sm.write(bytes((0,))) time.sleep(0.5)
Save the file below as code.py and transfer it to your CIRCUITPY drive. Your device should automatically restart and run the code. Shortly, a LED will blink on and off about once every second. If it doesn't, use Mu to connect to the Serial REPL of your device and you'll be able to see any errors that occurred.
Code Walkthrough
The full program is shown above, but let's look at the interesting bits a few lines at a time:
hello = """ .program hello loop: pull out pins, 1 ; This program uses a 'jmp' at the end to follow the example. However, ; in a many cases (including this one!) there is no jmp needed at the end ; and the default "wrap" behavior will automatically return to the "pull" ; instruction at the beginning. jmp loop """
PIO programs are included within your CircuitPython source as strings, and then converted into a program with the assemble
function.
sm = rp2pio.StateMachine( assembled, frequency=10000, first_out_pin=board.LED, )
The PIO peripheral contains several "state machines", which are the units that run PIO programs. The StateMachine
constructor takes the assembled program as well as some additional information:
-
frequency
says how quickly each pio instruction executes. If you have a task that you need to take "exactly X microseconds" or "execute at exactly Y kHz", this will allow you to determine the right frequency value. -
first_out_pin
names the first pin that will be updated by out instructions in the PIO program. This program only affects a single pin.
while True: sm.write(bytes((1,))) time.sleep(0.5) sm.write(bytes((0,))) time.sleep(0.5)
The forever-loop of our Python code alternates between sending the byte 1 and the byte 0 to the PIO state machine. Each time a byte is sent, the PIO program acts on it.
loop: pull out pins, 1 jmp loop
Every PIO instruction is documented in the RP2040 datasheet, so while this guide will give a high-level description of what is happening, it eliminates many details in order to keep the descriptions sort.
The first line, loop:
, is a label. This line, together with the last line jmp loop
create a forever-loop.
The second line contains the first instruction, pull
, which waits until a value is sent to the State Machine (A value is sent by the sm.write
function calls in our Python code). The value is stored in a location (register) called the OSR (Output Shift Register).
The next line contains another instruction, out pins, 1
. This is our first instruction with operands. The first operand, pins, says where the data is being transferred to. The second operand, 1, says how many bits are being transferred. The source of the data is the OSR, the same as the implicit destination of the pull
instruction.
The final line contains the last instruction, jmp loop
. A jmp
instruction makes the program continue at the named location instead of the next line.
The net effect of this program is to turn the related pin HIGH if the number sent is even and the pin LOW if the number sent is odd. And that's why the Python forever-loop makes the Pico's LED turn off and on about once per second.
Page last edited January 22, 2025
Text editor powered by tinymce.