My development on the RP2350 has halted because I keep running into issues with the A2 revision errata and have been unable to get my hands on the newer A4 revision chips from a US distributor.
The remaining work on the 3.x branch at commit a87af34666f7189c7ed48736850fe4a21c64800a is daunting:
RP.GPIO
The implementations of Set/Clear/OE need to be rewritten to use the GPIOC coprocessor for single-cycle inlining where possible.
Unit test coverage is at 83%. The DORMANT_WAKE states are going to be tricky to test well.
All of the HAL.GPIO procedures need to be verified to have the same levels and equal or better timing compared to 2.x with an oscilloscope.
RP.Clock
Unit test coverage is at 72%. GPOUT and frequency counter failure are not tested.
Breaking up the Clock_Id type resulted in separate Enable_ADC and Enable_PERI procedures. While the common case is that you’ll enable these at startup and never touch them again, they should probably have corresponding Disable_ procedures. Maybe it should be type Gated_Clock_Id (ADC, PERI); with Enable and Disable procedures instead- this would mean one less backwards incompatible change from 2.x. I haven’t really decided how I want to approach this.
Both the RP2040 and RP2350 implementations need to be tested on hardware with GPOUT to verify PLL configuration is actually generating the correct frequencies.
RP.DMA
Coverage is at 72%, none of the IRQ procedures are tested. I want to reorganize the _IRQ functions into a RP.DMA.Interrupt child package, similar to RP.GPIO.Interrupt.
I’ve not done any functional testing beyond the unit tests on this module. There are significant changes to the DMA register layout on RP2350, so this should be tested carefully, especially the PIO2 and HSTX DMA_Request_Triggers that didn’t exist in RP2040.
RP.ADC
82% coverage is pretty good actually. On the higher pin count RP2350 packages the ADC is on pins 40 .. 47, not 26 .. 29. Someone will have to find or make a board with the larger package to test this properly, I believe the Pico 2 uses the lower pin count package.
RP.I2C and RP.I2C_Master
RP.I2C is deleted from the 3.x branch. I don’t want to maintain two separate I2C implementations going forward. This means 3.x has no I2C target/slave functionality right now. It would be nice to introduce a RP.I2C_Target package to fill that gap, though this is more of a wishlist feature than a requirement for a 3.x release.
After much consternation, RP.I2C_Master is in a good place and should function well on both boards… But I can’t test it on the RP2350 A2 revision I have because the I2C pins get latched up by errata E9 in the middle of the unit test. I can even replicate the hardware bug with my Softdev.I2C_Master bit banging implementation, independent of the Synopsys IP block. Without the A4 silicon, it’s impossible to guarantee correct I2C operation.
RP.Interpolator
I haven’t looked at the RP2350 version of it. At a glance, it’s the same, but the register layout and base addresses need to be verified correct. We’ve never had a unit test for this.
RP.PIO
I believe the only change on RP2350 is that there’s one more PIO block, but the registers and base addresses need to be checked against the datasheet. It might be nice to reorganize the IRQ procedures similar to RP.GPIO.Interrupt, but I’m not going to be too picky about this because PIO is already such a pain to work with.
All of the assembled PIO programs need to be re-tested and their example programs updated: Audio_I2S, Touch_Sense, WS2812
There is zero unit test coverage of PIO currently.
bunnie recently blogged about some of his gripes with PIO and I largely agree. Too much out-of-band configuration, nobody gets it right the first time and it’s difficult to debug without a simulator of some sort.
RP.PWM
Coverage at 84%, unit tests pass, but I haven’t done any verification that it does what it should on hardware. Need to hook up an oscilloscope, generate some waveforms, and test the counting/gating functionality between two pins.
RP.Reset
The list of resets has been updated for RP2350, no reason to doubt that it works as advertised, but coverage is at 33% because the tests never encounter RESET_DONE=False after asserting reset. It always happens within a cycle or two. Not a big issue, but I’d be interested in finding a way to test that branch, especially with a timeout.
RP.SPI
I’ve verified this one with real hardware driving a MAX7219 based LED matrix. The generated clock frequency was slightly lower than the Set_Speed call, I suspect an off-by-one in the clock divider calculation or frequency counter output.
Coverage is at 46%.
RP.Timer
Honestly not sure what to do with this. With the runtime supporting Ada.Real_Time, you don’t need RP.Timer for most applications. There’s a second AON timer on RP2350 that could be configured to run at a different frequency, but I’m not really sure why you’d want that. You can get the same functionality out of a PWM slice.
RP.UART
I’ve done no testing on RP2350. I assume it’s the same Synopsys IP block. I’d like to move away from the SVD definitions if possible, but hiding them from the spec is good enough. Coverage is 67%, mostly missing tests for odd error cases. Might need some external fault injection to trigger those.
RP.USB_Device
Haven’t looked at it, but I’ve still got unprocessed trauma from the last time I did. This thing scares me.
RP.Watchdog
Haven’t looked at it, but how complicated could a watchdog possibly be?
RP.Flash
Completely different on RP2350. I haven’t looked at it, but I suspect this will be annoying to test.
New stuff
HSTX, external PSRAM, SHA256, OTP, TRNG, security modes, low power modes, ROM functions, voltage regulators, RISC-V cores. There’s no support for any of this in rp2040_hal right now.
Documentation
Once all of the above is implemented and tested, pico_doc and pico_examples need to be updated with a complete changelog, 2.x to 3.x migration guide, and documentation of new behaviors. I consider this to be a requirement before merging the branch.
Contribution policy
I’m open to contributions that fill some of these gaps but I want to be clear that I will not accept any AI generated code in this repository. I want to keep the copyright status clean and traceable.
Most of these changes require probing real hardware with real electrons, which I’ve yet to see an LLM do. Personally, I’ve been writing drivers by hand, then feed it into Claude Code for review, not implementation. Whether this has saved me any meaningful amount of time or debugging is up for debate.