At some point I noticed that the Raspberry Pi foundation is selling the Pico 2 with the RP2350 microcontroller.
This chip was interesting to me because it contains both ARM Cortex-M33 cores but also Hazard3 RISV-V cores.
So I bought some Pico 2 boards to get some small ARM and RISC-V hardware to write compilers for.
This blogpost is my notes from getting the boards flashed with MicroPython using picotool.
Some studying
Once the boards arrived it was time to do some light reading and getting our bearings in the documentation. There is a quite a lot of documentation that seems to be of good quality and here is some of the things that I found. It is not necessary to read all of this material and this list is intended as my quick-reference.
Raspberry Pi Pico-series Python SDK
A MicroPython environment for Raspberry Pi microcontrollers.
Raspberry Pi Pico SDK
Raspberry Pi Pico-series C/C++ SDK
Libraries and tools for C/C++ development on Raspberry Pi microcontrollers
RP2350 Datasheet - A microcontroller by Raspberry Pi
Hardware design with RP2350 - Using RP2350 microcontrollers to build boards and products
Raspberry Pi Pico 2 Datasheet - An RP2350-based microcontroller board
Getting started with Raspberry Pi Pico-series
C/C++ development with Raspberry Pi Pico-series and other Raspberry Pi microcontroller-based board
USB Flashing Format (UF2)
picotool
picotool is a tool for woring with RP2040/RP2350 binaries, and interacting with RP2040/RP2350 devices when they are in BOOTSEL mode. (As of version 1.1 of picotool it is also possible to interact with devices that are not in BOOTSEL mode, but are using USB stdio support from the Raspberry Pi Pico SDK by using the -f argument of picotool).
Raspberry Pi - MicroPython
MicroPython is a full implementation of the Python 3 programming language that runs directly on embedded hardware like Raspberry Pi Pico. You get an interactive prompt (the REPL) to execute commands immediately via USB Serial, and a built-in filesystem. The Pico port of MicroPython includes modules for accessing low-level chip-specific hardware.
MicroPython - Quick reference for the RP2
What to actually read
-
"Getting started with Raspberry Pi Pico-series"
-
The picotool repository readme (https://github.com/raspberrypi/picotool)
-
Raspberry - MicroPython (https://www.raspberrypi.com/documentation/microcontrollers/micropython.html) + More documentation links.
-
MicroPython Pico 2 (https://micropython.org/download/RPI_PICO2/) + This has firmware download links. + Return to bootloader:
machine.bootloader() -
MicroPython - Quick reference for the RP2 (https://docs.micropython.org/en/latest/rp2/quickref.html)
Getting picotool
We need to build the picotool program from source and we do this by following the instructions in the git repository readme file.
On my Ubuntu 22.04.5 laptop all that was necessary was the following.
$ sudo apt install libusb-1.0-0-dev $ mkdir ~/pico2-build $ cd ~/pico2-build $ git clone https://github.com/raspberrypi/pico-sdk $ cd pico-sdk $ git submodule update --init $ cd ~/pico2-build $ git clone https://github.com/raspberrypi/picotool $ export PICO_SDK_PATH=~/pico2-build/pico-sdk $ cd picotool $ cmake . $ make -j 10 $ sudo make install
Now it is time to connect the Pico 2 board. The microcontroller is delivered with a bootloader in ROM memory. The bootloader will either run a some program already in the microcontroller or it can enter "BOOTSEL mode" (USB boot). In order to write new programs to flash we need to get the microcontroller into USB boot mode. The default is for the microcontroller to run the application program (if there is one in the flash memory). If there is no program the microcontroller appears to do nothing. To get into USB boot mode it is necessary to hold the BOOTSEL button while connecting the Pico 2 USB connection. The BOOTSEL button is the only button on a Pico 2.
If we have not connected the Pico 2 correctly we may see this error.
$ sudo picotool info -a No accessible RP-series devices in BOOTSEL mode where found.
In my case it turned out the USB cable was bad, go figure… If the Pico 2 is connected but not in BOOTSEL mode we may get something like the following output instead.
sudo picotool info -a No accessible RP-series devices in BOOTSEL mode were found. but: Device at bus 3, address 14 appears to be an RP-series MicroPython device not in BOOTSEL mode. Device at bus 3, address 12 appears to be an RP-series MicroPython device not in BOOTSEL mode.
In this case there are devices that appear to be Raspberry Pi hardware but they are not in BOOTSEL mode so picotool can not communicate with them.
Once we have the Pico 2 in BOOTSEL mode and we run picotool info -a we should see something like:
$ sudo picotool info -a Program Information none Fixed Pin Information none Build Information none Device Information type: RP2350 revision: A2 package: QFN60 chipid: 0x9de4a20330c588d5 flash devinfo: 0x0c00 current cpu: ARM available cpus: ARM, RISC-V default cpu: ARM secure boot: 0 debug enable: 1 secure debug enable: 1 boot_random: 63f18545:59f483bf:09391077:545c179b boot type: bootsel last booted partition: slot 0 reboot param 0: 0x00000000 reboot param 1: 0x00000000 rom gitrev: 0x312e22fa Metadata Blocks none
Program MicroPython in ARM mode
Now that we have the Pico 2 board working with picotool it is time to write the firmware.
First we can download it from https://micropython.org/resources/firmware/RPI_PICO2-20250415-v1.25.0.uf2 (see https://micropython.org/download/RPI_PICO2/).
Then we can program it using picotool load like this:
$ picotool load --execute RPI_PICO2-20250415-v1.25.0.uf2 Family ID 'rp2350-arm-s' can be downloaded in absolute space: 00000000->02000000 Loading into Flash: [==============================] 100% The device was rebooted to start the application.
The --execute causes the microcontroller to reset and execute the new program. Without it the microcontroller remains in BOOTSEL mode. There is also picotool reboot to manually reboot the microcontroller.
Now there should be a USB device that looks like this
$ lsusb ... Bus 003 Device 009: ID 2e8a:0005 MicroPython Board in FS mode ...
There should also be a tty device /dev/ttyACM0 and we can open the device with a serial console program like for example picocom.
$ sudo picocom -q /dev/ttyACM0 MicroPython v1.25.0 on 2025-04-15; Raspberry Pi Pico2 with RP2350 Type "help()" for more information. >>>
We have a MicroPython REPL! Since this blogpost is really just about getting things setup there is not that much more to do. There are two commands that was useful for keeping track of which device is which.
>>> import platform >>> platform.platform() 'MicroPython-1.25.0-arm--with-newlib4.3.0' >>> import machine >>> machine.unique_id().hex() '3481d72148b10c09'
Inventory
This just my own little inventory to keep track of which board is which. The boards have no human readable identification so I added "9d" and "34" stickers.
-
9d 9de4a20330c588d5 MicroPython-1.25.0-arm—with-newlib4.4.0
-
34 3481d72148b10c09 MicroPython-1.25.0-riscv—with-newlib4.3.0
Next steps
For me the next steps is probably going to be something like:
-
Write a led-blinker and hello-world using the C/C++ SDK. This is so that I have a small base to build on and learn from. Because studying the machine code of an entire MicroPython executable is to much code.
-
Investigate if and how programs can run code from SRAM. It would be nice to avoid having to write to flash for every small test run of compiled code, so I will try to run code from SRAM first.
-
Investigate how to write code to flash from a running application. Because at some point it may become interesting to write a bootloader.
-
Prepare a in-cirquit debugger.
Because outside of the releative safety of MicroPython it will be really useful to have a proper debugger. Especially when running programs that contain machine code generated by my own tools that probably contains bugs. First I need to program one Pico 2 as a in-cirquit debugger and then learn how to use OpenOCD (Open On-Chip Debugger) with GDB.
That is all
Have a nice day!