Portability
(This section is optional. Feel free to skip to the next section, where we clean our code up a bit and call it a day.)
You may wonder whether all this fancy ecosystem is worth its weight. The setup for our blinky is pretty fancy, and uses a lot of Rust crates and features for such a simple job.
One cool advantage, though, is that our code becomes really portable. On a different board, the setup may be different, but the actual blinky loop is identical!
Let's take a look at a blinky for the Sipeed Longan Nano. This is a little $5 board that, like the MB2, is an embedded board with an MCU. Otherwise, it is completely different: different processor (the GD32VF103, with a RISC-V instruction set entirely unlike the ARM instruction set we're using), different peripherals, different board. But it has an LED attached to a GPIO pin, so we can blinky it.
#![no_std] #![no_main] use panic_halt as _; use riscv_rt::entry; use gd32vf103xx_hal::{pac, prelude::*, delay::McycleDelay}; use embedded_hal::{blocking::delay::DelayMs, digital::v2::OutputPin}; #[entry] fn main() -> ! { let dp = pac::Peripherals::take().unwrap(); let mut rcu = dp.RCU.configure().ext_hf_clock(8.mhz()).sysclk(108.mhz()).freeze(); let gpioc = dp.GPIOC.split(&mut rcu); let mut led = gpioc.pc13.into_push_pull_output(); let mut delay = McycleDelay::new(&rcu.clocks); loop { delay.delay_ms(500); led.set_high().unwrap(); delay.delay_ms(500); led.set_low().unwrap(); } }
The differences in setup here are partly because different hardware, and partly because this code
uses an older HAL crate that hasn't yet been updated for embedded-hal
1.0. Yet the main loop is
identical as advertised, and the rest of the code is pretty recognizable. Because of the portability
provided by Rust's easy cross-compilation and the embedded Rust ecosystem, blinky is just blinky.
You can find a complete working nanoblinky example on GitHub, if you want to see all the details or even get your own board and try it yourself.