labscript-suite / PrawnBlaster

Firmware for the Raspberry Pi Pico to turn it into a labscript-suite pseudoclock device
BSD 3-Clause "New" or "Revised" License
5 stars 5 forks source link

PrawnBlaster

The PrawnBlaster firmware turns the $5 Raspberry Pi Pico microcontroller board into a labscript suite pseudoclock device.

What is a pseudoclock device?

A pseudoclock is a device that can be programmed to output a variable frequency clock. The entire sequence of clock pulses is programmed into internal memory (over serial) and then executed on command (in order to achieve precise timing). In the case of the PrawnBlaster, you can program in a series of instructions containing the period of clock ticks and the number of times you would like that clock tick to repeat before moving to the next instruction.

Features/Specifications

Note 1: The half-period is the time a clock pulse stays high. All clock pulses produced by the PrawnBlaster have a 50-50 duty cycle.

Note 2: The internal clock can be configured to run at up to 133 MHz. We set it to a default of 100 MHz in order to produce nice round numbers. You can increase the clock frequency at runtime (via a serial command) which scales the timing specifications accordingly.

How to flash the firmware

Download the latest prawnblaster.uf2 file. On your Raspberry Pi Pico, hold down the "bootsel" button while plugging the Pico into USB port on a PC (that must already be turned on). The Pico should mount as a mass storage device (if it doesn't, try again or consult the Pico documentation). Drag and drop the .uf2 file into the mounted mass storage device. The mass storage device should unmount after the copy completes. Your Pico is now running the PrawnBlaster firmware!

PrawnBlaster pinout

Note: Don't forget to connect the ground of your signal cables to one of the ground pins of the Pico!

Communicating with the Pico

Communication is done over a USB serial connection. You should be able to use any terminal software of programming language to communicate. As an example, here is how you can launch a basic terminal with the Python PySerial package (assuming your Pico is on COM4):

python -m serial.tools.miniterm --eol=CRLF COM4 115200

Note the baudrate of 152000 and the requirement that commands be terminated with \r\n (CRLF). Communication during buffered execution is allowed (it is handled by a separate core and will not interfere with the DMA transfer of instruction data to the Pico's PIO cores).

Supported serial commands.

Note: the commands are only read if terminated with \r\n.

Reconfiguring the internal clock.

The clock frequency (and even source) can be reconfigured at runtime (it is initially set to 100 MHz on every boot). To do this, you send the command setclock <mode:int> <freq:int>, where the parameters are:

For example, to set the internal frequency to 125 MHz, you would send:

setclock 0 125000000

To set the internal frequency back to 100 MHz, you would send:

setclock 0 100000000

To use a 50 MHz external reference (on GPIO 20) you would send:

setclock 1 50000000

Note: When configured to use an external reference, the board will revert to the internal clock (at 100 MHz) if the external reference is interrupted.

External reference requirements

If configured to use an external source (clock mode 1 or 2, see above), the source must be a 0-3.3V CMOS signal at the frequency you wish to run at. This directly clocks the cores running the PrawnBlaster firmware, so minimum pulse lengths are directly related to the reference frequency. An external clock of 50MHz means a minimum half-period of 5/50MHz=100ns. An external clock of 100MHz means a minimum half-period of 5/100MHz=50ns.

Note: Officially, the documentation for the Pico says external clock sources can only be up to 50MHz. We have successfully tested up to 125MHz (see #6). We recommend you personally verify the output of the PrawnBlaster is as expected if running from an external reference above 50MHz.

Compiling the firmware

If you want to make changes to the firmware, or want to compile it yourself (because you don't trust binary blobs from the internet), we provide a docker configuration to help you do that.

  1. Install docker desktop and make sure it is running (if you are on Windows, you may have to mess around a bit to get virtualisation working at an operating system level)
  2. Clone this repository
  3. Open a terminal with the current working directory set to the repository root (the `docker-compose.yaml`` file should be there)
  4. Run docker compose build --pull to build the docker container
  5. Run docker compose up to build the PrawnBlaster firmware.

Step 4 will take a while as it has to build the docker container. If it is slow to download packages from the Ubuntu package repositories, consider providing an explicit apt mirror that is fast for you: docker compose build --pull --build-arg APT_MIRROR="http://azure.archive.ubuntu.com/ubuntu/".

If you want to change which version of the pico SDK it builds against, this is set in the build/docker/Dockerfile file. Just change the git tag of the pico SDK that gets cloned out by git, then rebuild the docker container (see step 4).

Note once the docker container is built, you can run step 5 as many times as you like. You do not need to rebuild the container, even if you make changes to the PrawnBlaster source code. You only need to rebuild the docker container if you modify the build/docker/Dockerfile file.

FAQ:

Why is it called a "PrawnBlaster"?

The PrawnBlaster is named after the Australian $5 note, which is colloquially known as a "Prawn". This follows the tradition started by the PineBlaster which was named after the Australian $50 note (colloquially known as the "Pineapple").

What are the trigger pulse requirements?

The initial start trigger (if using hwstart) and standard waits should only require a trigger pulse that is 4 clock cycles long (there is a 2 clock cycle buffer in the Pico GPIO design to reject spurious pulses).

Note that using indefinite waits requires that your trigger pulse is at least 12 clock cycles long and that it does not go high until 4 clock cycles after the previous instruction has completed. If this requirement is not met, you may find that your first wait (in the indefinite wait) reports a wait length and/or the second (indefinite) wait is not immediately processed until a subsequent trigger pulse. This is due to the architecture of how indefinite waits are defined (as two sequential waits).

What are the default pins?

While we have specified defaults for input/output pins (see serial commands above), there are circumstances where this will not happen. For example, the default input pin for pseudoclock 0 is GPIO 0. If this was explicitly assigned to pseudoclock 1 (as either an input or an output - e.g. setoutpin 1 0), then getinpin 0 will still report default until you attempt to use any of the I/O of the PrawnBlaster. At this point, defaults will be assigned to explicit pins. Pin 0 would usually be assigned as the trigger input pin for pseudoclock 0, but its already in use because it was explicitly set for pseudoclock 1 output. If a default pin is in use, we look for the lowest pin number that is not in use, and use that instead. After using PrawnBlaster I/O, a call to getinpin/getoutpin will report the actual pin in use and not default.

What this ultimately means is that if you use a mixture of explicit pin sets and leave the remaining on default, you may not actually get the defaults we list (depending on what pins you have reallocated). If you want to find out what pins, you should

  1. Set the number of pseudoclocks in use
  2. Set an explicit pins you care about with setinpin/setoutpin.
  3. Send go low 0 to force defaults to be assigned explicit pins (this is the simplest command that uses an output).
  4. Send getinpin 0, getoutpin 0, (etc. if using more than 1 pseudoclock) in order to determine which GPIO pins have actually been assigned to each pseudoclock.

Can I overclock the Pico board?

Yes, some people have reported being able to significantly overclock their Raspberry Pi Pico boards. While we do not recommend you do so (nor will we be liable for any damage to your Pico or attached devices should you overclock it), we have provided a version of the PrawnBlaster firmware with no upper limit to the clock frequency here. Use at your own risk! We provide no support for the overclockable firmware. If you need to tweak any other operating parameters of the Pico in order to achieve a stable overclock, you will need to manually modify the firmware source code and recompile it with those changes.

Are all input pins equal?

It seems the answer to that is no - some input pins seem to have a different delay in processing triggers than others. There are more details in #5, but this will not affect users of the labscript suite since all 4 pseudoclocks will be configured to trigger from the same input pin by the labscript suite device class.

If you are using the PrawnBlaster outside of the labscript suite, and want each pseudoclock to be triggered by a different GPIO pin, then you should be aware there seems to be a +/-10ns fluctuation in trigger response which may lead pseudoclocks to become out of sync with each other by 20ns per trigger.

Can I use other RP2040 boards?

Maybe - it depends what pins are available. In general it should work as long as it has 9 GPIO pins available for use (and not hardwired to a peripheral) and one of them is pin 20/22. Without pin 20 or 22, you can't externally reference the board. And with less GPIO pins you can't have 4 independent pseudoclocks each with an independent trigger. If you only need 1 trigger, you can get away with 1 pin for a trigger, 1 pin for each pseudoclock output you want (somewhere between 1 and 4) and 1 pin (either GPIO 20 or 22) for externally referencing if you need it. But unless you have a strong reason to get another RP2040 based board, we suggest sticking with the standard Pico (Which is usually the cheaper option anyway).