Rust with the Raspberry Pi Pico 2 & RP2350
After writing seven blog articles about getting embedded rust working on the Raspberry Pi Pico W, it seems like a good time to write something about the exciting new Raspberry Pi Pico 2 that was just announced less than 2 weeks ago.
Before I go any further, if you’re interested in reading any other the other articles in the series, you can follow the link below.
Also, a note about this particular Medium article: I intend to revise it on a regular basis, so if you want to get a snapshot of the state of Rust on Pico 2 is developing, you can bookmark this page.
The New Raspberry Pi Launch
Since the beginning of this year when I started getting interested in the RP2040 microcontroller and the Pico & Pico W boards, I had read that Raspberry Pi Ltd was working on the RP2040’s successor. There weren’t any details of what new goodies would be found in the chip, but I was intrigued to think of what they would dream up almost four years after the release of the original chip.
On August 8, the new product was announced, and a number of news outlets like the Register released some stories about the new product. I’m not going to bother with the laundry list of improvements—that wouldn’t make this blog article that novel—so you can follow that Register link for those details. Yes, it’s faster. Yes, there’s some more memory. Yea! There are now standard floating point operations supported so you don’t need to depend on glacial software emulation. (Maybe I’m the only one who cares about that.) If you really want to dig into the details, the best thing to do is read through the new 1346 page datasheet. Honestly, if you’re interested and have an hour or two, it’ll give you a great idea of what’s under the hood.
The more eyebrow raising aspect is that you can run either as a standard ARM core (the ARM Cortex M0+ upgraded to the M33) or you can switch to a RISC-V architecture instead. In reality, that means there are four cores on the chip, but two will always be dormant depending on your configuration.
There’s a decent amount of excitement out there about RISC-V because the architecture is an Open Source initiative that is meant to enable companies to develop products without the licensing encumbrance that comes with something like ARM. It’s cool that Raspberry Pi has brought RISC-V to developers to make it available for experimentation. This is cool if you’re interested in RISC-V, but it’s not going to make your Pico 2 application do anything new that you couldn’t do with the ARM cores.
A note on security
One last thing worth mentioning about the RP2350’s features: there’s a ton of functionality built around security. Apparently, one of the challenges the RP2040 chip has had in finding its way into commercial applications is its lack of robust security. I never thought of an embedded chip as a potential security vulnerability, but apparently there are risks of things like malicious code injections or interception of unencrypted communications. Hence, the new chip introduces a bunch of new features such as:
- One-time-programmable (OTP) memory, which allows you to “burn in” security hashes or keys
- SHA-256 acceleration
- A hardware true random number generator (TRNG)
- A strange “redundancy coprocessor” and hardware fast “glitch detectors” that is meant to somehow detect unexpected instructions running in the CPU. (There’s a lot of documentation in the official datasheet that reads like Klingon to me.)
There’s a secure-boot mode which, if enabled, only boots a binary if it has been signed using a private key, with a hash of the corresponding public key stored in OTP.
The Raspberry Pi Foundation is so proud of this new functionality that they featured the RP2350 in the electronic badges at this year’s DEF CON 32 conference with a $10,000 bounty offered to anyone who can hack it.
Pico 2 Availability and Pico 2 W news
I didn’t personally see the product release announcement until almost two weeks after August 8th, and when I looked at my two go-to suppliers, Adafruit and SparkFun, the Pico 2 showed up as backordered. Both suppliers have their own custom boards driven by the RP2350 chip such as the SparkFun Pro Micro RP2350, but that product is also showing up as backordered. (I got the Pro Micro RP2040 a while ago. It has a cool RGB multicolor onboard LED and their convenient Qwiic connector.)
As of today, August 22nd, people on the various embedded Rust community boards are mentioning that their own Pico 2 boards are due to arrive in the mail in a couple days, so it looks like it’ll be a little while before you and I will be able to get ours. I put a pre-order in with SparkFun, so I’ll write an update when mine arrives. In the initial Raspberry Pi press release, they mentioned the following:
While there is relatively little stock in channel today, Pico 2 is in full-rate production with our friends at Sony. Many of our Approved Reseller partners are operating backorder and reservation schemes, and we will be shipping units to them on a regular basis over the next few weeks.
If you’ve been following my blog series on developing Rust on the RP2040, and especially if you got your own Pico W board to follow along, it’s worth noting that these initial Pico 2 board come without headers, so if you want to try these out, you’ll need to do your own header soldering.
The last thing worth pointing out is that this Raspberry Pi Pico does not have native wireless networking. Again, if you’ve been following my blog series, it is focused on the Pico W and using the Embassy project to enable transmission of data so that we can be portable and send sensor telemetry to a server somewhere. But fear not, both of these things will be addressed soon enough. In the same press release, the Raspberry Pi folks wrote the following:
Before the end of the year, we expect to ship a wireless-enabled Pico 2 W, using the same Infineon 43439 modem as Pico W, and versions of both Pico 2 and Pico 2 W with pre-installed 0.1-inch headers.
So what about Rust support?
As you can imagine, this is what I’ve been following the most closely. On that same August 8th launch day, Rust developer Jonathan “theJPster” Pallant released this great and informative blog post announcing that he had been working for a while with a prototype board to port the rp2040-hal
to the new RP2350 chip. His github repository already had 17 of the example programs working in both ARM and RISC-V mode, with another three running only on ARM, allowing him to declare “To my knowledge this is the first ever microcontroller launch with Rust support out-of-the-box.” Four days ago, he published the first 0.1.0 version of the rp235x-pac
peripheral access crate. He also has a pull-request into rp-rs
to have his work get pulled into the official Raspberry Pi project so that the RP2040 and RP235X families can share their proper lineage moving forward.
There’s still plenty of work to do. Jonathan’s blog goes into a lot of great detail about how the RP2350’s boot process differs from the 2040. Currently you have to use the picotool
utility from Raspberry Pi’s (C/C++) SDK to upload your binaries, so I can’t use the current probe-rs
system to upload and debug programs. The debugging challenge comes from the fact that the RP2350 chip uses the newer ARM Debug Interface Version 6 (ADIv6), which isn’t supported yet, but apparently the probe-rs
are already looking into this.
Embassy support
The last piece that I’m tracking is, unsurprisingly, Embassy support. It looks very “preliminary” at the moment. There is a new rp2350-v2
branch in the Embassy project, but mostly I’m just seeing some patches in the existing project to make way for rp2040 to be an explicitly declared “feature”. On the Matrix.io discussion board, it sounds like people are still waiting for their boards to show up in the mail.
Since I essentially associate Embassy with networking, I’ll be hoping to try to get that working in about 3–4 months when the Pico 2 W is available. Given the speed by which everyone is already working, that seems reasonable.
Getting Blinky Working
On Sept 14th my Raspberry Pi Pico 2 board was delivered! The next day I worked toward the goal of getting the classic Blinky app running to get everything going end-to-end. I ran into a couple hitches, so I wanted to capture some notes here to help you out.
If you’ve been reading the rest of my blog about the rp2040
and going through the examples, you’re going to find yourself on a slightly different path.
Behind the scenes, there is still work going on with the probe-rs
team to support the needs of the new ARM Debug Interface Version 6 (ADIv6) protocols and to get the basic support working. I suspect their next binary release of the debug probe firmware will include everything we need to follow my preferred development path, but until that time you’ll need to follow the old-school path:
- Step 1: Use
cargo build
to build your application binary, either selecting thethumbv8m.main-none-eabihf
target for the ARM Cortex M33 cores or theriscv32imac-unknown-none-elf
target for the cool new RISC cores! - Step 2 (option 1): Use
picotool
to load the binary directly onto the board. - Step 2 (option 2): Use the same
picotool
to convert the binary to a.uf2
file that you can then drag directly on the board’s UF2 loader.
But first: setting up your environment!
The first thing you are going to need to do is build this picotool
command. Picotool is part of the Raspberry Pi Pico SDK. Back before I was learning Rust, when I was trying to write sample applications in C/C++, the SDK was a necessary starting point.
With my rp2040
blog series, I’ve been happily working with my pure-Rust development ecosystem, and the only thing I needed from the SDK was the CYW43 chip’s networking firmware. But now I found myself needing to download the fresh new version of the SDK—this one supporting both the Pico and Pico 2 family—and build the tooling.
I first found a good location near the top of my Pico development folder structure and then installed the SDK via github checkout:
git clone https://github.com/raspberrypi/pico-sdk
I set my environment variable PICO_SDK_PATH
to the directory I’d cloned the SDK into.
Then I downloaded the separate picotool
library into a parallel directory via:
git clone https://github.com/raspberrypi/picotool
There were two other dependencies libusb
and pkg-config
that I needed to install, so I used brew install libusb pkg-config
on my Mac. If you’re using Linux, you’ll do sudo apt install libusb
and I’m not sure if you need the pkg-config
part. (Also, make sure you already have CMake installed in your environment.)
The other part was a little counter-intuitive: within my picotool
directory, I needed to make a build
subdirectory, cd
into that directory, and then type:
cmake ../
Once that ran successfully, I was able to finally build everything via:
make -j8
(The -j8
part is optional. It tells the system to go ahead and do parallel builds where possible. The “8” part suggests you have 8 cores, so it runs up to 8 processes simultaneously when building things.)
From there, you may install picotool
systemwide with sudo make install
, but I have a directory ( ~/bin
) under my user account for local binaries, so I just copied the binary there. You’ll want to test that everything is working by executing the command picotool version
and verifying a version of v2.0.0 or later.
You’ll also want to make sure these new targets are in your Rust toolchain by running both of these:
rustup target add thumbv8m.main-none-eabihf
rustup target add riscv32imac-unknown-none-elf
Compiling and Running the Example
Jonathan’s initial library is at https://github.com/thejpster/rp-hal-rp2350-public , and until his work is formally incorporated into an official release of the rp-rs
library, I’m going to suggest first cloning this initial port. (At least that’s what I have documented here.)
I cloned the library and built everything with the following:
git clone https://github.com/thejpster/rp-hal-rp2350-public
cd rp-hal-rp2350-public
cargo build --example pwm_blink --target thumbv8m.main-none-eabihf --all-features
cargo build --example pwm_blink --target riscv32imac-unknown-none-elf --all-features
(A note: JP’s instructions had a typo on that last command. He had the target as rv32imac-unknown-none-elf
which isn’t a known target.)
Final steps: running the examples
In order to flash your application to the Pico 2 board, you need to hold the BOOTSEL button down (the little white button) and while holding it down you connect it to your dev computer via a microUSB cable.
Once you’ve plugged it in, you can then release the BOOTSEL button. At this point you should see two things.
First of all, you should be able to type picotool info -d
and see information about your device. My output looks like this:
Thor:rp-hal-rp2350-public murray$ picotool info -d
Device Information
type: RP2350
package: QFN60
chipid: 0x9d301f1514c1922b
flash devinfo: 0x0c00
current cpu: ARM
available cpus: ARM, RISC-V
default cpu: ARM
secure boot: 0
debug enable: 1
secure debug enable: 1
flash size: 4096K
The second this is that the device will appear as a USB storage device on your system named RP2350. It will appear to have two files: INDEX.HTM which redirects to this Raspberry Pi page and an INFO_UF2.TXT file that just has the contents:
UF2 Bootloader v1.0
Model: Raspberry Pi RP2350
Board-ID: RP2350
The old fashioned way I used to do Pico development (in C/C++) was to create a .uf2
binary. When you copy/drag that binary onto the USB storage device, it would get flashed onto the board, and then immediately the board would detach from USB (giving me an annoying warning about not ejecting the device first!) and it would reboot and try to run the application.
If you want to do this, you can use the picotool
by executing:
picotool uf2 convert ./target/thumbv8m.main-none-eabihf/debug/examples/pwm_blink -t elf ./pwm_blink.uf2
…and then dragging the resulting pwm_blink.uf2
file onto the USB device. If you want to do this compiled for the RISC-V cores, you would simply say this instead:
picotool uf2 convert ./target/riscv32imac-unknown-none-elf/debug/examples/pwm_blink -t elf ./pwm_blink.uf2
The simpler way, however, is to use the picotool load
command to load the binary directly. Here you would say:
picotool load -t elf ./target/thumbv8m.main-none-eabihf/debug/examples/pwm_blink
for ARM or
picotool load -t elf ./target/riscv32imac-unknown-none-elf/debug/examples/pwm_blink
for RISC-V.
Then you can tell the board to reboot via picotool reboot
.
By the way, the picotool load
commands in JP’s blog had some typos in the path to the binary, so things will go smoother if you use the lines I’ve given above.
Up next: The Pull-down Resistor Flaw
It’s time to publish this revision, but there’s one last bit of news regarding the Pico 2. Unfortunately, there was a design flaw with the GPIO pull-down resistors. I don’t think it would impact any of my code from my rp2040 blog (when the time comes to port it across) but I might try to come up with a demo that shows off the bug and discusses when you would ever run into it and how to work around it.
Updates:
- Aug 26: As of Thursday, Aug 22nd, some of the developers on the community boards showed pictures of their newly-arrived boards. As you can imagine, most of the discussion on the
rp-rs
discussion board is about the 253x development work. - Oct 2: I’m remiss in not getting an update here earlier. (Sorry readers!) On Saturday, Sept 14th, my Pico 2 board was delivered. The next day it took a couple hours to figure out all the steps needed to get the classic blinky demo working. I followed the instructions that Jonathan had on his blog post and had to work through a couple issues related to some typos in his example.