PIOLib: A userspace library for PIO control
Dip your toes into the world of PIO on Raspberry Pi 5 using PIOLib
The launch of Raspberry Pi 5 represented a significant change from previous models. Building chips that run faster and use less power, while continuing to support 3.3V I/O, presents real, exciting challenges. Our solution was to split the main SoC (System on Chip) in two — the compute half, and the I/O half — and put a fast interconnect (4-lane PCIe Gen 3) between them. The SoC on Raspberry Pi 5 is the Broadcom BCM2712, and the I/O processor (which used to be known in the PC world as the ‘southbridge’) is Raspberry Pi RP1.
Along with all the usual peripherals — USB, I2C, SPI, DMA, and UARTs — RP1 included something a bit more interesting. One of RP2040’s distinguishing features was a pair of PIO blocks, deceptively simple bits of Programmable I/O capable of generating and receiving patterns on a number of GPIOs. With sufficient cunning, users have been able to drive NeoPixel LEDs and HDMI displays, read from OneWire devices, and even connect to an Ethernet network.
RP1 is blessed with a single PIO block — almost identical to the two that RP2040 has — as well as four state machines and a 32-entry instruction memory. However, apart from a few hackers out there, it has so far lain dormant; it would be great to make this resource available to users for their own projects, but there’s a catch.
Need for speed
The connection between RP1’s on-board ARM M3 microcontrollers and the PIO hardware was made as fast as possible, but at the cost of making the PIO registers inaccessible over PCIe; the only exceptions are the state machine FIFOs — the input and output data pipes — that can be reached by DMA (direct memory access). This makes it impossible to control PIO directly from the host processors, so an alternative is required. One option would be to allow the uploading of code to run on the M3 cores, but there are a number of technical problems with that approach:
1. We need to “link” the uploaded code with what is already present in the firmware — think of it as knitting together squares to make a quilt (or a cardigan for Harry Styles). For that to work, the firmware needs a list of the names and addresses of everything the uploaded code might want to access, something that the current firmware doesn’t have.
2. Third-party code running on M3 cores presents a security risk — not in the sense that it might steal your data (although that might be possible…), but that by accident or design it could disrupt the operation of your Raspberry Pi 5.
3. Once the M3s have been opened up in that way, we can’t take it away, and that’s not a step we’re prepared to take.
Not like that, like this
For these reasons, we took a different path.
The latest RP1 firmware implements a mailbox interface: a simple mechanism for sending messages between two parties. The kernel has corresponding mailbox and firmware drivers, and an rp1-pio
driver that presents an ioctl()
interface to user space. The end result of adding all this software is the ability to write programs using the PIO SDK that can run in user space or in kernel drivers.
Latency trade-off
Most of the PIOLib functions cause a message to be sent to the RP1 firmware, which performs the operation — possibly just a single I/O access — and replies. Although this makes it simple to run PIO programs on Raspberry Pi 5 (and the rest of the Raspberry Pi family), it does come at a cost. All that extra software adds latency; most PIOLib operations take at least 10 microseconds. For PIO software that just creates a state machine and then reads or writes data, this is no problem — the WS2812 LED and PWM code are good examples of this. But anything that requires close coupling between the state machine and driver software is likely to have difficulties.
The first official use of PIOLib is the new pwm-pio
kernel driver. It presents a standard Linux PWM interface via sysfs, and creates a very stable PWM signal on any GPIO on the 40-pin header (GPIOs 0 to 27). You can configure up to four of these PWM interfaces on Raspberry Pi 5; you are limited by the number of state machines. Like many peripherals, you create one with a Device Tree overlay:
dtoverlay=pwm-pio,gpio=7
One feature absent from this first release is interrupt support. RP1 provides two PIO interrupts, which can be triggered by the PIO instruction IRQ (interrupt request), and these could be used to trigger actions on the SoC.
Over time, we may discover that there are some common usage patterns — groups of the existing PIOLib functions that often appear together. Adding those groups to the firmware as single, higher-level operations may allow more complex PIO programs to run. These and other extensions are being considered.
Let me play!
If you’d like to try PIOLib, you will need:
- The library (and examples)
- The latest kernel (
sudo apt update
;sudo apt upgrade
) - The latest EEPROM (see the ‘Advanced Options’ section of
raspi-config
)
I’ll leave you with a video of some flashing lights — two strings of WS2812 LEDs being driven from a Raspberry Pi 5. It’s beginning to look a bit festive!
The post PIOLib: A userspace library for PIO control appeared first on Raspberry Pi.