I’ve tagged release 0.6.0 of the rp2040_hal, pico_bsp, and pico_examples libraries for the Raspberry Pi Pico. Release notes are at the end of this page.

This is a relatively small release as I’ve found that these drivers are working well for my projects. If things keep going this way, I’ll be comfortable tagging a stable 1.0 release before the end of the year and promising no breaking changes without a major version bump.

Work needed

While we have simple drivers for most of the RP2040’s internal peripherals, there are a few tricky bits that still need work. I’d appreciate help with these.

Ravenscar Runtime

To take advantage of some of the more interesting features of Ada (tasking, protected types, etc) RP2040 support needs to be merged into bb-runtimes. On the rpi-pico-2021 branch I’ve rebased damaki’s branch on the community-2021 release of bb-runtimes. This branch cannot be merged upstream as it still uses a stage 2 boot (boot2) loader assembled from the upstream pico-sdk, which is licensed as BSD-3-Clause and copyright Raspberry Pi Foundation. AdaCore prefers that all contributions to bb-runtimes be licensed as GPL-3 and their copyright assigned to AdaCore. Therefore, we need to write new boot2 code that can be licensed as such.

I’ve made an attempt to reimplement the generic_03h version of boot2 in Ada, but this is broken. The ROM expects a .boot2 section at the beginning of flash to be padded to 256 bytes, with the last four bytes containing a CRC32. As far as I know, there’s no easy way to do the padding and checksum within the bb-runtimes build system. I’d be comfortable with having an out-of-band build process that generates a .S with the boot2 binary that can be committed to the bb-runtimes repository. In addition to the missing checksum, I believe my boot2 implementation does not save the link register and jump to the correct entry point after executing. I don’t know how to do that without adding inline assembly, which seems inelegant.

I’d appreciate help with getting the Ada boot2 implementation working so that the rpi-pico-2021 branch can be merged to bb-runtimes.


I’ve made some progress on a USB driver, but it’s far from complete and too disorganized to share right now. While it’s certainly possible to build a USB driver within the ZFP runtime restrictions, the implementation would be much easier and cleaner if tasking and storage pools were available. To that end, I’m prioritizing work on the Ravenscar runtime ahead of the USB stack. If anybody does want to work on USB, most of the device stack is already in usb_embedded, but that library requires hardware atomics that the Cortex-M0+ does not have. I have a branch with the atomics stuff removed that kinda works, but this feels like playing with fire.

Dual CPU

The bb-runtimes branch already has support for multiprocessing so I’m hesitant to duplicate that work in rp2040_hal. Even if I were to add SMP support to rp2040_hal, doing tasking without using Ada’s tasking features just seems wrong. Once again, this reinforces the importance of the Ravenscar work.

Integer divider

There’s a hardware integer divider in the SIO block that would significantly improve the performance of many programs. The assembly code used to hook this up to gcc’s EABI in pico-sdk is intimidating and more complicated than you’d expect.


I wrote a driver for it, but I’m not convinced that it works. Watchdogs are hard to test.

rp2040_hal 0.6.0 Release Notes

New features

Clocks can be disabled

To save power, peripheral clocks can be disabled with RP.Clock.Disable. Some peripherals may exhibit unexpected behavior if their clocks are disabled. Use at your own risk.

RTC can be paused

The RP.RTC.Pause and RP.RTC.Resume procedures stop and start the RTC. This is useful if you want the RTC to stop ticking while a user is setting the time. Preconditions requiring the clock to be running have been removed from the RTC procedures. RP.RTC.Initialize still needs to be called at least once, but can be skipped if RP.RTC.Running returns True, implying that the RTC is already Initialized.

Breaking changes

Delay_Microseconds no longer uses interrupts

RP.Timer.Delay_Microseconds now polls the timer registers in a busy loop, rather than setting up an alarm interrupt. This should make shorter (< 10 microsecond) delays more accurate as interrupt latency is no longer a factor. RP.Timer.Delay_Until can still be used to perform interrupt-based delays with microsecond precision.

Bugs fixed

16-bit RP.SPI.Transmit did not respect the Blocking configuration option

Issue #3

If Blocking was set in the SPI_Configuration and the 16-bit version of the Transmit procedure was used, Transmit would return before all data was clocked out. Thanks to @hgrodriguez for discovering this

RP.PWM did not check that Initialize was called first

If RP.PWM.Initialize was not called before configuring PWM slices, the configuration would succeed but would generate no output. An Initialized variable has been added to RP.PWM along with a precondition on all procedures that modify PWM slices to ensure that Initialized is True. If you forget to call RP.PWM.Initialize, your program will crash on the first run.

RP.ADC.Temperature could return incorrect data

If RP.ADC.Configure (Temperature_Sensor) was not called before RP.ADC.Temperature, incorrect temperature readings would be returned. RP.ADC.Temperature now ensures the temperature sensor is configured on every call, eliminating the need to call Configure for the temperature sensor.