Programmable I/O (PIO) is the feature that sets RP-series chips apart. Each PIO block contains state machines that run small programs with precise timing, independently of the CPU cores.
| Chip | PIO blocks | State machines |
|---|---|---|
| RP2040 | 2 | 8 |
| RP2350 | 3 | 12 |
When to reach for PIO
- A protocol with tight timing the chip has no hardware block for: WS2812/NeoPixel LEDs, 1-Wire, Manchester encoding, IR remote codes, HUB75 LED matrices.
- More of a standard interface than the hardware has: extra UARTs or SPI/I2C buses.
- Counting fast signals without CPU load: quadrature encoders.
Bit-banging these in C or MicroPython is fragile once interrupts, Wi-Fi or other work competes for the CPU. A PIO program keeps the timing no matter what the cores do.
Don't write it from scratch
The official pico-examples repository (PIO section) has working programs for:
pio_ws2812andpio_ws2812_parallel: WS2812 LED stripspio_onewire: 1-Wire library with a DS18B20 temperature sensor examplepio_uart_rx,pio_uart_tx,pio_uart_dma: extra UARTspio_spi_*,pio_i2c_bus_scan: SPI and I2Cpio_quadrature_encoder: encoder countingpio_hub75,pio_st7789_lcd: displayshello_pio,pio_blink: the minimal starting points
MicroPython also exposes PIO (the Raspberry Pi pico-micropython-examples repository has a PIO section, e.g. a NeoPixel ring).
Tips
- State machines are a limited resource; count them when you combine several PIO-based drivers or libraries.
- Pair PIO with DMA for high data rates (see
pio_uart_dma,pio_logic_analyser).