pio2o is a Python program that generates an Oberon module to get the binary code for PIO assembly programs.

There are two steps:

  1. run the PIO assembler pioasm to create the corresponding binaries;
  2. generate an Oberon module to read this binary code, to then load it into the PIO instruction registers.

The former restriction on one PIO program per module only has been lifted, and .wrap and .wrap_target are supported.


The PIO assembly code can either be

  • placed inside comments and two keywords directly in an Oberon module, or
  • read from a separate file.

Inside an Oberon module, from the example program:

    .program square_wave
      set pindirs 1
      set pins 1 [1]
      set pins 0
      jmp loop

    .program square_wave_asym
      set pindirs 1
      set pins 1 [1]
      set pins 0

Everything within the PIOBEGIN and PIOEND1 markers must comply with the PIO assembly language specifications, including comment styles (/* .. */, //, ;).

In a separate pure PIO assembly code .pio file, the PIOBEGIN and PIOEND markers are omitted, of course.

The PIO programs’ binary code and the .wrap and .wrap_target parameters are extracted from pioasm’s output by scanning the corresponding C header file. Since this a pretty simplistic algorithm as implemented,2 it’s best not to use PIOBEGIN and PIOEND elsewhere in the same module, including other comments, at least not at the beginning of a line.

Example Program

Please refer to example program PIOsquare.

Installation for Command Line Usage

This is how I install pio2o, which may not the “right” way to do it, but it works:

  • put pio2o.py into any directory, which must be on $PYTHONPATH, though;
  • one possibility is to leave the file in its directory in the repo structure, so you get and “install” any updates automatically. Just put the directory on $PYTHONPATH;
  • run the program with the -m option for Python (without the .py extension).

Hence, to generate the Oberon module for the example PIOsquare, I run in the Windows PowerShell, inside the example code directory (with pioasm installed as described below):

PS python -m pio2o PIOsquare.mod


PS python -m pio2o PIOsquare.pio

Which both generate PIOsquarePio.mod, that is, Pio gets added to the source module name. You can optionally specify a different output module name using -o module_name.


PS python -m pio2o -h


usage: pio2o [-h] [-v] [-o MODULE] ifn

Create an Oberon module for PIO assembly code. 'pioasm' is used to assemble
the PIO code, which then can be accessed from the Oberon module.

positional arguments:
  ifn            input file (.mod or .pio)

  -h, --help     show this help message and exit
  -v, --verbose  print feedback
  -o MODULE      output module name (Oberon)

PIO source code can be extracted from an Oberon module (.mod), or read from a
separate file (.pio). In the Oberon module, place the code inside a comment and
keywords PIOBEGIN and PIOEND.

Installation for Astrobe’s Tools Menu

Install as outlined above, then add this snippet – mutatis mutandis – to your Tools.ini file in the Astrobe configs folder:3

MenuItem=Create PIO Module
Parameters=-m pio2o %FileDir%\%FileName%

PIO Code Assembler pioasm

pio2o relies on the PIO assembler pioasm in the Raspberry Pi Pico C SDK. Just the binary! No need to touch the SDK otherwise. :)

There’s now a simple installer for Windows. Make sure the corresponding directory is in Window’s Path environment variable. The default installation puts piasm here:

C:\Program Files\Raspberry Pi\Pico SDK v1.5.1\pico-sdk-tools


  1. The formerly used PIO; and PIO. markers cause too much headaches when scanning the input file, considering that module PIO is most likely being used in the input module, with calls such as PIO.PutCode↩︎

  2. I have looked at full-blown C parsers, but decided this would be simply too heavy for the task at hand here, including the more involved installation. ↩︎

  3. In case you have installed pio2o in the Tools menu before, note the change of %FileDir%\%FileRoot%.mod to %FileDir%\%FileName%↩︎