Rust & IoT

Petr Hodina

  • What is Rust?
  • Rust for IoT
  • Demo
“Rust is a systems programming language that runs blazingly fast, prevents segfaults, and guarantees thread safety. ”

Features

  • zero-cost abstractions
  • guaranteed memory safety
  • threads without data races
  • trait-based generics
  • pattern matching
  • minimal runtime
  • efficient C bindings

Hello world


fn main() {
    println!("Hello, world!");
}
					

$ rustc main.rs
$ ./main
Hello, world!
					

Cargo

  • Build system
  • Package manager

$ cargo new hello_world --bin
					

$ cd hello_world
$ cargo run
   Compiling hello_world v0.1.0 (file:///projects/hello_cargo)
     Running `target/debug/hello_world`
Hello, world!
					

Control & safety

Control & safety

Concepts

  • Ownership
  • Borrowing
  • Match
  • Errors
  • Unsafe

Borrowing


                let v = vec![1, 2, 3];
                let v2 = v;
                // ..
                println!("First element: {}", v[0]);
                

                let v2 = v;
                -- value moved here
                // ..
                println!("First element: {}", v[0]);
                                              ^ value used here after move
                

No error for copy type

References


fn main() {
    let s1 = String::from("hello");

    let len = calculate_length(&s1);

    println!("The length of '{}' is {}.", s1, len);
}

fn calculate_length(s: &String) -> usize {
    s.len()
}
                

Mutable References


fn main() {
    let mut s = String::from("hello");

    change(&s);
}

fn change(some_string: &String) {
    some_string.push_str(", world");
}
                

One mutable reference or unlimited read-olny references

Match pattern


enum UsState {
    Alabama,
    Alaska,
    // ... etc
}

enum Coin {
    Penny,
    Nickel,
    Dime,
    Quarter(UsState),
}

fn value_in_cents(coin: Coin) -> u32 {
    match coin {
        Coin::Penny => 1,
        Coin::Nickel => 5,
        Coin::Dime => 10,
        Coin::Quarter(state) => {
            println!("State quarter from {:?}!", state);
            25
        },
    }
}
                

Errors


use std::fs::File;

enum Result {
    Ok(T),
    Err(E),
}

fn main() {
    let f = File::open("hello.txt");

    let f = match f {
        Ok(file) => file,
        Err(error) => {
            panic!("There was a problem opening the file: {:?}", error)
        },
    };
}

Unsafe

  • Dereferencing a raw pointer
  • Calling an unsafe function or method
  • Accessing or modifying a mutable static variable
  • Implementing an unsafe trait

let mut num = 5;

let r1 = &num as *const i32;
let r2 = &mut num as *mut i32;

unsafe {
    println!("r1 is: {}", *r1);
    println!("r2 is: {}", *r2);
}
                

Rust for IoT

STM32F3 Discovery

  • Microcontroller: STM32F303VCT6
  • Core: ARM Cortex-M4 + FPU
  • RAM: 40+8 KiB
  • Flash: 256 KiB
  • Peripherals: Timers, Serial, I2C, SPI, PWM, etc.

Tools

  • A nightly Rust toolchain.
  • Xargo, to build the core crate
  • Linker: ld
  • Debugger: gdb
  • OpenOCD

Useful crates

  • cortex-m
  • stm32f30x
  • corrode
  • rust-bindgen

LED blinking


#![feature(used)]
#![no_std]

// version = "0.2.0", default-features = false
extern crate cast;
extern crate cortex_m;
extern crate cortex_m_rt;
extern crate stm32f30x;

use core::u16;

use cast::{u16, u32};
use cortex_m::asm;
use stm32f30x::{GPIOE, RCC, TIM7};

mod frequency {
    /// Frequency of APB1 bus (TIM7 is connected to this bus)
    pub const APB1: u32 = 8_000_000;
}

/// Timer frequency
const FREQUENCY: u32 = 1;

#[inline(never)]
fn main() {
    // Critical section, this closure is non-preemptable
    cortex_m::interrupt::free(
        |cs| {
            // INITIALIZATION PHASE
            // Exclusive access to the peripherals
            let gpioe = GPIOE.borrow(cs);
            let rcc = RCC.borrow(cs);
            let tim7 = TIM7.borrow(cs);

            // Power up the relevant peripherals
            rcc.ahbenr.modify(|_, w| w.iopeen().enabled());
            rcc.apb1enr.modify(|_, w| w.tim7en().enabled());

            // Configure the pin PE9 as an output pin
            gpioe.moder.modify(|_, w| w.moder9().output());

            // Configure TIM7 for periodic timeouts
            let ratio = frequency::APB1 / FREQUENCY;
            let psc = u16((ratio - 1) / u32(u16::MAX)).unwrap();
            tim7.psc.write(|w| w.psc().bits(psc));
            let arr = u16(ratio / u32(psc + 1)).unwrap();
            tim7.arr.write(|w| w.arr().bits(arr));
            tim7.cr1.write(|w| w.opm().continuous());

            // Start the timer
            tim7.cr1.modify(|_, w| w.cen().enabled());

            // APPLICATION LOGIC
            let mut state = false;
            loop {
                // Wait for an update event
                while tim7.sr.read().uif().is_no_update() {}

                // Clear the update event flag
                tim7.sr.modify(|_, w| w.uif().clear());

                // Toggle the state
                state = !state;

                // Blink the LED
                if state {
                    gpioe.bsrr.write(|w| w.bs9().set());
                } else {
                    gpioe.bsrr.write(|w| w.br9().reset());
                }
            }
        },
    );
}

// This part is the same as before
#[allow(dead_code)]
#[used]
#[link_section = ".rodata.interrupts"]
static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240];

extern "C" fn default_handler() {
    asm::bkpt();
}

Links

  • rust-lang.org
  • crates.io
  • play.rust-lang.org