Skip to content
This repository was archived by the owner on Dec 9, 2018. It is now read-only.

Latest commit

 

History

History
238 lines (175 loc) · 8.06 KB

2017-07-14.md

File metadata and controls

238 lines (175 loc) · 8.06 KB

Weekly status report

From 2017-07-08 to 2017-07-14

RFCs

A few weeks ago the Rust core team, the Rust subteams, and core Rust contributors met at the Mozilla All Hands week to discuss outstanding Rust issues, specially related to the 2017 roadmap. One of the covered topics was making progress towards making embedded / no-std development possible on stable.

From the blockers identified from this survey Xargo, panic_fmt, compiler-builtins and asm! were discussed. From those four a stabilization path was identified for Xargo and panic_fmt, and this week I have written the RFC proposals for those stabilization paths. The TL;DRs are:

Xargo

Land a minimal part of Xargo's functionality into Cargo. Basically Cargo will be able to (cross) compile the core, std or test crates from the rust-src component on stable. This RFC has a much smaller scope than a previously proposed RFC: no support for Cargo features or custom source, no elimination of the sysroot and implicit dependencies, no publishing the standard crates on crates.io, etc.

panic_fmt

A #[panic_implementation] attribute will be added to the language. It will behave like the #[global_allocator] attribute and will let you specify the behavior of panic! in no-std context. Example below:

// cf. https://doc.rust-lang.org/std/panic/struct.PanicInfo.html
use core::panic::PanicInfo;

// use this instead of `#[lang = "panic_fmt"]`
#[panic_implementation]
fn my_panic(pi: &PanicInfo) -> ! {
    // prints: "program panicked at 'reason', src/main.rs:3:4"
    write!(&MY_STDERR, "program panicked at {}", pi).ok();

    // .. and diverge somehow ..
}

I'm now waiting on feedback from the Rust team before submitting the RFCs. I want to make sure we are on the same page.

RTFMv2

I continued working on the next iteration of the Real Time for The Masses framework. Relevant changes since last week:

  • the rtfm! macro has been renamed to app!

  • the macro parser has been refactored into its own crate.

  • I have made the fields init.path and idle.path optional. If omitted these fields default to the paths init and idle respectively, which is what most people will use, I expect.

  • I have replaced all the panic! / unwraps in the proc macro implementation with proper error handling (:heart: error-chain :heart:). You now get nice backtraces when there's an error in the contens of the app! macro. For example:

app! {
    device: blue_pill::stm32f103xx,

    tasks: {
        SYS_TICK: {
            priority: 1,
            resources: { SYST }, // <- wrong delimiter
        },
    },
}

produces:

error: proc macro panicked
  --> examples/blinky.rs:16:1
   |
16 | / app! {
17 | |     device: blue_pill::stm32f103xx,
18 | |
19 | |     tasks: {
...  |
24 | |     },
25 | | }
   | |_^
   |
   = help: message: Error: parsing
           Caused by: parsing `tasks`
           Caused by: parsing task `SYS_TICK`
           Caused by: parsing `resources`
           Caused by: expected Bracket, found Brace

I believe this is good as the error messages can get without proper span information.

RTFM on MSP430

The main motivation for moving the app! macro parser into its own crate was to share code between this crate and the port of the RTFM framework to the MSP430 architecture. Yup, you can now use this very same macro and the task and resources model to write concurrent applications for MSP430 microcontrollers 🎉.

With this refactor it should be straightforward to port the RTFM frameworks to other architectures like AVR once they become available on upstream rustc.

Device families

This week a discussion started on creating a HAL tailored for device families. The main goal here is to share as much code as possible between devices that belong to the same family.

To elaborate:

We currently use svd2rust to get hardware support for a bunch of different devices. svd2rust transforms one SVD file into one device crate; that crate provides a low level register API to use the hardware. Then we have embedded-hal which is a HAL, a set of traits, that can be implemented for device crates and provides a higher level API that "erases" all the device specific details like registers and magic hexadecimal values.

The issue with the current implementation of this approach is that depending on the vendor one SVD file could represent one microcontroller or a few very similar microcontrollers; this actually results in a bunch of duplicated code because vendors tend to reuse peripheral designs across their products. In Rust-speak the types stm32f100xx::TIM2, stm32f101xx::TIM2 and stm32f102xx::TIM2 and their APIs are semantically the same but the code is duplicated across device crates so the types are not equal in the eyes of the Rust compiler. This may not sound too bad because that duplicated code was generated by a tool but this problem carries over the next layer: where a human has to implement the HAL traits on top of these crates:

// crate: stm32f100xx-hal-impl

impl hal::Timer for stm32f100xx::TIM2 {
    // implementation that some person wrote
}

// crate: stm32f101xx-hal-impl

impl hal::Timer for stm32f101xx::TIM2 {
    // the exact same implementation has to be written here
}

// crate: stm32f102xx-hal-impl

impl hal::Timer for stm32f102xx::TIM2 {
    // more code duplication here
}

We want to avoid this. We can do that by de-duplicating the types at the device crate level. So instead of having svd2rust generating a bunch of duplicated code in different crates, we want it to generate something like this:

// crate: stm32-common

// declare the type and its API *once*
pub struct TIM2 { .. }

impl TIM2 { .. }

// crate: stm32f100xx
extern crate stm32_common;

// then just re-export it across device crates
pub use stm32_common::TIM2;

// crate: stm32f101xx
extern crate stm32_common;

pub use stm32_common::TIM2;

We have yet to figure out how to structure such re-export system but we have been analyzing how much duplication such system would avoid. A tool was written to spot peripherals that are the same across different SVD files. For some vendors the de-duplication is very significant: across 52 SVD files from the Silabs vendors 1802 peripherals are declared (i.e. svd2rust would have generated 1802 different types) but there are only 55 unique instances. So with the re-export logic 1747 types would have not been duplicated.

Community highlight

@cr1901 has ported a MSP430 application from C to Rust. The application is an AT keyboard protocol to XT keyboard protocol converter. The result of the rewrite was a functional 2KB Rusty firmware that exactly fitted in a miniscule MSP430G2211 microcontroller. Apparently the Rust version ended up being slightly larger than the original C version binary size wise. @cr1901 will be looking into further optimizing the application for binary size. I hope they'll give my MSP430 port of the RTFM framework a try for their next iteration!

TODO

  • release RTFM v2 + blog post

  • Blog post about Rust on MSP430

  • Continue working on the HAL.

  • Launch an initial version of the areweembeddedyet.com site.

  • Start a series of blog posts about developing the robotic application.

  • Finish cleaning the crate that supports the BLE400 development board and announce on u.r-l.o.