Blink... Blink... Blink...

In Bobbin CLI: Getting to Blinky I introduced Bobbin CLI, but I didn’t actually answer how you actually get to Blinky, the embedded world’s “Hello, World”.

There are many excellent posts and tutorials showing how to get a board blinking using many different different types of hardware and development tools, including the excellent Rust your ARM microcontroller. But sometimes you need something more basic: you simply want to know whether your toolchain and hardware work!

It also may be the case that you have hardware that isn’t covered by an existing project, particularly if you are using Rust. There are hundreds of development boards out there, but there are only a small handful that have any kind of Rust projects associated with them.

This is what Bobbin Blinky is: a collection of minimal Blinky applications.

These crates are meant to be fast to compile and easy to debug. This means:

  • Each crate is board specific.
  • There are no additional dependencies, not even compiler_builtins.
  • Code is generated using opt-level = "s"
  • All peripheral access is using ptr::read_volatile and ptr::write_volatile.
  • No clock configuration is performed.
  • Hardware watchdogs are disabled if enabled by default.
  • The blink rate is approximate.
  • Exceptions and panics are handled by infinite loop.
  • Constants are hard coded.

An example - the STM32 Nucleo-F429ZI development board:

#![no_std]
#![no_main]
#![feature(asm)]
#![feature(lang_items)]

pub mod lang_items;
pub mod exceptions;

use core::ptr;

// LED0 = PB0;

pub const RCC_AHB1ENR: *mut u32 = 0x4002_3830 as *mut u32;
pub const GPIOB_MODER: *mut u32 = 0x4002_0400 as *mut u32;
pub const GPIOB_BSRR: *mut u32 = 0x4002_0418 as *mut u32;

#[no_mangle]
pub extern "C" fn main() -> ! {
    unsafe {
        // Enable PORTB
        ptr::write_volatile(RCC_AHB1ENR, ptr::read_volatile(RCC_AHB1ENR) | 1 << 1);
        // Set PB0 Mode = Output
        ptr::write_volatile(GPIOB_MODER, ptr::read_volatile(GPIOB_MODER) | 1 << 0);
        loop {
            // Set PB0
            ptr::write_volatile(GPIOB_BSRR, 1 << 16);
            // Delay approx 1/2 second
            for _ in 0..2_000_000 { asm!("nop") }
            // Reset Set PB0
            ptr::write_volatile(GPIOB_BSRR, 1 << 0);
            // Delay approx 1/2 second
            for _ in 0..2_000_000 { asm!("nop") }
        }
    }
}

produces a binary of this size in about 110 second of compile time:

$ bobbin build
   Compiling nucleo-f429zi v0.1.0 (file:///home/bobbin/bobbin-blinky/nucleo-f429zi)
    Finished dev [optimized + debuginfo] target(s) in 0.12 secs
   text	   data	    bss	    dec	    hex	filename
    148	      0	      4	    152	     98	target/thumbv7em-none-eabihf/debug/nucleo-f429zi
$

which can then be loaded onto a board so that you can see it work:

$ bobbin load
    Finished dev [optimized + debuginfo] target(s) in 0.0 secs
   text	   data	    bss	    dec	    hex	filename
    148	      0	      4	    152	     98	target/thumbv7em-none-eabihf/debug/nucleo-f429zi
     Loading target/thumbv7em-none-eabihf/debug/nucleo-f429zi
    Complete Successfully flashed device
      Loader Load Complete
$

These crates don’t replace proper examples and tutorials, but I hope they’re a resource that both new and experienced developers use when want to do a quick end-to-end check of their toolchain and their hardware. The ultimate goal is have a crate for every significant commerial and open source board that it is possible to target using Rust.

Currently, 23 boards covering roughly 20 Cortex-M MCUs from seven different vendors are represented.

Development Boards with Embedded Debug Probes

Boards without Embedded Debug Probes

Future Boards

Boards that are currently unsupported at this time but of interest:

Feel free contact me with suggestions of other interesting boards to add to the list.

Troubleshooting

If you get errors or the board simply doesn’t blink, here’s a good list of things to check:

  • Make sure you have the most recent version of Bobbin CLI by running cargo install bobbin-cli --force.
  • Run bobbin check to see the versions of the prerequisites that Bobbin CLI can find. You may need to install newer versions of these prerequisites.
  • The next most likely cause is the firmware for the on-board debugger if your board has one. You may wish to review Bobbin CLI - Development Board Firmware for an overview of the situation and links to updated versions.

Conclusion

It’s incredibly satisfying getting boards up and running from scratch. Go out, grab a board, and make it blink!