Using RISC-V cores on the Raspberry Pi Pico 2 board and RP2350 MCU – From blinking an LED to building Linux

Raspberry Pi Pico 2 was released last month with a Raspberry Pi RP2350 microcontroller equipped with two Arm Cortex-M33 cores and two 32-bit RISC-V “Hazard3” cores with up to two cores usable at any time. So in this guide, we’ll show how to use the RISC-V cores on the RP2350 MCU, compare their performance against the Arm Cortex-M33 cores, and even build Linux for RISC-V for RP2350 boards that have PSRAM.

Apart from the extra memory and more powerful cores, plus new features related to security and the HSTX interface, the Raspberry Pi Pico 2 and Pico will be very similar to the end user and the instructions in our article “Getting Started with Raspberry Pi Pico using MicroPython and C” remain valid. I don’t think there’s a MicroPython RISC-V image yet, so we’ll focus on running C programs on the RISC-V cores.

A quick check with the Arm cores

Raspberry Pi Pico 2 USB cable Debug Probe kit

I received a kit with the Raspberry Pi Pico 2, a micro USB to USB cable, and the Raspberry Pi Debug Probe, and I’ll use all these in this article.

Since we’ll benchmark the Arm cores later, I’ll install the C/C++ environment for Arm first and blink the onboard LED to make sure my Raspberry Pi Pico 2 sample works fine.:Let’s install the dependencies, SDK, and code samples:


The steps above are exactly the same as for the Raspberry Pi Pico. Let’s now build the blink_simple demo for the RP2350 target:


The procedure is almost the same as on the Raspberry Pi Pico, except we need to add “-DPICO_PLATFORM=rp2350” to build the RP2350, as the Pico SDK defaults to RP2040.

We have a bunch of files:


We can confirm the Arm architecture is used here:


Let’s copy the “blink_simple.uf2” firmware to the Raspberry Pi Pico 2 that shows up as RP2350 in the file manager.

Raspberry Pi Pico 2 Blink simpleThe onboard LED starts blinking. Success!

Raspberry Pi Pico 2 Arm RISC-V LED blink

Blinky on the RISC-V cores

Let’s reproduce this on the RISC-V cores. We’ll need to check the Pico C/C++ SDK PDF documentation to get the right toolchain, where we learn (in section 2.10) that only the more recent GCC versions support the Hazard3, meaning it would have to be built from source, or we can select another toolchain such as the CORE-V toolchain available for various Linux distributions and macOS.

CORE-V RISC-V toolchain

My laptop is still running Ubuntu 22.04, so I downloaded and installed the relevant toolchain, and set the export PICO_TOOLCHAIN_PATH and PICO_RISCV_TOOLCHAIN_PATH variables:


Now we can go back to the blink_simple directory and configure the blink_simple sample to be built with the RISC-V toolchain:


Let’s check the output of the latest command to make sure the RISC-V toolchain has been selected:


It looks good. We can also see some of the samples won’t work on RISC-V as they rely on features only available to the Arm cores.

Let’s try to build the sample:


We have the same bunch of files but with different sizes:


For instance, the blink_simple.uf2 is 13824 bytes when compiled for RISC-V, but was 12800 bytes for Arm.

Let’s double-check our new blink_simple.elf file:


RISC-V it is! Another utility to check the architecture is the uf2conv.py script from Microsoft:


Time to enter bootloader mode by pressing the BOOTSEL button and power cycling the Pico 2 board, before copying the blink_simple.uf2 file to the RP2350 drive…

Success! The LED is blinking with the Raspberry Pi Pico 2 running our RISC-V binary.

Serial output on the Raspberry Pi Pico 2 / Cytron MOTION 2350 Pro

Since I’m going to run a benchmark, I’ll need some serial console to visualize the output. I don’t have headers where I am right now, but I do have some jumper cables, so I solder three wires to pin 1 to 3 of the Raspberry Pi Pico 2 and connected it to the Raspberry Pi Debug Probe.

Raspberry Pi Pico 2 serial Debug Probe

Then I build the hello_world using RISC-V to give it a try:


But I didn’t find any UF2 file there:


But after the initial confusion, I realized there are two hello_world samples. The “serial” sample outputs data through serial and requires a USB to TTL board, while the “usb” sample outputs data through USB to serial, so we don’t need the debug probe, and the micro USB to USB cable is enough…

However, it looks like I may have managed to temporarily “brick” my Raspberry Pi Pico 2 (See RISC-V Linux section), and after several failed attempts at recovery, I decided to switch to Cytron MOTION 2350 Pro board for testing that part… I started with the hello_serial.uf2.

RP2350 Hello World Serial

This uses the Bootterm program and /dev/ttyACM0 device exposed by the Raspberry Pi Debug Probe.

I then copied the hello_usb.uf2 to the board and only used a USB-C cable and Bootterm connected to /dev/ttyACM1 device exposed by the USB interface of the Raspberry Pi RP2350 microcontroller.

RP2350 Hello World USB serial

All good. Let’s have a quick look at the hello_serial.c code


and the hello_usb.c code:


Wait… What? Those are the exact same files. The difference is only in the CMakeLists.txt.

Serial:


USB:


Simply setting the following two lines switch from serial to USB serial output:


Good to know.

Coremark on the Arm and RISC-V cores of the Raspberry Pi RP2350 MCU

I wanted to run a benchmark to evaluate the performance of the Hazard3 RISC-V core(s) against the Arm Cortex-M33 core(s). I found the CoreMark-RP2040 project on GitHub, which I managed to build for RISC-V after changing the  Makefile to add “-DPICO_PLATFORM=rp2350-riscv” to the cmake command:


I also had to export the full path for the Pico SDK even though I have checked out the project in the pico-examples directory. Running make all could complete the build:


The UF2 file can be found in the artifacts_to_upload directory:


I copied it to the RP2350 drive (MOTION 2350 Pro board) and could start the CoreMark benchmark in the serial console, but it did not work:


There must be some modification needed. TaterLi (see comments) told me to set MULTITHREAD to 1 in src/core_portme.h. And indeed it works:


But something is wrong as the score (286.2 CoreMark/MHz) is completely different from the one in the Hazard3 repository for the RISC-V core found in the RP2350 MCU:


That’s 3.81 CoreMark/MHz.

I tried again to run the performance on one of the Arm Cortex-M33 cores:


Here the score is 280.83 CoreMark/MHz or similar to the 286 CoreMark/Mhz for the RISC-V core.  Note that it’s not a standardized test…

The 3.81 CoreMark/Mhz reported for the Hazard3 RISC-V is likely better compared to the Cortex-M33 in the LPC55xx microcontroller as the document entitled “LPC55xx CoreMark on Cortex-M33 Porting Guide” mentions 4.08 CoreMark/MHz. In any case, both the Cortex-M33 and Hazard3 cores have very similar integer performance. One person ran a sample with floating-point and the Hazard3 core is currently much slower than the Cortex-M33 cores because it’s using a software implement, while the Cortex-M33 relies on “highly optimized FP routines”.

RISC-V Linux for RP2350 boards with PSRAM

Mr-Bossman has recently released a RISC-V Linux port using the buildroot build system which you can find on GitHub. The Raspberry Pi Pico 2 won’t be able to run RISC-V Linux simply because it does not have enough RAM with only 520KB from the RP2350 MCU and just 4MB flash on the board for storage. That’s why the RISC-V Linux port was tested on the Sparkfun Pro Micro – RP2350 board with 16MB flash and 8MB PSRAM.

Nevertheless, I’ll try to build the Linux image on my laptop, and I’ll also get a working RISC-V gcc toolchain in the process:


This will take a while and ends with:


We can check the resulting images in the relevant directory:


“Image” is the Linux kernel, “rootfs.ext2” the root file systems, “raspberrypi-pico2.dtb” the device tree file, and “flash-image.bin” the complete image.  It is 6MB in size, so you’d need a Raspberry Pi RP2350 board with at least 8MB flash plus some PSRAM.

We are not quite finished and we have one more command to complete the build:


The last command fails with:


That’s because CMakeList.txt needs to be updated to match the config of your system, notably the three lines below:


After changing those lines the build could complete and only failed when trying to flash the image since I didn’t connect any:


If I connect my Raspberry Pi Pico 2 it goes further asking me for the sudo password when running picotool to flash the image for the board:


Since it’s designed for the Sparkfun Pro Micro – RP2350 only, I stopped there. It still managed to change something as my Pi Pico 2 won’t run the blinky sample and outputs the following in the serial console:


That’s because a new bootloader was copied to the board:


I’m stuck. While I can copy a different UF2 firmware, the board won’t reboot, and the update apparently fails since it’s still running the psram-bootloader after a power cycle.  I’ve asked on Raspberry Pi forums and we’ll see if there’s a solution. [Update: The solution – in the comments section below and the forum thread – was to simply copy flash_nuke.uf2 to the board to clear the flash].

That will be all. I hope this article can help some people more easily get started with the RISC-V cores on the Raspberry Pi Pico 2 board and RP2350 MCU.

Share this:

Support CNX Software! Donate via cryptocurrencies, become a Patron on Patreon, or purchase goods on Amazon or Aliexpress

ROCK 5 ITX RK3588 mini-ITX motherboard
Subscribe
Notify of
guest
The comment form collects your name, email and content to allow us keep track of the comments placed on the website. Please read and accept our website Terms and Privacy Policy to post a comment.
12 Comments
oldest
newest
Georgi Angelov
14 days ago

clean
make -j4 ( four )
how long does it take: make a blink

Simon Wright
Simon Wright
13 days ago

I managed to mess up my board by using GDB to load an ESP32-H2 elf file, which writes to ~0x4000_0000. Revived it by finding, downloading and loading flash_nuke.uf2 to clear all flash

TaterLi
13 days ago

Modify MULTITHREAD to 1, located in core_portme.h, because at present RP2350 no matter RISC-V or ARM platform, his multi-core support is not very perfect. BUILD_TYPE=Debug RISC-V Result: 2K performance run parameters for coremark. CoreMark Size  : 666 Total ticks   : 14935940 Total time (secs): 14.935940 Iterations/Sec  : 267.810396 Iterations    : 4000 Compiler version : GCC13.2.0 Compiler flags  : og Memory location : STACK seedcrc     : 0xe9f5 [0]crclist    : 0xe714 [0]crcmatrix   : 0x1fd7 [0]crcstate   : 0x8e3a [0]crcfinal   : 0x65c5 Correct operation validated. See README.md for run and reporting rules. CoreMark 1.0 : 267.810396 / GCC13.2.0 og / STACK 12345678910111213141516 2K performance run parameters for coremark.CoreMark Size  : 666Total ticks   : 14935940Total time (secs): 14.935940Iterations/Sec  :… Read more »

TaterLi
13 days ago

It could be compiler or no optimization (debug mode) related.

The compiler is based on a recent build of riscv/riscv-gnu-toolchain.

TaterLi
13 days ago

Use better compilation args (rv) 2K performance run parameters for coremark. CoreMark Size    : 666 Total ticks      : 13315515 Total time (secs): 13.315515 Iterations/Sec   : 450.602173 Iterations       : 6000 Compiler version : GCC13.2.0 Compiler flags   : -O3 -g -march=rv32ima_zicsr_zifencei_zba_zbb_zbkb_zbs -mbranch-cost=1 -funroll-all-loops --param max-inline-insns-auto=200 -finline-limit=10000 -fno-code-hoisting -fno-if-conversion2 Memory location  : STACK seedcrc          : 0xe9f5 [0]crclist       : 0xe714 [0]crcmatrix     : 0x1fd7 [0]crcstate      : 0x8e3a [0]crcfinal      : 0xa14c Correct operation validated. See README.md for run and reporting rules. CoreMark 1.0 : 450.602173… Read more »

Yenda
Yenda
11 days ago

Can anyone enlighten me what is the rationel behind adding two kinds of cores? Feels like silicon waste (ie price hike) without any benefit, except it’s kinda cool?

yenda
yenda
10 days ago

Thanks!

anan
10 days ago

This is an interesting article. It’s a good way to get some risv-v experience.

Khadas VIM4 SBC