Raspberry Pi 5 IoT In C - Starting PIO
Written by Harry Fairhead   
Monday, 08 September 2025
Article Index
Raspberry Pi 5 IoT In C - Starting PIO
PIO Basic Concepts
The PIO Assembler
Configure the state machine

With the state machine that we are going to use settled, we can now configure it. You could do this directly, but the simplest and best way to do the job is to use the SDK. This allows you to set up a struct with all of the configuration values set and then initialize the state machine in one go. First we need a default configuration and this is another utility function provided by the header file that the assembler creates:

pio_sm_config c = squarewave_program_get_default_config(offset);

Now we have to set the configuration as promised. We need to specify which pins are going to be in the SET group:

sm_config_set_set_pins(&c, 2, 1);

and in this case we have selected just one pin, GPIO 2, as the group starts at GPIO 2 and has just one pin. This means that our set instruction in the PIO program will toggle just pin GPIO 2. We also have to set the GPIO function to GPIO_FUNC_PIO0 to let the processor know that the pin is being controlled by the PIO.

Instead of using the function from Gpio5:

gpio_set_function(2, GPIO_FUNC_PIO0);  

you can use the specific PIO function to do the same job:

pio_gpio_init(pio0, 2);

Finally we can load the configuration into the state machine and start it running:

pio_sm_init(pio0, sm, offset, &c);
pio_sm_set_enabled(pio0, sm, true);

If you now look at the output of GPIO 2 you will see a square wave.

The complete program is listed below, but remember that it needs the PIO header that the assembler creates:

#include "pico/stdlib.h"
#include "hardware/pio.h"
#include "sqwave.pio.h"
int main()
{
uint offset = pio_add_program(pio0,
&squarewave_program);
uint sm = pio_claim_unused_sm(pio0, true);
pio_sm_config c =
squarewave_program_get_default_config(offset);
sm_config_set_set_pins(&c, 2, 1);
pio_gpio_init(pio0, 2);
pio_sm_init(pio0, sm, offset, &c);
pio_sm_set_enabled(pio0, sm, true);
while(true){};
return 0;
}

 

The pico/stdlib.h and hardware/pio.h headers are supplied by the library. stdlib.h simply includes:

#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include "piolib.h"

pio.h header doesn’t do anything and is only included for compatibility with Pico programs so it can be deleted.

To make this work you also need to let VS Code know where the PIO include files are. Add:

            "args": [
                "-fdiagnostics-color=always",
                "-I../piolib/include",
                "-g",
                "${file}",
                "../piolib/piolib.c",
                "../piolib/pio_rp1.c",
                "-o",
           "${fileDirname}/${fileBasenameNoExtension}"
            ],

to the args section of the C/C++: gcc build active file task in tasks.json . This assumes that the header files and PIO C files are in a folder called piolib in the same folder as the project folder.

Note: At the time of writing you cannot use piolib at the same time as Gpio5 as some of the functions they define are in common and hence clash. The simplest solution is to add Gpio5_ to the start of each gpio function in the Gpio5 library – this works but it means you cannot run a Pico program without modification.

If you try this out you will find that the program does produce a square wave, but it isn’t suitable as a Blinky example. At the moment the clock rate is set to produce a square wave at around 66 MHz and we need to bring down the frequency to something more reasonable so that we can see an LED blink on and off. Notice that the Pi 5’s PIO runs at 200MHz and this is faster than the standard Pico PIO, which means that timings will change when you port a program from the Pico to the Pi 5.

Notice that the PIO program runs as fast as the PIO clock allows it to run, but the C program runs slower than in the case of the Pico due to the fact that the PIO isn’t directly connected to the CPU running the C program. For programs that simply load the PIO with a program and some data this makes no difference, but for programs that interact with the running PIO program it can introduce timing problems.

In chapter but not in this extract

  • Clock Division and Timing
  • Writing Loops
  • Data to the PIO
  • Sharing GPIO lines
  • Out to the GPIO
  • Side Effects
  • Input
  • Edges
  • Advanced PIO
  • DHT22 Using the PIO – Counting
  • DHT22 Using the PIO – Sampling.
  • Complete Listing
  • A PIO DS18B20 Program
  • Complete Listing

Summary

  • The PIO and the state machine are special processors designed to interact with the outside world.

  • You can use a PIO attempt to implement any otherwise unsupported protocol.

  • The Pi 5 has one PIO with four state machines.

  • The GPIO lines associated with the PIO are determined by a set of groups – OUT, SET, IN and SETSIDE. GPIO lines also have to be set to PIO mode before they will work in any of the groups.

  • You can set the clock frequency that the PIO uses to execute instructions one per clock cycle.

  • The clock should be set to a frequency that is suitable for the sort of pulses the PIO is working with.

  • It is easy to toggle a GPIO line, but slightly harder to make it slow enough to flash an LED. To do this you need to implement a busy wait loop.

  • The OSR and ISR are used to send data to and receive data from the GPIO lines.

  • There are two FIFO stacks which can be used to send data to the OSR and ISR from the processor.

  • Every instruction can change the state of GPIO lines in the SETSIDE group as a side effect of its execution.

  • Working with edges isn’t natural for the state machine, but it can be achieved using wait instructions.

  • It is possible to implement the DHT22 protocol as defined in the data sheet using a PIO by using counting loops to time each pulse.

  • A better use of the PIO is to notice that the protocol can be decoded by testing the state of the line a fixed time after the rising edge.

  • With a shift in viewpoint, it is just possible to squeeze a 1-Wire bus protocol into a 32-instruction PIO program.

You can find the complete Gpio5 at its Github repo:

 https://github.com/IOPress/Gpio5,

at the book’s web page:

https://iopress.info/index.php/books/raspberry-pi-5-iot-in-c

Raspberry Pi 5 IoT In C
Drivers and Gpio5

By Harry Fairhead

CIoTPi5360
Buy from Amazon.

Contents

  1. The Pi 5 For The IoT
  2. C and Visual Studio Code
  3. Drivers: A First Program
  4. The GPIO Character Drive
  5. GPIO Using I/O Control
  6. GPIO Events
  7. GPIO Hardware With Gpio5
         Extract: GPIO Registers
         Extract: GPIO5
  8. Some Electronics
  9. The Device Tree
  10. Pulse Width Modulation
         Extract: PWM Using GPIO5
  11. SPI Devices
  12. I2C Driver and Gpio5
        
    Extract: I2C with Gpio5
  13. Sensor Drivers – Linux IIO & hwmon
  14. 1-Wire Bus
  15. The PIO
         
    Extract: Starting PIO  ***NEW!
  16. Going Further With Drivers
  17. Appendix I Gpio5

 <ASIN:1871962943>

To be informed about new articles on I Programmer, sign up for our weekly newsletter, subscribe to the RSS feed and follow us on Twitter, Facebook or Linkedin.

Banner


Python Still Growing - 2024 Developer Survey Results
20/08/2025

The results of the 2024 Python Developers Survey, conducted as a collaborative effort between the Python Software Foundation and JetBrains have been published. This was the eighth editi [ ... ]



Oracle Database Adds MCP Tooling Support
02/09/2025

Oracle adds MCP support to two of its flagship tools, SQLcl and
SQL Developer for VS Code, in an attempt to simplify user interaction with the database.


More News

pico book

 

Comments




or email your comment to: comments@i-programmer.info

 



Last Updated ( Monday, 08 September 2025 )