A closer look at Raspberry Pi RP2040 Programmable IOs (PIO)

The popularity of Raspberry Pico board powered by RP2040 microcontroller has made every reader wanting to know more about the board and chip. So today we will be talking about RP2040’s Programmable IOs, a feature that makes it different from most other microcontroller boards.

The two PIO blocks or let’s call it the hardware interfaces in the RP2040 have four state machines each. These two PIO blocks can simultaneously execute programs to manipulate GPIOs and transfer raw data.  Now, what do these state machines do? Well, the PIO state machines execute the programs fetched from various sources. Sometimes the programs are taken from the PIO library (UART, SPI, or I2C) or user software.

RP2040 Programmable IOs State Machine

Why Programmable I/O?

All the boards usually come with hardware support for digital communications protocols such as I2C, SPI, and UART. However, if you plan to use more of these interfaces than what is available on the board, you can use the programmable IOs provided in RP2040 microcontroller.

Well, this has more capabilities than one can think of. Let’s say you want to output a DPI video or “communicate with a serial device found on AliExpress” is now possible with Programmable I/O.  As the name says, ‘Programmable’ IO makes it clear that it can be programmed directly to support several interfaces including SD card interface, VGA output, and higher speed data transfer. Hang on! We have the most exciting part of the article coming up – ‘How to program these programmable I/Os to make your job easy’.

How do I get started with the RP2040 PIO programming?

The Pico SDK (Software Development Kit) provides the headers, libraries and build system necessary to write programs for RP2040-based devices such as Raspberry Pi Pico in C, C++ or Arm assembly language

If you plan to use Python to code, you only require a suitable editor (let’s say Thonny) and MicroPython installed on the development board. But in the case of C/C++, you require CMake file that tells the Pico SDK how to turn the C file into a binary application for an RP2040-based microcontroller board, as explained in our recent MicroPython and C tutorial for Raspberry Pi Pico.

The PIO Assembler parses a PIO source file and outputs the assembled version ready for inclusion in an RP2040 application. This includes the C and C++ applications built against the Pico SDK, and Python programs running on the RP2040 MicroPython port.

To get started with programming the state machine for your PIO application, there are three components for C/C++ based program.

  • A PIO program
  • C-language based software to run the show
  • A CMake file describing how these two are combined into a program image to load onto an RP2040-based development board.

PIO Assembly Instructions

Now, when it comes to programming these IO interfaces, there are nine assembly instructions “JMP, WAIT, IN, OUT, PUSH, PULL, MOV, IRQ, and SET”. Although most people may be interested in programming the PIO interfaces with C/C++ or Python language, let us look into some of the assembly language instructions used for the IO interfaces.

  • JMP: This ‘jump’ instruction can be a conditional or a non-conditional statement. In this, it transfers the flow of execution by changing the instruction pointer register. In simple words, with ‘jmp’ statement the flow of execution goes to another part of the code.
  • WAIT: This instruction stalls the execution of the code. Each instruction takes one cycle unless it is stalled (using the WAIT instructions).
  • OUT: This instruction shifts data from the output shift register to other destinations, 1…32 bits at a time.
  • PULL: This instruction pops 32-bit words from TX FIFO into the output shift register.
  • IN: This instruction shift 1…32 bits at a time into the register.
  • PUSH: This instruction to write the ISR content to the RX FIFO.

RP2040 Programmable IOs Assembly Language

More information about the assembly language instructions is available in the RP2040 datasheet.

RP2040 PIO programming example in C/C++ and MicroPython

To make it easier, we will look into the program of hello_world that blinks the onboard LED using the Programmable IOs and TX FIFO’s 32-bit data (PULL instructions).

The program in C/C++ looks something like this:

The above C/C++ code blinks the LED with one complete cycle of  1 second. LED is programmed in such a way that it will be on for 500 ms followed by off for 500 ms. But, before state machines can run the program, we need to load the program into this instruction memory. “The function pio_add_program() finds free space for our program in a given PIO’s instruction memory, and loads it.” With this, we configure the state machine to output its data to the onboard LED.

The assembly code for .pio file shown below has all the C helper functions to set C/C++ code.

Apart from these, you also require CMake file that describes how .pio and .c files are built into a binary suitable for loading onto your Raspberry Pi Pico development board.

There’s no equivalent sample written with MicroPython, but we can see a simpler PIO MicroPython code used to blink the onboard LED:

There’s no separate .pio file in this case, and both MicroPython and assembly code are placed into the .py file.

Note that even though PIO can be programmed with MicroPython, the Python SDK documentation says it’s currently unstable/work-in-progress, so C/C++ is recommended.

There can be many modifications to the code by adding the color you want to display with the help of the hex format in RGB. However, there are many real-life examples like PWM, UART or even interfacing NeoPixels. For those interested, you can find many PIO programming examples in the GitHub repositories for C and MicroPython samples.


RP2040 Programmable IOs have the capability to simultaneously execute programs to support interfaces like VGA output and higher speed data transfer. You can check Chapter 3 in the SDK documentation for C/C++ and Python to find out more about RP2040 Programmable IOs.

Share this:

Support CNX Software! Donate via cryptocurrencies, become a Patron on Patreon, or purchase goods on Amazon or Aliexpress

ROCK 5 ITX RK3588 mini-ITX motherboard
Notify of
The comment form collects your name, email and content to allow us keep track of the comments placed on the website. Please read and accept our website Terms and Privacy Policy to post a comment.
David Willmore
David Willmore
3 years ago

*crickets chirp*

David Willmore
David Willmore
3 years ago

I see the fanboys from HaD made it over here. As usual, they had nothing useful to say.

Jon Morss
Jon Morss
3 years ago

Nice example(s).
For the C code, are you using the same cmake command as shown in the Pico Getting Started Guide?

Or are you doing the typical:

Just curious.


Jean-Luc Aufranc (CNXSoft)

I could just build the PIO samples as follows:

3 years ago

Terrible language and grammar.

3 years ago

Which part is terrible? I’m serious. It’s pretty much concise and clear.

David Willmore
David Willmore
3 years ago

Maybe they meant the programming language for the PIO module. Which, having programmed microcontrollers, DSPs, and VLIW units, looks horrible.

3 years ago

How would you improve it? I’m just trying to learn from others’ mistakes 🙂

James Mahoney
James Mahoney
1 year ago

I agree with Paulius on this one, it is ok to disagree or not like something but it would serve everyone to clearly state why and give an example of how you think it can be improved, everyone would benefit and learn!

Khadas VIM4 SBC