Skip to content

Introduction to Embedded Systems Development with Rust on Raspberry Pi

For decades, C and C++ have dominated embedded systems and hardware-level programming. However, modern systems demand both raw performance and absolute security. Rust is a system-level language that guarantees memory safety and thread safety at compile time, eliminating common bugs like null pointer dereferences, buffer overflows, and data races.

This guide shows you how to set up a Rust development environment for Raspberry Pi, configure cross-compilation, and write safe GPIO control code.


1. Why Choose Rust for Raspberry Pi?

  1. Memory Safety: The Rust compiler validates memory access patterns at compile-time (via Ownership and Borrowing rules), eliminating segmentation faults.
  2. Zero-Cost Abstractions: High-level abstractions (like iterators, pattern matching, and closures) compile down to machine instructions as fast as hand-written C.
  3. Concurrency Safety: Rust prevents data races (multiple threads trying to write to the same memory address concurrently) by validating data sharing at compile-time.
  4. Modern Tooling: cargo handles dependency management, compiling, and testing seamlessly.

2. Setting Up the Rust Cross-Compiler

While you can compile Rust code directly on a Raspberry Pi, compiling on a more powerful host PC (Linux, macOS, or Windows) is significantly faster. We will configure cross-compilation to target Raspberry Pi's 64-bit architecture (aarch64-unknown-linux-gnu).

1. Install Rust on Your Host PC

Run the official Rust installer:

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

2. Add the Target Architecture

Add the toolchain target for 64-bit Raspberry Pi OS:

rustup target add aarch64-unknown-linux-gnu

3. Install Cross-Compilation Linkers (Ubuntu/Debian Host)

sudo apt install gcc-aarch64-linux-gnu -y

4. Configure Cargo Linker

Create a global Cargo config file (or a local .cargo/config.toml in your project root) and specify the linker:

[target.aarch64-unknown-linux-gnu]
linker = "aarch64-linux-gnu-gcc"

3. Creating a Rust Hardware Project

1. Initialize a Cargo Binary Project

cargo new rpi_gpio_demo
cd rpi_gpio_demo

2. Add the rppal Library Dependency

rppal (Raspberry Pi Peripheral Access Library) is the standard Rust crate providing safe access to GPIO, I2C, SPI, PWM, and UART.

Open Cargo.toml and add:

[dependencies]
rppal = "0.14.1"

4. Writing GPIO Logic in Rust

Let's write a program that sets up a GPIO output pin (LED) and an input pin (button), turning on the LED only when the button is pressed.

Open src/main.rs and write:

use std::error::Error;
use std::thread;
use std::time::Duration;
use rppal::gpio::Gpio;

// Define BCM pins
const LED_PIN: u8 = 18;
const BUTTON_PIN: u8 = 23;

fn main() -> Result<(), Box<dyn Error>> {
    println!("Initializing GPIO...");

    // Initialize the GPIO driver
    let gpio = Gpio::new()?;

    // Configure the LED pin as an output
    let mut led = gpio.get(LED_PIN)?.into_output();

    // Configure the Button pin as an input with a Pull-Up resistor
    let button = gpio.get(BUTTON_PIN)?.into_input_pullup();

    println!("GPIO Ready. Press the button to turn on the LED. Press Ctrl+C to exit.");

    loop {
        // Read input pin state
        if button.is_low() {
            // Button is pressed (connected to ground)
            led.set_high();
        } else {
            // Button is released
            led.set_low();
        }

        // Small sleep to prevent 100% CPU thread lock
        thread::sleep(Duration::from_millis(50));
    }
}

Safety Features of rppal:

  • Ownership validation: If you try to call gpio.get(18) twice, rppal returns an error, preventing two independent parts of your code from trying to configure the same physical hardware pin simultaneously.
  • Resource Cleanup: When variables led and button go out of scope, Rust's drop checker automatically cleans up the pin configuration, acting as an automatic hardware RAII guard.

5. Compiling and Transferring Binaries

1. Compile the project

Build the binary targeting the Raspberry Pi:

cargo build --target aarch64-unknown-linux-gnu --release

2. Transfer the Binary to your Pi

scp target/aarch64-unknown-linux-gnu/release/rpi_gpio_demo pi@192.168.1.100:/home/pi/

3. Run on Raspberry Pi

SSH into your Raspberry Pi and execute the binary:

./rpi_gpio_demo