Giter VIP home page Giter VIP logo

wg's Introduction

Embedded devices Working Group

Coordination repository of the embedded devices Working Group (WG)

This repository issue tracker is used by the embedded WG to coordinate efforts towards making Rust a great choice for embedded development.

Want to get started with embedded development with Rust? Check out our embedded Rust book and the rest of our bookshelf.

Want to stay up-to-date with community progress? Check out our newsletter.

Join the discussion on Matrix! #rust-embedded:matrix.org

Vision

What is it that we really want? At a broad level:

  • To improve the absolute quality (functionality, safety, performance) of embedded software in the wild.
  • To improve the productivity of embedded software development teams, by reducing the tangible and intangible costs of achieving a level of quality.
  • To improve the experience for programmers developing for embedded systems.
  • To make embedded systems programming more accessible for people that are not already embedded systems developers.

What we do

At a high level we have two main tasks:

We work with the community to improve the embedded ecosystem.

  • We maintain and develop core crates in the embedded ecosystem ensuring that the development roadmap aligns with the needs of its users. You can find all the crates we maintain in the Organization section.

  • We develop and curate resources about embedded Rust development. Check our bookshelf!

  • We maintain and moderate the venues the embedded community uses to discuss. That includes this coordination repository and our Matrix room.

And, we serve as a bridge between the Rust teams and the embedded community.

How you can help

Everyone can contribute to the embedded WG efforts! There are several ways to help out:

  • Let us know where the gaps are. If you think the language, the compiler, the tooling, the documentation or the crate ecosystem is lacking some feature, information or library to build embedded software let us know and we'll bring it up to the Rust teams or organize the community to build the crates or tools to fill the gaps.
  • Participate in RFC (Request For Comments) threads. We are always looking into ways to improve. This may involve things from changing how we run the WG to landing major breaking changes in core crates. To ensure we are actually making things better we need your input! That's why all these changes are preceded by an "RFC", a discussion thread (which may or may not be backed by a proper RFC document) where we evaluate the pros and cons of a proposal and explore alternatives. Only after there's consensus on accepting the proposal is the proposal made effective.
  • Help wanted!. There's always lots to do but the WG members only have so much free time. You can help us fixing bugs, implementing features, writing tests, trying out examples and tutorials, writing documentation, fixing typos, etc. We'll mentor you through these tasks and review your work. In some cases you may not even need previous embedded experience or access embedded hardware to help us out so don't let that discourage you from checking out our help wanted issues.
  • Join our weekly meetings on Matrix. We use these meetings as a faster, synchronous alternative to the RFC threads on GitHub. The agenda is posted in the matrix channel in advance to the meeting. Everyone is free to join the meeting and share their thoughts. You can also nominate an existing GH thread for discussion if you think it would benefit from a more synchronous discussion. The usual meeting time is Tuesdays, 8pm CET/CEST.

  • We have several teams focused on different areas: tooling, Cortex-M crates, etc. and each team maintains several projects (crates, docs and / or tools) that live under the rust-embedded organization. You can collaborate with the maintenance and development of these projects by becoming a project collaborator (consult with the team that owns the project) or by joining the team.

Organization

The WG is composed of several teams whose functions are defined in RFC #136. The embedded WG develops and maintains a large set of projects under the rust-embedded organization. This section lists all the teams and all the projects owned by the WG.

The core team

The functions of the core team are:

  • Representing the WG in meetings with other Rust teams.
  • Communicating the needs of the embedded Rust community (e.g. language features, core API stabilization) to the Rust teams.
  • Giving the casting vote on intra-WG decisions where no voting majority can be achieved.
  • Driving and moderating the weekly meetings.

Members

The Cortex-A team

The Cortex-A team develops and maintains the core of the Cortex-A crate ecosystem.

Members

Projects

Projects maintained by this team.

The Cortex-M team

The Cortex-M team develops and maintains the core of the Cortex-M crate ecosystem.

Members

Projects

Projects maintained by this team.

The Cortex-R team

The Cortex-R team develops and maintains the core of the Cortex-R crate ecosystem.

Members

This team is currently empty! Please get in touch via an issue or the Matrix chat if you are interested in helping to maintain the Cortex-R crates.

Projects

The embedded Linux team

The embedded Linux team develops and maintains the core of the embedded Linux crate ecosystem.

Members

Projects

Projects maintained by the embedded Linux team

The HAL team

The HAL team develops and maintains crates containing shared traits and related code that enables the development of hardware abstraction layers and drivers which can interoperate across all embedded Rust devices on all architectures.

Members

Projects

Projects maintained by the HAL team.

The infrastructure team

The infrastructure team manages our domains, DNS records, e-mail aliases, etc.

Members

Projects

Projects maintained by this team

The libs team

The libs team manages library code that is not architecture-specific.

Members

Projects

Projects maintained by this team

The MSP430 team

The MS430 team develops and maintains the core of the MSP430 crate ecosystem.

Members

Projects

Projects maintained by this team

The RISC-V team

The RISC-V team develops and maintains the core of the RISC-V crate ecosystem.

Members

Projects

Projects maintained by this team

The resources team

The resources team develops, maintains and curates documentation, books, our social media accounts and websites, and similar resources on embedded Rust.

Members

Projects

Projects maintained by the resources team

The tools team

The tools team maintains and develops software for embedded development which typically runs on your development machine rather than the embedded targets themselves.

Members

Projects

Projects maintained by the tools team

The triage team

The triage team is charge of keeping PR queues moving; they ensure no PR is left unattended.

Members

Hibernating and Alumni

The following alumni have put themselves into the hibernation state, due to being absent or busy for an extended amount of time. See ops/hibernating.md.

Contact

Each team can be privately contacted via the following e-mail addresses:

You can usually find the members of the embedded WG on the Rust Embedded Matrix room (#rust-embedded:matrix.org).

Our Matrix room is logged by on the bridged IRC channel, and you can find the logs at: https://libera.irclog.whitequark.org/rust-embedded/

Other projects

These are other projects you may be interested in but that (currently) are not owned by the WG.

Ongoing community efforts

Device specific communities

Several device specific communities exist that are not part of the working group. These communities maintain crates for peripheral access, hardware abstraction, examples, and more that are specific to a particular family of devices. The list below is not exhaustive and will be updated as device support increases.

  • nrf-rs: Nordic nRF series of microcontrollers
  • stm32-rs: STM32 microcontrollers
  • lpc-rs: NXP LPC microcontrollers
  • imxrt-rs: NXP i.MX RT microcontrollers
  • esp-rs: Espressif Systems microcontrollers
  • rp-rs: Raspberry Pi microcontrollers including the RP2040

embedded-hal is a project that aims to build a standard set of traits (interfaces) for I/O functionality common in embedded devices: Serial, I2C, etc. with the goal of serving as a base for building reusable driver crates, crates to interface with external components like sensors.

There are plenty of traits that still need to be designed, in particular ones that involve async I/O. Join the discussion and help us design the missing traits so that they'll fulfill your needs.

To put the embedded-hal to test and to expand the embedded crates.io ecosystem we are running the weekly driver initiative. The goal is to release a new no_std, generic, embedded-hal driver crate every one or two weeks.

There's lots of cool devices that would be great to have drivers for. Join the initiative and help us grow the embedded crates.io ecosystem!

The community is building a curated list of crates useful for embedded development. In this list you'll find driver crates, board support crates and general purpose no-std crates. Help us improve this list by adding your crate via PR or by tackling any of our help wanted issues.

As an experiment the Rust lang user forum has gained a new embedded category.

This is meant as a friendly exchange for anyone interested in embedded topics with Rust.

So if you want to discuss ideas, problems or solutions please feel free to chime in on existing topics or create a new one!

RFCs

When the team deems it necessary the RFC process may be used to make decisions or to design processes, user interfaces, APIs, etc.

Learn more about the Rust's RFC process (which is the same as our own) here.

To create an RFC, simply:

  • clone this repo to your own personal one
  • copy 0000-template.md to text/0000-my-feature.md (where "my-feature" is descriptive. Don't assign an RFC number yet)
  • fill in the details of your RFC in that file
  • Open an pull request with this repository

wg's People

Contributors

adamgreig avatar almindor avatar andre-richter avatar bartmassey avatar bbrown1867 avatar bors[bot] avatar dirbaio avatar disasm avatar dkhayes117 avatar eldruin avatar hannobraun avatar jamesmunns avatar jannic avatar japaric avatar jonas-schievink avatar korken89 avatar laanwj avatar mabezdev avatar mendelt avatar newam avatar notriddle avatar posborne avatar reitermarkus avatar romancardenas avatar ryankurte avatar thalesfragoso avatar thejpster avatar therealprof avatar tmplt avatar yuhanliin avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

wg's Issues

Let's participate in the novemb.rs Code Sprint

Website

TL;DR It's an offline/online/remote Rust code sprint with a focus on
European/African time zones/locations but everyone's welcome no matter their
time zone/location.

The event will last two days: November 19 and 20.

It seems like a great opportunity to get together and work on embedded stuff.
We can use the #rust-embedded IRC channel to coordinate our work.

We are currently discussing what we could work on in rust-community/novemb.rs#4.
The discussion went a little off topic but I've posted what areas I think we
could focus on in my latest comment (see the etherpad link).

Please fill the list in the etherpad if you'd like to participate and let's
discuss about the "focus areas" on that thread.

Embedded.fm Wednesdays in Rust

I would like to learn embedded programming and Rust and I thought that maybe I could follow this blog post serie: http://embedded.fm/blog/embedded-wednesdays

Hopefully taking notes and sharing my findings in the process.

Which microcontroller / development board should I try? In the serie they use STM32F401C discovery board but I don't think Rust supports it. Please correct me if I'm wrong.

Please give a look at the end of this blog post http://embedded.fm/blog/2016/3/22/embedded-tools

What do you think? Thanks!

Async IO for embedded concurrency

I'd like to discuss the merits of async IO style concurrency versus preemptive tasks in embedded applications. Rust may make it easier to write async IO style concurrent embedded applications. See futuro for an example of using a Future trait in an embedded context. But what's the benefit of this style of concurrency vs preemptive tasks (e.g. FreeRTOS)?

My understanding is that on an OS, async IO is preferred for applications with large numbers of blocking tasks because userspace context switching is cheaper than OS context switching. But in an embedded application, there is no OS, so context switching should be just as expensive whether you're using preemptive tasks or callback based co-routines (async IO).

So is there a benefit to writing an embedded application using async IO (presumably using a Future like trait) over preemptive tasks? I've never actually written a concurrent application using async IO, so maybe I'm missing something obvious. Is it significantly more ergonomic? Does it save on stack space? What sort of applications would benefit from being written using async IO?

AVR support

Parent issue: #2

Next steps:

  • Wait until AVR support lands in upstream LLVM
  • Update rust-lang LLVM fork (rust-lang/rust#37609), implement cabi stuff, etc.
  • Experiment with custom targets out of tree (to get the specification right)
  • Get libcore compiling without modifications
  • Upstream all LLVM patches required for the AVR fork (avr-rust/rust-legacy-fork#116)
  • Write documentation about writing/compiling/flashing/debugging Rust
    programs for this target
  • Add the AVR target to the compiler (as a built-in target) (tracking issue rust-lang/rust#44052)
  • ๐ŸŽ‰

See also avr-rust/rust for out of tree work towards AVR support in Rust.

Tooling: Ideal developer experience

Building programs, written in C or Rust, "manually" for microcontrollers is quite complicated as it
involves several device specific files (e.g. linker scripts) and configuration (e.g. compiler flags).

This issue is about what the ideal experience would look like for embedded Rust developers. I think
it's informative to study first what the experience of C/C++ developers looks like:

Embedded C/C++ developers usually (always?) use an IDE and a SDK to make the process
straightforward. Here's how the process looks like for them (disclaimer: this is my vague
recollection)

  • User: Picks the target device (via a GUI)
    • The SDK generates the required linker scripts, chooses what flags to pass to gcc and also what
      libraries (the soft float variant or the hard float variant?) to link to.
  • User: Configure the device (via a GUI): e.g. pick the clock frequency
    • The SDK generates initialization code (crt0.o-ish stuff + configuration of clock, PLL, etc.)
      that runs before main.
  • User: Writes their program in a high level API
    • The SDK will compiles the right implementation of the high level API for the target device
  • User: Clicks "Build & Debug"
    • The SDK compiles the program, flashes the binary to the device and starts a debug session
    • Apart from the standard debug experience: step by step execution, breakpoints, disassembly,
      inspection of memory, etc. the SDK also provides "registers maps" that describe the contents of
      register in a human readable way: instead of hex-speak 0xdeadbeef, you get "the CEN bit of
      the CR register is set" but in a more graphical way.

I think those are, at a "minimum", the conveniences that SDKs provide. SDKs may also include an
OS/RTOS but that sort of escapes the realm of tooling.

What are other niceties that C SDKs provide? And how do you picture the ideal Rust developer
experience? Finally, how could we materialize all those conveniences using Cargo? We probably want
to spawn more issues about this last question.

Consistent development experience

Ideally the development experience for the different embedded targets should be very similar so a
user can easily transition from one target to the target instead of having to redo the setup
process, learn about new tools, learn a new development process, migrate to different crates that
basically do the same things as the ones they were previously using, etc.

This problem can be tackled from different sides:

  • Tooling

It should be possible to use Xargo Cargo, the RLS and some IDE to do development for all the
embedded targets. One click "build, flash and debug" functionality should be present.

I had reports that VS Code plus the cortex-debug plugin works fine for Cortex-M development. The
plugin also has support for printing semihosting and ITM output to the console.

A CLI equivalent should also exist. For example, two subcommands like cargo flash and cargo debug should Do The Right Thing for each embedded target. This may require the user to specify, for
example, what parameters to pass to OpenOCD in some configuration file.

  • Same starting point

Ideally a minimal embedded program should look like this:

#![no_std]

// provides the entry point
extern crate arch_specific_crate;

fn main() {
    // and optionally some debugger based logging functionality
    log!("Hello, world!")
}

for all the embedded targets. This can be accomplish by standardizing a crate like cortex-m-rt and
replicating it for all the embedded targets, and by providing Cargo project templates (with linker
scripts, etc.) for each embedded target.

Cargo doesn't currently provide support for project templates (there was a pre-RFC discussion
months ago but it didn't go anywhere). The solution currently adopted in Cortex-M land is to just
cargo clone a crate from crates.io that serves as a template and go from there (cf.
cortex-m-quickstart). We could adopt that solution or push for proper project template support
in Cargo.

  • Large set of reusable crates

One of Rust's strengths is the crates.io ecosystem. Unfortunately most of the crates.io ecosystem
can't be used in no_std context. There are several reasons for this: the author is not aware that
their crate is compatible with no_std, the author is not willing to depend on unstable crates like
alloc to support no_std, etc.; but hopefully the portability WG will work on this issue.

There's currently an on going community effort of producing generic driver crates (crates to
interface external devices like sensors) that work with any platform that has an implementation of
the embedded-hal traits. Most of the participants are Cortex-M developers; to ensure these
crates and the embedded-hal abstractions work with all the other embedded targets AVR, MSP430 and
RISCV developers must also participate.

  • Ports of multitasking models

There are a few ways to do multitasking on bare metal: RTFM, a Tokio-like cooperative event loop,
good old threads, etc. All these multitasking models should be available for all the embedded
targets. Ideally the different ports of these models should expose the same or very similar APIs.

For more details about multitasking models check issue #45

cc @dvc94ch @pftbest @dylanmckay

Support older versions of the ARM architecture

As of 2017-05-23 Rust officially supports only the ARMv6 and ARMv7 architectures. For ARM Linux, binary releases of std are provided for these targets. For bare metal ARM, there are built-in targets for ARM Cortex-M microcontrollers.

These are two cases that I know of that are currently unsupported:

  • ARMv5 processors that run Linux
  • ARMv4 processors (microcontrollers?) that operate without an OS

ARMv5 Linux

std

These targets want to use std but from the POV of LLVM these targets don't support atomics as there are no atomic load / store instructions in the instruction set. This leaves these targets with two options:

  • Declare max-atomic-width as being 0. This removes atomic types like AtomicUsize from libcore making it impossible to build libstd as std depends on those atomic types. The built-in target armv5te-unknown-linux-gnueabi does this.

  • Declare max-atomic-width as being 32. With this change libstd can be compiled but trying to link a std program will result in linker errors of the form: "undefined reference to __sync_fetch_and_foo". As there are no atomic instructions LLVM lower atomic operations to these intrinsics. These intrinsics will have to be provide by the user as there's no implementation for then in the compiler-rt project. One possible implementation for these intrinsics is to use Linux's kernel user helpers as suggested here.

uclibc

Some of these targets want to use uclibc instead of glibc because that's what their systems' OS uses. The complication here is that the libc crate does not support uclibc. However the libc crate does compile when compiled for an uclibc target, but it will actually assume that the target is using glibc. This is rather bad because uclibc and glibc don't have the same ABI so using the libc crate for an uclibc target can result in a segfault / crash at runtime.

Important: All std programs make use of the libc crate so all std programs are affected by this issue.

Bare metal ARMv4

I don't have details for this target but since it's a bare metal target it will work in no_std mode. A custom target will be required as there's no built-in target in rustc. The specification of that custom target can probably derived from the specification of an existing target. thumbv6m-none-eabi seems like a good base target:

$ rustc -Z unstable-options --print target-spec-json --target thumbv6m-none-eabi
{
  "abi-blacklist": [
    "stdcall",
    "fastcall",
    "vectorcall",
    "win64",
    "sysv64"
  ],
  "arch": "arm",
  "data-layout": "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64",
  "env": "",
  "executables": true,
  "features": "+strict-align",
  "is-builtin": true,
  "linker": "arm-none-eabi-gcc",
  "linker-flavor": "gcc",
  "llvm-target": "thumbv6m-none-eabi",
  "max-atomic-width": 0,
  "os": "none",
  "panic-strategy": "abort",
  "relocation-model": "static",
  "target-endian": "little",
  "target-pointer-width": "32",
  "vendor": ""
}

Increase discoverability of embedded crates on crates.io

Hey all,

Lately I have been thinking about how we can increase the discoverability of the
embedded ecosystem (tooling, crates, documentation, etc.). Part of that effort
is making it easier to find relevant crates on crates.io and that's why I have
opened this issue.

Background:

A categories feature landed recently (well, not that recently) on crates.io
(you can see list of current categories here) and I think we may be able to
leverage it to increase the visibility of embedded crates.

I have gone through all the crates collected in this survey and have
classified them according to whether they are using categories on crates.io or
not (see list at the bottom). Most crates are not using categories at all. The
crates that are using categories are using the following categories:

  • command-line-utilities
  • concurrency
  • data-structures
  • development-tools
  • development-tools::debugging
  • embedded
  • hardware-support
  • no-std

Now some questions:

Have categories helped you find a crate that you needed for embedded development
before? Or did you even know about them?

Do you think that categories on crates.io help with discoverability, or that
instead we should have a more curated list of crates for embedded development?

Do you think we should reach out to the authors of the embedded crates listed at
the bottom and encourage them to add relevant categories to their crates?

What categories do you think we should encourage people to use?

Are there categories that you think are missing?

Finally a request: If you are an author of embedded / no-std crates on crates.io
please add categories to your crates to increase their discoverability!


cc @posborne @jamesmunns @thejpster @vitiral

Has categories

bitflags
Categories: no-std

xargo
Categories: embedded development-tools command-line-utilities

log
Categories: development-tools::debugging

cortex-m
Categories: embedded no-std hardware-support

slog
Categories: development-tools::debugging

cortex-m-quickstart
Categories: embedded no-std

cortex-m-rtfm
Categories: embedded no-std concurrency

heapless
Categories: data-structures no-std

No categories

lazy_static

intrusive-collections

fixedvec

sysfs-gpio

i2cdev

spidev

log_buffer

teensy3

cpuio

alloc_buddy_simple

pic8259_simple

volatile_register

spin

linked_list_allocator

rlibc

x86

prusst

m

lm4f120

fel-cli

alloc-cortex-m

cortex-m-semihosting

byteorder

build-const

defrag

Doesn't apply

meta-rust
Not on crates.io

meta-rust-bin
Not on crates.io

compiler_builtins
Likely will never be on crates.io as it's part of the sysroot

bridge-rpc
Not on crates.io

Abstract support for peripheral drivers for communication protocols

The following list of protocols are often found as drivers in many embedded systems:

  • SPI
  • I2C
  • CAN
  • UART
  • Ethernet
  • The protocol the WS2812 leds use (very popular in hobby projects)

Each application often needs to use these in slightly different ways, and need support for: interrupts, asyncio of some form, and blocking operation typically. It would be great as a community, especially for the microcontroller/arduino sub-ecosystem to standardize on some sort of interface for these and standard libraries.

An easy and standard API to these peripherals will help produce. The ARM provided CMSIS layer tends to build up some of this standardization, at least trying to make what might be disparate peripherals feel very similar to the application programmer.

RTOS implementations / bindings

Parent issue: #55

Place to discuss RTOS implementations / bindings.

There's some agreement on making some standard RTOS API (traits) and then have the implementation adhere to that.

TODO

Define tasks to tackle

One step setup

Embedded development involves cross compilation and remote debugging; the Rust toolchain doesn't
provide all the tools so you have to install external ones like: a cross linker (e.g.
arm-none-eabi-ld), a cross debugger (e.g. arm-none-eabi-gdb), some tool to communicate with the
remote target (e.g. OpenOCD), etc.

It would be great if the user didn't have to figure out where to get all those tools and install
them manually.

There are a few upcoming changes that might affect this situation.

lld is a multi-arch linker and it can be used to link ARM Cortex-M binaries so once this is in
place user won't need to install arm-none-eabi-ld.

I don't think lld supports any of the other embedded targets (MSP430, AVR or RISCV) though

lldb is a multi-arch debugger. I personally could never get it to work with OpenOCD; I never found
an equivalent to the monitor and load commands which are used to flash the binary into the
remote target. lldb can debug ARM Cortex-M programs just fine; I have used it debug a emulated ARM
Cortex-M microcontroller (QEMU).

Maybe someone had more luck with it and can share their experience?


One way to address this setup problem could be to provide a installer (script) like
https://rustup.rs/ does but for each target architecture.

cc @jcsoo

Survey: unstable features you routinely (have to) use

This goal of this survey is to get an idea of what (currently) unstable Rust features would need to be stabilized to make embedded development feasible on the stable channel.

One unstable feature per comment. If an unstable feature you use is already listed in the comments up vote it (:+1: reaction) so we can track the number of users that feature has.

Cargo doesn't work out of the box for Cortex-M micros

The Rust compiler supports the Cortex-M architecture but this doesn't work out of the box:

$ cargo build --target thumbv6m-none-eabi

for two reasons:

  • thumbv6m-none-eabi is not a "built-in" target so you have to supply your own target definition.
  • cargo build doesn't compile the standard crates and there's no binary release of the standard
    crates for this target.

The upstream solution is to either:

  • Add the thumb targets to the compiler and also provide binary releases of the standard crates
    for them. Or,
  • Just add the targets and teach Cargo how to build the standard libraries "on the fly".

This is being worked on. Seems like the Rust team is leaning towards the second solution. You can
track the upstream status in:

`cargo-objdump`, `cargo-size`, etc.

Triage

2018-06-29

The llvm-tools rustup component now exists and cargo-binutils is making use of it. Check this announcement for details.

Let's discuss the final UI we want for the Cargo subcommands in the cargo-binutils issue tracker.


Once #50 is accepted / implemented it would be nice to have wrapper over e.g. llvm-objdump for
convenience. The wrapper would take care of passing -triple=$target to llvm-objdump, demangling
the output, passing the path to the binary to llvm-objdump, etc.

We don't have to wait until #50 is implemented though; we can start prototyping on top of
arm-none-eabi-objdump.

Tasks

  • Define what kind of user interface we want. To be done in the cargo-binutils repository.

  • Prototype cargo-objdump, cargo-size, etc. on top of arm-none-eabi binutils

  • Make cargo-objdump et al. use LLVM binutils once #50 is implemented.

Originally discussed in #43 but I think this more in line with #44

cc @thejpster

Ship llvm binutils with the Rust toolchain

As per the discussion in #43, it would be convenient to have LLVM tools like llvm-objdump and
llvm-size shipped with the Rust toolchain. These would remove the need to have to install GCC
binutils which require you to do one binutils install per target architecture. OTOH, LLVM binutils
have multi-arch support and support all (most?) the architectures that rustc supports (since rustc
is LLVM based).

Tasks

We are looking for someone to take on this task:

  • Submit an RFC to ship llvm binutils with the Rust toolchain. @japaric can help with the
    edition of the RFC.

The RFC should make the case for having these tools shipped with the Rust toolchain. llvm-objdump,
llvm-nm and llvm-size are pretty useful to diagnose problems and to measure / estimate metrics
like binary size and performance. llvm-objcopy can be used to translate ELF files (what rustc
usually outputs) into binary files (what program loaders expect). llvm-cov nicely complements
rustc profiling support (-Zprofile).

The team will bring this up during the Rust All Hands event (last week of March) and we'll see if we need an RFC.

@whitequark is llvm-cxxfilt actually needed? It shouldn't contain architecture specific code,
right? Also, there's a Rust implementation of c++filt.

The RFC should note that note as a drawback that does this makes us more reliant on LLVM but we are
already shipping lld (a much bigger LLVM tool) with the Rust toolchain as of rust-lang/rust#48125
(we should submit the RFC after that PR lands).

Part of #43

Make the communication channels more visible

Currently it is not very clear how somebody could contact the "Rust Embedded" community.
Through a Google search, I found that the links are actually mentioned in the RFC.

Could you guys please add the Gitter and Mozilla IRC links to the "Rust Embedded" org description?

Survey: Crates you use for embedded development

Ultimately, we'd like to have a list of curated crates that are nicely categorized in a presentable format (a website with search function, etc.). But, for starters, let's list here all the crates we use for embedded development.

Just add a comment here with the list of crates that you use The crate can be a library or a tool (binary). Try to stick to the following format:

[`$crate_name`]($crates_io_url_or_github_repo_url) - $description
Tags: `$tag1` `$tag2` ...

I'll be collecting them here in the top comment. Try to not to list a crate that has already been mentioned unless you'd like to propose more tags for it.

The tags at this point are free form and can be anything you think will be useful to someone that has to decide whether they can use that crate or not (is it for my target architecture/device? Is it no_std? etc.).

This is also a good opportunity to figure out what are common tags that we could use for #11.


Here's the list so far:

bitflags - A macro for C-like bit flags, pretty useful for modeling hardware registers.
Tags: no_std macro bitflags

lazy_static - A macro that allows to initialize a static using arbitrary code.
Tags: no_std macro static lazy

rustc_builtins - Current state of the Rust port of compiler-rt. Provides various intrinsics that are required by the compiler.
Tags: no_std compiler-rt instrinsics

DEPRECATED in favor of the official compiler_builtins crate (see below)

xargo - A drop-in replacement for Cargo that compiles the sysroot for custom targets on the fly.
Tags: cargo sysroot core libcore liballoc libcollections

intrusive-collections - Intrusive (non-allocating) singly/doubly linked lists and red-black trees.
Tags: no_std intrusive rbtree collections

log - Supports logging in no_std environments, as long as you define your own logger type.
Tags: no_std log

cortex-m - Low level access to Cortex-M processors
Tags: arm cortex-m hardware no_std register peripheral

meta-rust - Yocto layer providing from-source version of the Rust compiler and Cargo
Tags: build yocto

meta-rust-bin - Yocto layer that uses pre-built Rust and Cargo from rust-lang.org
Tags: build yocto

fixedvec - Vec-like interface to a pre-sized buffer of memory. Allows using something like Vec when doing heapless programming.
Tags: no_std

sysfs-gpio - A Rust Interface to the Linux sysfs GPIO interface
Tags: hardware linux gpio

i2cdev - Rust library for interfacing with i2c devices under Linux
Tags: hardware linux i2c

spidev - Rust library providing access to spidev devices under Linux
Tags: hardware linux spi

log_buffer - Rust library for logging into a circular string buffer
Tags: no_std

slog - Supports logging in no_std environments, as long as you implement your own Drain
Tags: log no_std

teensy3 - Rust interface layer for the Teensy 3.1/3.2 microcontroller
Tags: arm cortex-m hardware no_std

cpuio. Bare metal (no_std) inb, outb, inw, outw, inl, outw instructions, with a Rust-friendly API.
Tags: no_std x86

alloc_buddy_simple. Simple, drop-in replacement allocator for Rust running on bare metal. This intended for small, known-size heaps that contain simple collections, such as lists of USB devices discovered on the bus.
Tags: allocator no_std

pic8259_simple. Kernel-space interface to the 8259 and 8259A interrupt controllers.
Tags: no_std interrupts

volatile_register - for memory mapped registers
Tags: kernel_mode no_std registers

spin - a spinlock Mutex
Tags: no_std

linked_list_allocator - basic memory allocation
Tags: bare_metal no_std allocator

rlibc - pure Rust implementation of some required C library functions (like memset)
Tags: no_std intrinsics
NOTE the compiler_builtins crate also provides memset (see below)

compiler_builtins - Instrinsics LLVM needs
Tags: no_std intrinsics

x86. Library to program x86 (amd64) hardware. Contains x86 specific data structure descriptions, data-tables, as well as convenience function to call assembly instructions typically not exposed in higher level languages.
Tags: x86 no_std

prusst - Rust interface to the PRU subsystem on AM335x processors (BeagleBone & other SBC)
Tags: hardware linux pru beaglebone

m - A C free / pure Rust mathematical library ("libm") for no_std code
Tags: no_std math float

lm4f120 - A set of drivers for the TI LM4F120.
Tags: bare-metal drivers

fel-cli - CLI tools for dealing with Allwinner devices in FEL mode, in pure Rust.
Tags: arm sunxi allwiner fel

alloc-cortex-m - A heap allocator for Cortex-M processors
Tags: arm cortex-m allocator

cortex-m-semihosting - Semihosting for ARM Cortex-M processors
Tags: cortex-m arm semihosting

cortex-m-template - A Cargo project template for ARM Cortex-M bare metal development
Tags: arm cortex-m Cargo template

DEPRECATED in favor of cortex-m-quickstart (see below)

byteorder - Library for reading/writing numbers in big-endian and little-endian.
Tags: endian big-endian little-endian byte binary

cortex-m-quickstart - A template for building applications for ARM Cortex-M microcontrollers
Tags: arm cortex-m template

cortex-m-rtfm - Real Time For the Masses (RTFM), a framework for building concurrent applications, for ARM Cortex-M microcontrollers
Tags: arm cortex-m concurrency

heapless - static friendly data structures that don't require dynamic memory allocation
Tags: no-heap static

build-const - a helper library for computing constants at compile time in build.rs or a script. Also includes no_std macros for importing them
Tags: embedded no_std build const static

defrag - safe defragmenting memory manager for microcontrollers
Tags: no_std embedded memory manager microcontroller

bridge-rpc - (in development) a protocol designed to allow a system of different devices, to communicate with each other and issue commands through (optionally) guaranteed unique remote procedural calls. It allows inter-network communication through the concept of "bridges". Both nodes and bridges can be highly resource constrained devices (such as microcontrollers). Intended supported networks include tcp/ip, UART, CAN and ZigBee.

aligned - Statically allocated arrays with guaranteed memory alignments
Categories: embedded memory-management no-std
Tags: alignment aligned array

cty - Type aliases to C types like c_int for use with bindgen
Categories: embedded ffi no-std
Tags: bindgen ffi c types

scroll A suite of powerful, extensible, generic, endian-aware Read/Write traits and contextual conversion traits (Byte serializing and deserializing)
Tags: pread bytes endian pwrite

ssmarshal - stupid simple (no_std) serde serialzation library
Tags: no_std, (TODO)

smoltcp - A TCP/IP stack designed for bare-metal, real-time systems without a heap.
Tags: tcp network udp ethernet ip

byte - A low-level, zero-copy, panic-free, binary serializer and deserializer. (parser and encoder)
Tags: no_std byte encode binary parser

clerk - A hardware agnostic HD44780 LCD controlling library.
Tags: embedded driver

stlog A lightweight logging framework for resource constrained devices
Categories: embedded no-std development-tools::debugging
Keywords: log elf symtab

lcd - Yet another HD44780/LCD display library (third, at least)! Batteries are not included: all binding to the hardware/GPIO initialization is the responsibility of the user (including the sleep function).
Tags: no_std embedded

genio - io::{Read, Write} traits for no_std. It has wrappers for std::io::{Read, Write} to allow use in crates that support std and no_std. Its Read, Write traits have associated type parameters to support custom error types.

framed - Rust crate to send and receive data over lossy streams of bytes.

cstr_core - #[no_std] port of std::ffi::CStr and std::ffi::CString. CString support is optional, and uses the alloc crate instead of std.

hashmap_core - #[no_std] port of std::collections::HashMap and std::collections::HashSet. This crate uses alloc instead of std and uses FNV as the default hash function since SipHash requires a source of random numbers.

Maintenance of core parts of the embedded / Cortex-M ecosystem

A.K.A. @japaric is a bottleneck for development :-)

There are critical components of the embedded / Cortex-M ecosystem that are currently being
maintained by me. Unfortunately I don't have the bandwidth to keep up with everything so issues and
PRs have been piling up in some repos.

This issue is a call for maintainers (if you want to help leave a comment!) and a place to discuss
how to organize maintainership duties.

First, these are the crates that should be maintained by more people:

  • embedded-hal

Abstractions for things like Serial, SPI, I2C, etc. to build generic drivers that work with AVR, ARM
Cortex-M, MSP430, RISCV, etc. microcontrollers.

There's a bunch to do here as some abstractions are missing and async support is currently
nonexistent. Most of the work to do here is ensuring that the established process for adding new
traits is followed and that discussions move towards consensus.

Quite a few people have volunteered to help and are now collaborators so I think this one is well
covered for now.

  • svd2rust

Tool used to transform CMSIS SVD files (XML files that describe the hardware registers of a
device) into code for low level manipulation of hardware registers. Although the SVD spec was
created by ARM svd2rust is being used for both ARM Cortex-M and MSP430 devices. In the later case
TI provides DSLite files (their version of SVD files) and those are converted to SVD files using the
dslite2svd tool.

It's expected that svd2rust will also grow AVR support -- Atmel has its own description file
format: atdf -- using the atdf2svd approach. And there are XSVD (JSON version of SVD files) files
for RISCV -- I don't think they are official though? -- so svd2rust could also grow support for
RISCV via a xsvd2svd tool.

Unfortunately svd2rust has grown into an unmaintainable mess. The test suite takes a lot of time
to run (it takes longer than the CI limit) and it only checks if the generated code still compiles
-- it provides no feedback about whether the generated code exposes a certain interface or not. The
underlying parser lacks error handling and simply panics on errors. Also, svd2rust doesn't give
you helpful error messages when your SVD file has some problem -- this is an important feature to
have when manually editing SVD files.

So both svd2rust and the underlying svd parser need to be refactor (read: rewritten) to make
them more modular and testable. I think the approach to take here is a refactor like the one
proposed in rust-embedded/svd#37. Basically we should be able to test code generation on parts of a SVD
file. For example that <enumeratedValues>..</enumeratedValues> produces this enum Foo { .. }
and this API impl Foo { fn is_variant(&self) -> bool { .. } }, etc. This will let us write unit
tests that can replace the huge existing tests that only check for compilation errors. And while you
are at it you can add error handling to the parser and nice error messages to svd2rust.

This is a huge task but it will make it easier to continue the development of svd2rust. There a
bunch of open issues related to SVD files not being supported; the refactor should make it easier to
fix those issues.

If you want to tackle this let me know in the comments!


Then we have core cortex-m crates.

This repo provides access to Cortex-M specific features like access to registers, safe wrappers around
assembly instructions and access to core peripherals.

One old issue in this repo is providing a svd2rust generated API to access the core peripherals.
The current API has been manually written and is not as type safe as a svd2rust one would be.
Fixing this requires writing or putting together an SVD file that contains only core peripherals,
running svd2rust over it and committing the code to the cortex-m repo.

This crate takes care of communicating the memory layout of a program to the linker and providing
implementations of language items that are required to build a no_std program.

There are a few missing features in this crate: support for placing functions / interrupt handlers /
the whole program in RAM, relocation of the vector table, etc. that need a design. It may be useful
to coordinate with the representatives of the other embedded targets to see if we can provide a
similar user interface for these features.

This crate is used as a Cargo project template for writing Cortex-M applications.

Every now and then a user figures a new way to misfollow the instructions and encounters a new error
message. These errors should be documented in the troubleshooting guide.


Regarding organization I think it may make sense to move these core components under the
rust-embedded org and then create, say, a cortex-m team in charge of maintaining the cortex-m
crates. As the AVR, MSP430 and RISCV communities grow they may also want to move core components
into the rust-embedded org and create their own maintainer teams. Thoughts on this?

cc @ryankurte @Emilgardis might be interested in picking up svd2rust development
cc @dylanmckay (AVR) @pftbest (MSP430) @dvc94ch (RISCV) see last paragraph, also svd2rust support

Test embedded targets in rust-lang/rust CI

Triage

2018-07-02

The extending Rust reach participants mentored by @jamesmunns are working on this. Among their
goals they have:

  • Adding "it compiles" tests. libcore, or some other crate, compiles for $TARGET
  • Adding "it links" tests. A minimal embedded program links with different compiler options
    (opt-level, LTO, incremental, etc.) and the presence of some symbols is checked (e.g. main).
  • Adding "it runs" tests. A embedded program is executed in QEMU and completes successfully.
  • Adding binary size regression tests. The binary size of a program, compiled with opt-level=s, is
    tracked over time (per PR) and the CI fails if the binary size of the program regresses.

In their next meeting they'll discuss which of these goals are must have for edition and which ones
are stretch goals, and a potential timeline.


Last year, compilation of the core crate broke for MSP430 / thumbv6m-none-eabi twice due to some changes to libcore source code. That problem could have been avoided if the core crate was compiled for thumbv6m-none-eabi / msp430 as part of rust-lang/rust test suite. Last year there was also quite some breakage in the embedded ecosystem due to the compiler work on incremental compilation and parallel codegen.

We should try to get rust-lang/rust test suite to include tests for embedded target. At the very least core should be compiled for embedded targets.

TODO

  • @japaric will ask the Rust team what kind of embedded targets tests would be possible to add to the rust-lang/rust test suite. We got an "OK, this is possible" from the infra team during the Rust All Hands meeting.

Programs linked to `std` are too big

The biggest problem at the lower spectrum of this sub-ecosystem is binary size. Rust programs tend
to be very big in size compared to the common storage sizes (a few MBs) of these devices.

Possible solutions are:

Dynamic linking

Currently, Rust doesn't have a stable ABI/metadata so it may change from version to version or even
between nightlies. Still, it is possible to use dynamic linking to get a very small executable but
the dynamic libraries (dylibs) are still rather big (due to metadata?).

Top down approach: strip down the binaries

Quite a few things can be done to the reduce the binary size of general Rust programs. This blog
post
does an excellent of covering them.

The results look encouraging in the "Hello world" example: from 600K to 8K but these results "don't
scale" to more complex programs. For instance, a program that depends on clap are still around 1 MB
in size, even with all these tricks.

Bottom up approach: Bring your own standard library

lrs is a re-implementation of Rust standard library that claims to produce very small binaries
with fast compile times but only supports Linux (all OpenWRT devices run Linux though). Sadly, it
appears to no longer be maintained, doesn't support MIPS and it's not compatible with the crates on
crates.io because lrs API is different from std's so we can't tell if complex program result in
significantly smaller binaries if lrs is used instead of std.

USB stack

This issue is for gathering resources on writing USB firmware in Rust and for tracking progress on building a generic USB stack in Rust.

This is basically a place where people working on USB firmware can post about the progress they have made, exchange notes, etc.

People that have been doing USB stuff (that I know of):

Embedded testing

There are quite a few ways to do testing in embedded development. This blog post by @jamesmunns
does a great job at describing the different approaches.

Right now Rust only provides testing support for std targets via the built-in #[test] attribute
and it's quite inflexible at supporting any other kind of testing framework. I tried and ended up
creating utest a no_std test runner that runs unit tests sequentially but it's a hack: the
test runner breaks down if any unit test panics so you can't use the standard assert! macros;
instead you have to use the macros that utest provides.

All this is going to change soon with the arrival of Custom Test Frameworks (CTF) -- see eRFC
rust-lang/rfcs#2318. With CTF you'll be able to annotate test functions with custom attributes and
perform a proc macro style transformation of the annotated items to generate a test runner program.

For example, a CTF could provide the following user interface:

// Err = test failed
#[my_test_attribute]
fn my_unit_test() -> Result<(), ()> {
    try_stuff()?;
    try_other_stuff()
}

#[my_test_attribute]
fn another_unit_test() -> Result<i32, ()> {
    Ok(0)
}

And the whole crate procedural macro would generate the following test runner:

#[no_std]

extern crate some_dep;

fn main() {
    if my_unit_test().is_err() {
        // report error
    }

    if another_unit_test().is_err() {
        // report error
    }
}

fn my_unit_test() -> Result<(), ()> {
    try_stuff()?;
    try_other_stuff()
}

fn another_unit_test() -> Result<i32, ()> {
    Ok(0)
}

This opens the door to HIL test frameworks and more featureful no_std testing frameworks in general.

โ€œNativeโ€ Host Testing

One route to testing embedded-hal drivers is to mock a implementation of the HAL (embedded-hal)
for x86_64 (or w/e the architecture of the build machine happens to be) and then test the drivers
against the mock implementation on the build machine.

I don't know if there's any sort of standard or best practice when it comes to mocking embedded I/O
interfaces but, the other day, @idubrov showed a text based mock implementation of digital I/O
that they used to test a LCD interface.

What other alternatives to mocking exist here?

HIL Testing

My understanding is that HIL testing involves (at least) two programs. One that contains the test
suite and will run on the target device, and one that runs on some host machine that communicates
with the target device and reports the results of running the test suite.

The target program can be generated using CTF from the crate under test while the host program can
probably be just some Cargo subcommand / external tool. There's an interesting use case here where
the target program may not fit in the target device memory if it contains all the unit tests; in
this scenario it would be necessary to split the test suite in several target programs. It's unclear
how to handle this with CTF; perhaps one should simply write the test suite as several files in the
examples directory -- each file is a crate that will translate into an independent target program.

Are there standards / best practices that we could use here? Should we use the Test Anything
Protocol
(TAP) for the device - host communication?

cc @nagisa @thejpster @jcsoo you probably all have thoughts on this topic

Embedded development on stable

Triage(2018-07-15): This is only waiting on #[panic_implementation] being stabilized. Proposal for FCP.


Development of no_std applications is relegated to the nightly channel because it requires opting
into several unstable features. This makes Rust hard to sell to C developers; they'd rather stick to
their stable vendor provided toolchains instead of having to deal with constant breakage /
regressions.

It may not be possible to stabilize all the features needed for application development this year,
but the following unstable features are widely used in library development and it might be possible
to stabilize them this year:

  • Xargo. rust-std components for embedded targets.

Once those are in place you'll be able to use Cargo as you normally would by first doing rustup target add thumbv7m-none-eabi.

Tracking issue rust-lang/rust#49382

Xargo requires the nightly channel to build the core crate / std facade. Having that functionality
in stable Cargo would make Xargo unnecessary.

The Cargo team said they'll work on this this year.

I wrote how to land the functionality in Cargo.

  • asm! We'll RFC "Stable assembly operations" instead of stabilizing asm!. See #63 for details

A pre-rfc on this topic is being discussed.

Upstream tracking issue rust-lang/rust#29722

The old const evaluator is going to be replaced with miri (cf. rust-lang/rust#46882). This fixes a
bunch of bugs and removes several restrictions the old const eval had. It's more likely this feature
will be stabilized once miri is in place.

Upstream tracking issue rust-lang/rust#24111


  • panic_fmt #[panic_implementation]

If we want to support the use case of linking a Rust library into a C program then setting a
no_std panic handler must be possible on stable.

An RFC on this topic has been accepted (tracking issue rust-lang/rust#44489) and part of the
implementation has landed in rust-lang/rust#47687


If we want to be able to build pure Rust no-std applications then a lot of other unstable features
are needed. It's unclear whether we can stabilize any of them this year.

  • compiler_builtins_lib #![no_std] expansion will include a stable extern crate compiler_builtins so you won't require opting into the compiler_builtins_lib feature gate

A PR implementing this has been submitted: rust-lang/rust#49503

Ideally these builtins should be shipped with core and it shouldn't be necessary to explicitly link
to the compiler-builtins crate.

  • start and termination lang items Can be worked around using unmangled symbols at the cost of not supporting the standard main interface. See stable-embedded-rust for an example.

These are required to support the standard main function interface.

  • linkage(weak) Can be worked around by using PROVIDE in a linker script. See stable-embedded-rust for an example.

Used to define a weak interrupt table with a default catch all handler while still allowing the user
to override any handler in the table.

  • global_asm! Weak aliases can be implemented using PROVIDE in a linker script. See stable-embedded-rust for an example.

Used to implement weak aliases; a feature which is not supported in the language.

  • #[used]

Used to force the compiler to preserve some "unused" symbols that are required at link time (like
the interrupt table).

Tracking issue: rust-lang/rust#40289

RFC for stabilization: rust-lang/rfcs#2386


There's other aspect to stability here and that's the lack of CI testing for no-std targets in
rust-lang/rust. The consequence of this is that changes unrelated to unstable features can break
these targets. This happened twice last year: changes in the core crate related to atomics broke
the thumbv6m-none-eabi target.

This issue can be addressed by having no-std targets being tested as part of CI testing. As we don't
want to block rust-lang/rust development on codegen / LLVM bugs it should be possible to easily
disable testing on these no-std targets; a mechanism for this is already in place for tooling like
clippy and miri. Here we should define how much testing we want to do: just building core (simpler),
or also testing that linking no-std applications works (more involved as it requires several
unstable features).

#52 tracks testing embedded targets in rust-lang/rust CI.

cc @pftbest

Fix linking issues when using multiple codegen units

To improve build times rustc is now defaulting to building crates using multiple codegen units. The
problem is that using multiple codegen units can sometimes break linking of no-std applications
("undefined reference to rust_begin_unwind").

We are looking for someone who can help us fix the problem in the compiler

Tasks

The current workaround for this issue is to force the compiler to use a single codegen unit in
Cargo.toml

# workaround rust-lang/rust#47074
[profile.dev]
codegen-units = 1
incremental = false

The weekly driver initiative

There's now a HAL published on crates.io: embedded-hal (Introduction blog post). ๐ŸŽ‰

To put it to test and to expand the crates.io ecosystem I'm starting the weekly driver initiative.

The goal is to release a new no_std, generic, embedded-hal based driver crate every one or two
weeks. Driver crate here means a library crate that lets you interface an external component like a
digital sensor or a wireless transceiver. A driver release consists of (a) publishing a library
crate on crates.io (*) and (b) presenting your driver to the community via any means: a blog post,
a tweet, a reddit post, a u.r-l.o https://users.rust-lang.org post, etc.

(*) Make sure you tag your crate with the embedded-hal-driver keyword!

If you'd like to participate leave a comment here stating the driver you'll be working on. If you
can post a link to the repo where the (WIP) driver code is or will be, even better! If you don't
have a personal blog to present your driver to the community you can do a guest post on my blog.

For a list of released and WIP drivers check the awesome-embedded-rust list. If you'd like your crate to be added to that list simply send a PR to that repo!

TODO (potentially):

These are components that @japaric has at hand:

  • DHT22 - temperature + humidity sensor (1-wire)
  • ENC28J60 - ethernet controller (SPI)
  • HC-06 - bluetooth (AT)
  • HC-12 - wireless transceiver (AT)
  • HC-SR04 - ultrasonic sensor
  • L298N - Motor driver
  • NEO-6M - GPS (USART)
  • NEO-M8N - GPS (USART)
  • PCA9685 - 16 channel Servo driver (I2C)
  • PCF8574 (+ 16x2 LCD) - 8-bit I/O expander (I2C)
  • PN532 - NFC (SPI)
  • RA-02 - Long-range Radio (SPI)
  • SN65HVD230 - CAN
  • SSD1306 - 128x64 OLED (I2C)
  • Servomotor (?)
  • WS2812B - smart LED
  • nRF24L01 - wireless transceiver (SPI)

Survey: Crates / libraries / tools you need / want

Let's try to find out what libraries the embedded ecosystem lacks with a survey!

Please request one library / tool per comment. You can comment several times though. I suggest sticking to the guidelines below but feel free to ignore some of them if you think it makes sense to do so:

  • Microcontroller and development board specific crates are out of scope for this survey. The requested crate must be general enough so that it can be useful to a non-trivial fraction of the embedded Rust community.

"I want a crate to program the e.g. STM32F4DISCOVERY development board" is out scope, otherwise we'd get a very long list of similar requests.

  • Check the issue #12 first.

You may be asking for something that already exists! If a crate an crates.io or GitHub doesn't work for you, please tell us why that's the case.

  • Please be as specific as possible and elaborate on your use case.

Don't just say "an Arduino-like framework that supports my microcontroller", which BTW would be out of scope because of point 1. That's too vague. Instead say "I need a low latency mechanism to send data from an interrupt handler to the main loop without disabling interrupts because I do $HARD_REALTIME_STUFF".

  • If someone has already posted here a library that you also need then upvote their answer so we can get an idea of how much demand there is for such library / functionality.

  • Bonus points if you can point to an existing C library that solves your problem. That way we can inform ourselves about prior art.

MSP430, unrecognized character `@' in symbol names.

So I tried to compile core and I get this errors from assembler:

core.s: Assembler messages:
core.s:9468: Error: junk at end of line, first unrecognized character is `@'
core.s:9740: Error: junk at end of line, first unrecognized character is `@'
...

the code on line 9468 looks like this:

_ZN4core3num7dec2flt5rawfp10prev_float14_MSG_FILE_LINE17h5bcd06a3b0d78233E:
    .short  str.3@
    .short  27
    .short  str.1v

I tried both msp430-gcc (4.6.3) and msp430-elf-gcc (5.3.0) and both give the same errors. Then I've renamed symbol str.3@ to str.3_at in assembly and it compiled successfully. I think msp430 assembler just does not like @ character in symbol names. So I see 2 options:

  1. Modify MSP430 target in LLVM so it will rename symbols with @
  2. Modify generate_local_symbol_name to not emit @ on MSP430

Addressing ergonomics around Rust and embedded/no_std development

This issue is a place to track broadening the Rust embedded ecosystem by tracking various papercuts that will hit users, especially new ones (both to embedded and Rust), when they start to dive it. Rust has been good at attracting new users and many don't come with a systems background. The broad availability of SBCs and microcontrollers that Rust can target and can be used for cool hobbyist or IoT projects will likely pull in many new users to the embedded development side of Rust. We should coddle these users into full-fledged embedded devs and increase our numbers!

Anyways, on to the list:

  • The current convention for crates that have both a no_std version with less functionality and a std version is to have a feature and enable it by default. We should decide on a consistent name and get this written up as a convention somewhere for devs to reference (tracked here). Once that's finished we could also scan crates.io for crates that use other names and file tickets against them to encourage the ecosystem to standardize [NO TRACKING ISSUES]
  • Crates that are compiled (using std by default) do not have core available to them and have to explicitly import them via extern crate core. Additionally, when compiling as no_std, this then results in a compilation error. This combination increases the friction for a user trying to use just core instead of std where possible. I suggest that core be automatically included for all projects (except if #![no_core] is specified). [NO TRACKING ISSUES]
  • Users will default to using the std version of something because of how the docs are arranged. Knowing about core and caring about no_std use is almost always not a primary thought of the crate developer. Convincing them to support no_std is now more onerous as they have to go in and adjust all the use paths to core. This is especially problematic given the point above. It would be great if this could be ameliorated by #![no_std] automatically mapping those std paths to core. A partial solution could be injecting use core as std. [NO TRACKING ISSUES]
  • For no_std crates, including hybrid dependencies (mixed std/no_std) doesn't expose only the no_std functionality by default. As discussed in Point 1 here many imports then look like byteorder = { version = "1", default-features = false }. So for users coming from std, there's extra work even declaring crate dependencies. [NO TRACKING ISSUES]
  • Core is missing functionality that would be appropriate to expose in core (not involve allocations or os-specific functionality). Right now that's things like signum(), sqrt(), and the like. It's a big surprise to users that they can't use sqrt() without the standard library! Other proposed functionality is OsStr and PathBuf and some of the UTF-16 processing, though for the first two it's a little unclear how those might be implemented. There are likely others and an audit of std would likely be enlightening. [tracking issue 1, tracking issue 2]
  • Some crates don't expose no_std even if they could. ref_slice is one such example where the author wasn't aware til an issue was posted. There's likely some work here that can be done to alert crate authors, though the most appropriate time seems to be when publishing to crates.io or when using clippy [tracking issue]
  • There's no way to enforce saying that a crate should not be compiled with std. no_std just specifies that the crate code doesn't need it, but std could still be pulled in by a dependency. This combos with Point 4 to make it the default that a user could try to implement a no_std crate and ship it only to have downstream users complain that it's not no_std because he forgot to include a dependency properly. There should be some sort of compilation check for this (it's part of The Rust Way(TM)). Maybe a clippy lint here would be a good place to start. [NO TRACKING ISSUES]
  • There isn't much in the way of Best Practices for embedded with Rust. This org is working to change that along with @brson's rust-api-guidelines repo, but having resources explicitly talking about this would be helpful. I've proposed a cargo checklist command that could be helpful here for new crate authors (tracking issue).
  • Users aren't aware of useful crates for no_std. This is a combination of exposure and the niche of no_std developers. Increasing users' exposure to no_std crates so they a) know they're available and b) think about making their crates suport no_std could be a good way to start here. I've suggested a badge on crates.io for no_std-compatible crates] to compliment the no_std keyword and no_std categories that are already there. Everyone loves badges!
  • cargo test by default doesn't expose std for no_std crates. This makes it harder to debug and work with tests for users used to doing println!(). I believe std should still be exposed within the test code itself, but it might also be worth compiling the crate as std so that these debugging statements can be inserted. This should only apply to the crate itself and not upstream dependencies. [NO TRACKING ISSUES].

Question: Hardware designed to run rust (bikeshed)

GPIO peripheral registers have the structure register{pin0: bool, pin1: bool ...}. If one where designing a GPIO IP with rust in mind, would one prefer reg_pin0 {input_en: bool, ...}?

The reason why I'd think it's a good idea is because pins could be owned by device drivers. Downside may be requires more gates because of unused bits. What are your opinions?

Guide for doing embedded development in an IDE

We have instructions for doing embedded development from the command line but we are missing
instructions for doing embedded development in an IDE.

I heard that VS Code plus the cortex-debug extension works nicely for embedded development but I
have no first hand experience.

We are looking for someone who can help us write down some instructions.

Tasks

  • Write instructions for setting up a Cargo project in VS code including instructions for
    setting up the cortex-m extension, Xargo and the RLS. It could be any other IDE but VS code is the
    IDE with official RLS support.

  • Bonus points if you write instructions for getting semihosting, ITM / SWO, register (SVD) view
    to work.

  • Identify any changes that we could make to cortex-m-quickstart to make integration with VS
    Code, or any other IDE, easier. Like checking in some configuration file (?).

Panic handler binary size bloat

There are two issues here. The first one I consider a (compiler) bug and the second one a missing
feature.

Panic strings kept in the binary

Even when panic_fmt (the panic handler) is defined to simply abort the compiler still produces
machine code that passes the (unused) arguments (panic message, file name, line number and column
number) to that function at runtime. This causes the arguments to be stored in the program which
takes up a sizable amount of non volatile memory (.rodata).

Here's @nagisa's description of the issue.

@nagisa was looking into this and they may have found the root of the problem. They'll open an issue
in the rust-lang/rust repo with more details.
Here's @nagisa proposed solution.

This is also a problem on WASM land; see rust-lang-nursery/rust-wasm#19. If this can't be fixed in
the compiler then this RFC (rust-lang/rfcs#2305) for optionally removing the arguments of
panic_fmt could be a solution.

Reduce footprint of panic messages

When panic_fmt is defined to print / log panic messages complete strings are stored in the binary.
This takes up precious space in non volatile memory (.rodata).

It would be great to be able to store the strings, along with file position data, in a table in
debuginfo, which is not flashed into the device, and store only the address to each table entry
in the binary. A external tool would be required to turn that address back into a panic location.

A related RFC has been proposed: rust-lang/rfcs#2154

cc @cr1901 @pftbest

Multitasking models

(Originally this was issue #45 but that turned into an RTOS only discussion)

Unlike Linux / Windows / *BSD / etc. targets where the OS provides threading support,
there exist no standard way to do multitasking on embedded targets. This means that we
either have to implement a multitasking mechanism ourselves or bind to a C implementation.
There are few different ways to do multitasking:

Preemptive multitasking with support for task prioritization. Hardware scheduler with zero software
(bookkeeping) overhead. Dead lock free execution plus all the memory safety that Rust grants.

@japaric is working on / maintaining the Cortex-M port.

  • Tokio-like cooperative event loop.

Basically, cooperative multitasking that avoids the "all wakeups must poll all events" problem.

There's an implementation for the STM32F4 here but I haven't look at it in detail. I think
that whatever implementation we end up adopting should meet these requirements:

  • Should integrate with the device sleep functionality.
  • It should be easy to use it with embedded-hal drivers.
  • It should not require dynamic memory allocation, or features that require memory allocation should
    be opt-in.
  • It should be possible to integrate this event loop with preemptive multitasking models like RTFM
    and the thread model.

@japaric is looking into a Cortex-M implementation of this and will write about his findings in a
blog post.

  • (RTOS) Threads. Discuss this in #45

A lot of embedded programmers are used to thread programming so this multitasking model should be
well supported. Here we have the choice to implement threading support in Rust or to bind an
existing RTOS / C implementation.

If we go the Rust route I think Chromium OS Embedded Controller implementation (MIT license)
could be used as a reference.

If we go the C route perhaps we could bind Amazon's FreeRTOS. I think that at some point I saw
some FreeRTOS bindings but that was before Amazon bought it.

Maybe thejpster can recommend some RTOS to bind? See #45

@japaric won't work on this due to conflict of interests (he's already working on RTFM)


Ideally, all these models should have ports for the all the embedded targets. Also, the
embedded-hal drivers should play nicely will all these multitasking models (without
duplicating a bunch of code).

Define minimal Traits for common embedded peripherals

Peripherals are often used in a similar style (or a few styles), with an uncountable number of details of difference between implementations.

In order to have Arduino-level usability and portability, it would be useful to define a minimal set of traits that can be used to write libraries against. When more constraints are necessary, these traits can be composed together.

For example, a baseline trait may look like this:

trait Serial {
  fn read(&self) -> Option<u8>;
  fn write(&self, u8) -> Result<(), ()>;
}

When necessary to constrain, the following pattern can be used.

struct FifoSerial {
// some fields omitted
}

impl Serial for FifoSerial {
  fn read(&mut self) -> Option<u8> {
    self.rd_fifo.pop()
  }

  fn write(&mut self, data: u8) -> Result<(), ()> {
    self.wr_fifo.push(data)
  }
}

// Marker trait used as a tag
impl Nonblocking for FifoSerial {};

fn forward<I: Serial, O: Serial+Nonblocking>(in: I, out: O) -> Result<(), ()> {
  // Take from a high priority port to a low priority, memory backed port
  if Some(b) = in.read() {
    try!(out.write(b));
  }
  Ok(())
}

I would like to define the behavior of at least the following peripherals:

  • GPIO (maybe pins, maybe ports, maybe both)
  • SPI
  • I2C
  • Serial
  • PWM (analogWrite)

Additionally, Arduino Language Reference and Arduino Libraries may be good references for a minimal amount of functionality to be useful.

Testing/CI/Release For Embedded Targets

Problem

Embedded targets typically do not target the same architectures that are readily available on CI services like Travis and developers machines, yet we would still like for CI to be able to build our software for alternative architectures and, ideally, run tests on that architecture.

As an example, let's consider another project I am a maintainer on, nix-rust/nix, which although not strictly focused on embedded is likely to be needed on many embedded systems (it is a dependency of mio and many other crates as it provides a set of safer APIs on top of libc which may not be present in std). For this project, we want to do the following:

  • Ensure the software builds correctly
  • Ensure the software built for passes all unit tests
  • (For Rust Applications) Generate working debug/release binaries

Matrixed with these additional things for each of the above:

  • With each major feature combination
  • On each supported target
  • On each support version of Rust

Project Case Studies

Currently, there are several projects that implement their own solutions to this problem (to varying degrees of success) and a few projects which exist to help aid developers who are seeking to build/test for several different platforms.

rust-lang/libc

The libc crate is built for and runs tests against a number of different targets including several which are not yet officially supported. The libc crate contains a CI Directory which provides an overview of the strategy it uses for doing cross-build/testing.

This boils down to the following (ignoring platforms like Windows/OSX that are not really relevant for embedded):

  • Triples are specified using the TARGET variable and the desired rust version is specified with the rust variable in the travis matrix. Linux is used for the host OS. E.g.
    - os: linux
      env: TARGET=arm-unknown-linux-gnueabihf
      rust: stable
    - os: linux
      env: TARGET=x86_64-unknown-openbsd QEMU=openbsd.qcow2
      rust: stable
      script: sh ci/run-docker.sh $TARGET
  • The ci/run-docker.sh script will do the following for $TARGET:
    • Runs docker build to create a docker image using the Dockerfile in ci/docker/$TARGET. E.g. https://github.com/rust-lang/libc/blob/master/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile. The docker images contain all non-rust dependencies that are required to build and test for $TARGET. Typically, this is gcc/libc (for the libc crate) and qemu-user.
    • Runs docker run to launch a new container from the previously built image and executes the run.sh script
    • With the run command, the rust sysroot (-v rustc --print sysroot:/rust:ro) is shared with the container at /rust
    • If the QEMU environment variable is specified, the QEMU image is fetched and and a bunch of rigamarole and setup is performed in order to set things up. Finally, QEMU is run and the output is parsed to determine success. The only emulated machine currently is x86_64.
    • QEMU- is automatically selected for specific targets (see https://github.com/rust-lang/libc/blob/master/ci/run.sh#L107) and QEMU is just used for running the libc-test binary (cross compilation of this binary for the target is done on the host.

Things work well, but there is a moderate amount of complexity. Effort that is done to improve testing for the libc crate do not directly help out other projects which might want the same enhancements.

Major contributors here have been @alexchrichton, @japaric, @semarie

nix-rust/nix

This nix-rust/nix crate is based off of the work done in libc in an earlier version and has diverged some since then. This work was originally done by yours truly.

  • Travis is used to perform testing for the various *nix platforms that are supported.
  • Cross target builds are specified as follows:
    - os: linux
      env: TARGET=aarch64-unknown-linux-gnu DOCKER_IMAGE=posborne/rust-cross:arm
      rust: 1.7.0
      sudo: true
    - os: linux
      env: TARGET=arm-unknown-linux-gnueabihf DOCKER_IMAGE=posborne/rust-cross:arm
      rust: 1.7.0
      sudo: true
    - os: linux
      env: TARGET=mips-unknown-linux-gnu DOCKER_IMAGE=posborne/rust-cross:mips
      rust: 1.7.0
      sudo: true
    - os: linux
  • At present, it is assumed that containers that will be used are published. No images are built as part of the travis build process itself
  • Rust and the sysroot for targets supported by the docker image are built into the target image itself rather than being mounted into the container as is the case with libc.
  • CI executes the run-docker.sh script which for cross-targets will in turn call run-docker.sh
  • This script will run (and pull) the specified docker container from dockerhub, executing the run.sh script in the container.
  • Cross compilation will be performed and, similar to libc, based on the Target we will either execute the tests directly or run them using QEMU.
  • Since nix has multiple test files (as will most projects other than libc), there are some hacks in order to attempt to figure out what those are so they can be run: https://github.com/nix-rust/nix/blob/master/ci/run.sh#L66

This work was done by @posborne based on libc.

japaric/smoke

I haven't looked at this one much but @japaric has some relevant experience. Appears to use some combination of Docker/QEMU for build/testing. Dockerfile appears to be monolithic.

Others?

Looking for feedback on other projects that are doing a non-trivial amount with doing cross-build/test within the Rust ecosystem. MCU targets would be appreciated in addition to the above projects which focus on targets with an OS.

Ecosystem Projects

rust-embedded/docker-rust-cross

The goal of this repository was to provide the Docker images (a common theme for this work) in order to perform cross-compilation and cross-test for non-host architectures. To date, I have not been diligent about keeping these images up-to-date with each Rust release.

The goal is to have a common repository of Docker images that can be reused across projects like libc/nix/others so each project doesn't need to go in the weeds on that front.

@posborne is the maintainer of this project.

japaric/rust-everywhere

Rust-everywhere seeks to make it easier to cross-compile crates for other targets and publish binaries. It does not appear to help out with running tests on foreign architectures, although this is something that is likely to be desirable for projects targeting other architectures.

Final Note

For many libraries that do not do FFI (especially libc/kernel FFI), the importance of actually running tests on the target architecture is probably not as strong. Within embedded, however, there seems to be a much greater chance that using APIs that may not already have nice interfaces is increased. As such, I feel this forum is still an appropriate place to discuss how we want to handle this problem moving forward.

Material for the revamped website

A revamped Rust website will be released with the Epoch 2018 in mid September. The four domain WG
will have a space in the website to showcase their accomplishments and make the case for Rust in
their domain.

Some ideas that were discussed in the first meeting.

Who's our audience?

  • Early adopters: students, hobbyists, researchers, startups

    • Not a lot of existing organizational momentum
    • Compatibility / portability isn't too important, as long as it works for them
    • No / little expectation of technical support
    • Free (as in beer) matters
    • Community matters, good chance they will join and contribute
  • Regular firmware developers

    • Expect a mostly polished environment
      • e.g. vendor SDKs / IDEs
    • Willing to pay $$$$ for technical support / SDK / IDE / tooling
      • Or free (as in beer) is not that important
    • Organizational momentum
      • Established development workflows / programming patterns
    • Important to be able to easily port code between processor lines or even families. Examples
      • STMF1xx to STMF3xx (need more CPU/RAM/Flash than initially thought)
      • STMF3xx to STMF1xx (need less than initially needed, cost optimization, dev board to product transition)
      • STMF1xx to KL2x (different peripherals/uC features needed, cost savings, etc)
    • Important to be able to reuse code across projects
    • Community may or may not be important, unlikely to contribute back though
  • Safety critical market: automotive, aviation, etc.

    • Requires certified tooling (compiler / language) which costs $$$$$$ to certify
    • Regulatory overhead
      • Must convince safety orgs that Rust is "fit for purpose", not just managers

There was consensus on focusing on the first group in the short term, on the second group in the
medium term and on the last group in the long term.

What do we want to highlight?

  • Tooling: Cargo, package manager; RLS, IDE support; debugging Just Works, etc.

  • Zero cost abstractions: we are competing against C, not against MicroPython, eLua, Espruino, etc.

  • Type system preventing memory safety / logic bugs

  • Reusable code: crates.io, embedded-hal drivers

  • One step / easy setup

  • Consistent development experience across different architectures cf. #44

What should we show on the website?

  • Hardware demos

  • Getting started guide that walks you through the development of an embedded application using an IDE

  • Cargo project templates

TODO

  • @japaric will ask the Rust team what kind of content can go on the website. Blog posts? videos? searchable crate catalogs? guides like tokio's?

RISCV Arch Support

Tracking issue for riscv support:

riscv-rust-toolchain

llvm and rustc

these are likely not going to get done for Epoch 2018 release:

  • llvm upstreaming (wip, asb is working on this)

  • rustc upstreaming (I don't need cabi support at the moment, and likely easier to get done once llvm upstream can build libcore)

  • port to riscv32-unknown-linux-gnu (waiting on better atomic support in llvm)

  • get compiler test suite to run on riscv backend (waiting on riscv32-unknown-linux-gnu port)


embedded rust

tasks for Epoch 2018:

  • svd2rust upstreaming (not much to do here, the missing svd features are supported in recent svd2rust, rust-embedded/svd2rust#185)
  • split hifive crate into e310-hal and hifive crates, update to latest embedded-hal
  • cross docker image for quick setup (related to #43 cross-rs/cross#131)

A richer tag system

#1 originally proposed using just three labels, Arduino, OpenWRT and RPi, to categorize issues. But @nastevens proposed using a richer tag system. Also check my comment about grouping tags in categories. The questions are:

  • Should we adopt a richer tag system for issues? Also for the list of curated crates? (I'm in favor of both). What about tags for documentation? (I prefer bigger categories like "micro-controller" over tags in this particular case)
  • Should we group our tags in categories like rust-lang/rust does? e.g. A-x86, A-avr, A-arm, etc. where A stands for Architecture.
  • What tags should we start with? We don't have to come up with all of them right now. But if we are going to use the categories system proposed above, we should try to come up with as many categories as early as possible, I think.
  • Extra idea of mine: Should we recommend a set of tags for crates on crates.io? Like: "if your crate only works for a specific architecture, use one of these tags: arm, avr, x86, etc.". Another; "if your crate doesn't use heap allocation then use the no-heap tag", etc.

svd2rust support for autogenerating ARM device drivers/memory maps

Rust should support the ability to autogenerate device drivers/memory maps from SVD files similar to the ARM CMSIS support or the AdaCore support for for Ada provided by svd2ada.

I know that @japaric started working on this in the japaric/svd repository, but I think in the long run this would go a long way to improving Rusts ability to compete in the ecosystem. The team at AdaCore has been doing some great work building out Ada support for embedded systems, while their model is a little more centralized than the more modular nature of the rust community, it would be interesting to be able to match their capabilities one day.

Provide real content at rust-embedded domains

We currently have three domains available to the rust-embedded org, but all of them simply redirect to landing pages:

There are a lot of possibilities for content that could go on that site:

  • List of useful crates for embedded dev (#12)
  • List of frequently asked questions about embedded dev with Rust (#13)
  • Getting started guides
  • News feeds, similar to the various "This Week In..." publications
  • Regular blogs or guest blogs
  • Lots more!

I'm opening this issue to track the work that will go into those sites, and to put out a call for help. If you're interested in helping flesh out these sites, please let me know!

Support more families of microcontrollers

The "Arduino" sub-ecosystem is probably the biggest as it contains several devices from different
architectures. Right now, Rust pretty much only supports, albeit not officially, microcontrollers
based on the ARM Cortex-M processor. This family is big but there are a lot of other widely used
architectures, to name a few:

  • AVR
  • PIC
  • MSP430
  • Xtensa (see ESP8266)

To ease adoption, eventually, most of these architectures should be officially supported by the
compiler. By "oficially", I mean that not only the Rust compiler should be able to generate programs
for the target but there should also be some minimal testing of the target in the rust-lang/rust
repo.

Here's the current state of Rust support for all the architectures listed above (as of 2016-09-28):

(Note that, because rustc is LLVM based, adding support for any of these architectures depends on
LLVM also supporting the architecture.)

  • ARM Cortex-M. Fully supported but not built into rustc. Can be used as a "custom" target by
    creating a JSON file that describes (specifies) the target.
  • AVR. The avr-llvm fork supports this architecture. This fork is in the process of being
    merged back into upstream LLVM.
  • PIC. Some (all?) 32-bit PIC micros are based on the MIPS32 M4K architecture so it may be
    possible to leverage existing LLVM support for the MIPS architecture to create targets for these.
    I think LLVM doesn't support the architecture of 8-bit and 16-bit variants though.
  • MSP430. There is a MSP430 backend in official LLVM. Success building a Rust program for MSP430
    was reported back in 2014 but I haven't seen anyone pushing for or requesting MSP430 support
    recently.
  • Xtensa. No LLVM support AFAIK.

Device family HALs in rust

Hey all,

Has anyone looked at / worked out how to build generic HALs / driver libraries that work across a family of cores instead of writing a peripheral implementation for each? IMO it is an important layer of abstraction to make embedded rust easier both to use and maintain, and I haven't seen it mentioned in any of the roadmaps so far or worked out how to achieve it yet.

As an example of what I am talking about, when using silicon labs cores in C we have the vendor provided emlib that includes <em_device.h>, through some macro wizardry that ends up being replaced with the processor headers, then each of the peripheral driver functions consumes / works on the types exposed in those headers. For an example, see em_gpio.h and em_gpio.c.

So we have one set of drivers to use (and maintain, though in this case by the vendor) that exploit the commonality between device families. This provides a useful abstract interface (ie. SPI mode, frequency rather than registers) and the correct peripherals are either loaded by default where there is one instance (eg. CMU) or injected into the driver where there are multiple (eg. SPI0, SPI1). Also, swapping between MCUs within a family is only a matter of changing the -DEFM32G210F128 argument on the command line and some pin/instance definitions.

The options I have come up with so far to support this in rust are:

  • macro-ing the device definition through the HAL package (somehow)
  • we could manually implement a set of traits for a given device family, and feed that into svd2rust to match and use them where appropriate.
  • we could teach svd2rust to extract common patterns from a set of input svds into traits for use in the HAL.
  • we could write the driver layer as a set of macros that assemble the right peripheral registers underneath based on a device config argument.
  • we could not worry, build support for single devices only, and duplicate code as required.

The first is imo the most achievable now, but because of the way rust2svd outputs files there is no common trait between a pair of the same peripherals, so I can't see how to abstract across both. The second is IMO the most elegant, in that the crate for a given device could include the family crate and use that to support the SVD output from rust2svd, and applications could then include the family crate and #cfg between device crates, though the HAL is going to need to do the same to handle different functions across devices. I guess that would end up looking something like (from the bottom up):

  1. Device definition helpers - #device, #family etc macros
  2. Family definition helpers - device and family listing, #efm32device, #efm32family macros
  3. HAL implementation - traits for families and devices and peripheral drivers using those to implement the embedded-hal traits discussed in #6 , #8 and #19
  4. Device implementation - rust2svd generated wrappers using HAL traits
  5. Application / drivers on top of this and abstract (except for configuration) from both the device and processor family.

However it's achieved it seems like there are going to be some interdependencies, but I would appreciate any feedback / thoughts / ideas on how to best solve it ^_^

`core::fmt` machinery optimized for size

This

// empty.rs
fn main() -> ! {
    loop {}
}

generates a .text section of 94 bytes

This

// print-no-fmt.rs
fn main() -> ! {
    iprintln!("The answer is ");

    loop {}
}

generates a .text section of 314 bytes

But this

// print-with-fmt.rs
fn main() -> ! {
    iprintln!("The answer is {}", 42u8);

    loop {}
}

generates a .text section of 2340 (!) bytes

Everything (including core) was compiled with opt-level=3 + LTO + panic=abort. FWIW, opt-levels s and z make little difference.

The question is: Can we improve binary sizes? (and run time?)

Steps To Reproduce

$ git clone --depth 1 https://github.com/japaric/f3
$ cd f3
$ xargo build --target thumbv7em-none-eabihf --no-default-features --example minimal --release

Then tweak examples/minimal.rs accordingly.

Observations

  • iprintln definition

  • write_str implementation

  • Looking at the disassembly of print-with-fmt.rs. It seems that the compiler is not inlining anything inside core::fmt. The probable cause is that the fmt::Write trait makes use of trait objects in its implementation.

Possible solutions

  • Reduce the number of panic!s and unwraps in the core::fmt implementation.

  • Create an alternative core::fmt implementation that uses generics instead of trait objects to incentivize inlining and better optimizations.

  • Create an alternative core::fmt implementation that provides less formatting options.

The last two solutions will require a new fmt::Write trait.

Meta

$ git rev-parse HEAD
2d28ca4e59f5971113d07992968bc9230357d08c

$ rustc -V
rustc 1.14.0-nightly (5665bdf3e 2016-11-02)

$ xargo -V
xargo 0.2.1 (700605d 2016-11-01)
cargo 0.13.0-nightly (717adc8 2016-11-02)

Tagging with the community label as this may require an out of tree re-implementation of the fmt::Write trait that could end up living in crates.io.

Support more OpenWRT devices

Currently, the Rust compiler supports MIPS OpenWRT devices via these targets:

  • mips(el)-unknown-linux-uclibc. OpenWRT 15.05. There is no binary release of std for this
    target though. Having binary releases for this target is at least blocked by rust-lang/libc#361
  • mips(el)-unknown-linux-musl. OpenWRT Trunk. As a Tier 3 (?) target.

OpenWRT not only supports MIPS devices but also ARM devices and other architectures. We should
investigate what's required to support those other targets.

For OpenWRT 15.05 ARM devices, we'll probably need an arm-unknown-linux-uclibc target.

OpenWRT Trunk for ARM seems more tricky. In theory, the arm-unknown-linux-musleabi target is the
right target but that produces statically linked binaries but users of these devices will probably
want dynamically linked binaries to keep binary sizes small. Hence something like
rust-lang/rfcs#1721 to support these devices.

Embedded Linux

Since it looks like we're breaking out topics from the Scope PR, here's a place to discuss the various classes of Linux devices and how they might be addressed in embedded-rust.

On one end there is uCLinux for devices without MMUs. I don't know how widely used this or any other similar projects are used, but it doesn't appear to be useful outside the embedded context.

On the other end there are all of the various traditional distros that happen to run on the Pi, BeagleBone and other single-board PCs.

In between are OpenWrt, Android and maybe ChromiumOS which are in between. There's also whatever Microsoft is offering for embedded Windows development - anyone know about that?

Finally I'd like to include Yocto and Buildroot which are tools that allow you to build customized Linux installations.

All of these are being used for embedded devices, but they don't necessarily need the same level of attention. The fuller featured Linux distributions really just need Rust libraries for Linux I/O support, and maybe intermediate ones like OpenWrt and Android just need the appropriate targets for cross compilation.

However Buildroot in particular seems like a prime target that could use some tooling on the Rust side. As motivation I'd like to point out the Nerves Project which is an Elixir (Erlang) toolset which makes it extremely easy to build flashable single-purpose Linux firmware.

Survey: Frequently Asked Questions

Let's start collecting questions for the FAQ!

What people usually ask about when they think/read/talk about Rust and embedded systems?

Post those questions here. It's OK if you post a question that seems similar or related to a question someone else already posted. I'll collect all the questions up here and then we can derive a smaller set of more general questions from this bigger pool.

Here's a good example from Reddit:

  • How is Zinc.rs going?
  • Is there an updated tutorial to deploy Rust into an Arduino and other small devices?
  • Is there already an 'Are We IoT Yet' website?
  • Where could I direct people that are interested to talk about IoT and Rust?

Another type of question I often hear is the one that involves the words Rust and Arduino:

Integration with C codebases

An approach that has worked well for the adoption of Rust in std land is to replace existing
components of a C codebase with Rust components (rather than the more radical rewrite everything in
Rust from scratch).

I think we are lacking guides for this important use case in embedded Rust land and we should fix
that. There are different aspects to integrating Rust into a existing C codebase:

  • Integrate Rust / Cargo into a C project build system.

The Rust team has been working on making this easier since last year but I don't know what's the
current status.

What build systems can we expect to encounter in practice? Makefiles, cmake? Do we have examples of
integrating Cargo with those?

  • Binding C code (FFI)

Some examples will probably come out of the work of binding RTOSes in #45. We should write a guide
(e.g. "how to use bindgen to bind C code that will be used in no_std context") once we have gained
experience.

  • Calling Rust from C applications.

Example use case: write your parser in Rust and call it from C.

Do we have any examples of this? Anyone tried rusty-cheddar in no_std context?

MSP430 support

Parent issue: #2

Next steps:

  • rustc: Enable the MSP430 LLVM backend, implement cabi stuff,
    etc. See rust-lang/rust#37672
  • Experiment with a custom target out of tree. Please document everything you do! You don't have to write a tutorial but take note of all the tools you use, the environment you used, the steps you did. Bonus points if you write down the outputs of running readelf -h and objdump -Cd on your (working) programs. LED blinking example
  • rustc: fix the LLVM assertion reported in rust-lang/rust#37829. It block us from compiling the core crate
  • rustc: unrecognized character `@' in symbol names. rust-lang/rust#38286. It's also blocking us from compiling core.
  • rustc: add a "msp430-interrupt" ABI to support interrupts as extern "msp430-interrupt" fn. (Done in rust-lang/rust#38465)
  • rustc: support the __bic_SR_register_on_exit gcc built-in somehow. Needed to enter/leave low-power mode.
  • Write documentation about writing/compiling/flashing/debugging Rust
    programs for this target. (See https://github.com/pftbest/rust_on_msp)
  • Add a built-in MSP430 target to rustc
  • ๐ŸŽ‰

Performance tracking tool for ARM Cortex-M microcontrollers

Update: 2019-01-20

See itm-tools


In my last blog post I talked about the Instrumentation Trace Macrocell (ITM)
peripheral as a mean to log data and/or debug messages from a microcontroller to
a PC or some other host. However the ITM can be used to trace many other things
like:

  • It can sample the Program Counter which can be mapped back to source code to
    produce flame graphs (where in the program is the processor spending most of
    its time?).

  • It can trace entries to and exits from exceptions and interrupts which you
    could use to count context switches and measure the time spent in interrupt
    context.

  • It can trace memory accesses to arbitrary (?) memory regions.

All this with timestamps accurate to the clock cycle.

I'm opening this issue to see if there are people interested in building a cross
platform Rust tool that can collect this performance information and present in
some way (text or graphs; it doesn't matter much how it's presented in the first
versions) as I'm not sure how much time I can put into this myself.

Here's more or less what needs to be done:

There are two aspects to this tool: the register manipulation necessary on
the device side, and the frame decoding and processing on the host side. So

  • First thing is to collect information about the ITM registers and the ITM
    frames related to the tracing functionality.

ARMv7-M Architecture Reference Manual (DDI 0403E.b) - Appendix D4 Debug
ITM and DWT Packet Protocol

CoreSight Components Technical Reference Manual (DDI 0314H) - Chapter 12
Instrumentation Trace Macrocell

  • Extend the ITM API on the cortex-m crate to deal with setting up the
    tracing stuff?
  • Extend the itm crate to handle parsing of ITM frames related to
    tracing.

See rust-embedded/itm#24

  • Build a basic tool that grabs the ITM frames from a device (e.g.
    /dev/ttyUSB0) or a file (itm.dump) and just prints the decoded frames to
    stdout. This both meant as a sanity check and to get an idea of the
    performance requirements of the tool (can it handle the data throughput?)

See itm-tools

  • Start adding functionality like context switch counting, interrupt time
    measurement, and flame graphs (or just % time spent vs PC address to begin
    with)

See itm-tools

  • Figure how to feed debug info into the tool to get flame graphs with
    proper line information (instead of just PC addresses). This sounds tricky to
    me as I know nothing about using debuginfo without a debugger.

  • ๐ŸŽ‰

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.