Rust on embedded RISC-V

Théo Rozier, January 3rd, 2022

In this series of blog posts, I'm going to explain how I managed to develop in Rust on the Ox64 SBC powered by a RISC-V heterogenous SoC. These posts will cover different methodologies you can use for finding relevant documentation and resources while working on such a niche board, in general you can use this series for writing Rust software on any SoC for any architecture.

Table of contents

Board

The board I chose is a PINE64 Ox64, as stated on their wiki, it's a Single Board Computer powered by a Bouffalo Lab BL808 SoC. This SoC is an heterogenous system with three separate CPUs:

I chose this particular board for it's multimedia subsystem, which is mounted around the C906 CPU. I was especially interested in its video processing capabilities.

Ox64 on my desk, just received

Pinout

This board doesn't embed any USB to UART module, the micro-USB port is only for 5V power supply and the USB-C port is not linked to such module. Therefore I had to solder two 20 pins connectors on the board in order to plug it on a breadboard, and then link it to a CP2102 USB to UART module.

The pinout of the board can be found online on their wiki, in general it's good to keep your board's pinout and schematics, it will often be useful if you want to go further (Ox64 Schematic 20221018 v1.1).

It can also be useful to have an oscilloscope around the corner, or simply a multimeter in order to measure status pins. You can additionally use a JTAG probe (in my case a SEGGER J-Link Pro) to debug the chip while running. The pinout is also quite complicated if we want to properly connect status and reset pins.

Ox64 on the breadboard, wired to CP2102 and J-Link probe

Software

As said in the introduction, my goal is to develop in Rust. To do so, we use the official Rust installer rustup to install the toolchain (GNU on Linux and MSVC on Windows for example), note that stable toolchain is enough! Once installed, we need to add some extra targets and components to the toolchain with the following commands:

1
2
3
rustup target add riscv32imac-unknown-none-elf
rustup component add llvm-tools-preview
cargo install cargo-binutils

The first command installs the 32-bit RISC-V compiler and tools, the second installs LLVM compiler tools, such as objcopy or objdump. The third line install a cargo binary called cargo-binutils, it's a wrapper that links cargo and LLVM tools, this provides additional cargo commands to run an LLVM tool directly on a cargo build's output.

If your distro already provide rustc or cargo via its dependency manager, it's likely that they will not provide the right components for embedded development nor the latest Rust version, so please consider using rustup.

For the text editor, I chose Visual Studio Code with rust-analyzer. This isn't important and everyone has its own preferences, but the important point in my opinion is to have autocompletion and type hints, this allows seeing static constraints on types.