As of 2018-09-18 the Rust compiler supports cross compiling to these embedded
rustup target list):
thumbv7em-none-eabi, Cortex-M4 and Cortex-M7
thumbv7em-none-eabihf, Cortex-M4F and Cortex-M7F
armebv7r-none-eabi, big endian Cortex-R4 and Cortex-R5
armebv7r-none-eabihf, big endian Cortex-R4F and Cortex-R5F
armv7r-none-eabi, little endian Cortex-R4 and Cortex-R5
armv7r-none-eabihf, little endian Cortex-R4F and Cortex-R5F
riscv32imac-unknown-none-elf, RV32I base instruction set with M, A and C extensions
riscv32imc-unknown-none-elf, RV32I base instruction set with M, and C extensions
rustc also supports code generation for the MSP430 architecture (see
rustc --print target-list).
In general, ARM Cortex-M and ARM Linux have the most mature ecosystems whereas the ARM Cortex-R, MSP430 and RISCV ecosystems are in early stages or not as mature.
For specific device support check awesome-embedded-rust.
We can talk about support at different levels: does the compiler support my device? does the crate ecosystem support my device?
Let's start with compiler support. The compiler supports architectures or ISA (Instruction Set Architectures) rather than specific devices. Compiler support can be further divided in two levels: compilation target support and architecture support.
By compilation target support we mean that you can readily cross compile a crate
for a certain compilation target using Cargo. To keep the default installation
slim only the native compilation target is installed and other targets have to
be installed using the
rustup target subcommand. If
rustup target list lists
a compilation target that matches your device then Cargo supports cross
compiling to your device.
For example, let's say we want to know if
rustc supports cross compiling to
32-bit RISCV. We check
rustup target list
$ rustup default 1.29.0 $ rustup target list | grep -i riscv || echo not supported not supported $ rustup default nightly-2018-09-18 # this date is just an example $ rustc -V rustc 1.30.0-nightly (2224a42c3 2018-09-17) $ rustup target list | grep -i riscv || echo not supported riscv32imac-unknown-none-elf riscv32imc-unknown-none-elf
This indicates that 1.29 doesn't support 32-bit RISCV but that 1.30 will.
Once you have installed a compilation target using
rustup target add $T you'll
be able to cross compile crates to it using
cargo build --target $T.
$ rustup target add riscv32imac-unknown-none-elf $ cargo build --target riscv32imac-unknown-none-elf
If your device doesn't appear in
rustup target list that doesn't mean that
rustc doesn't support your device at all. It could still support code
generation for your device architecture.
rustc uses LLVM to generate machine
code; if the LLVM backend for your device architecture is enabled in
rustc can produce assembly and/or object files for that architecture.
The easiest way to list the architectures that LLVM supports is to run
cargo objdump -- -version where
cargo-objdump is one of
$ rustup default nightly-2018-09-18 # this date is just an example $ rustup component add llvm-tools-preview $ cargo install cargo-binutils $ cargo objdump -- -version LLVM (http://llvm.org/): LLVM version 8.0.0svn Optimized build. Default target: x86_64-unknown-linux-gnu Host CPU: skylake Registered Targets: aarch64 - AArch64 (little endian) aarch64_be - AArch64 (big endian) arm - ARM arm64 - ARM64 (little endian) armeb - ARM (big endian) hexagon - Hexagon mips - Mips mips64 - Mips64 [experimental] mips64el - Mips64el [experimental] mipsel - Mipsel msp430 - MSP430 [experimental] nvptx - NVIDIA PTX 32-bit nvptx64 - NVIDIA PTX 64-bit ppc32 - PowerPC 32 ppc64 - PowerPC 64 ppc64le - PowerPC 64 LE riscv32 - 32-bit RISC-V riscv64 - 64-bit RISC-V sparc - Sparc sparcel - Sparc LE sparcv9 - Sparc V9 systemz - SystemZ thumb - Thumb thumbeb - Thumb (big endian) wasm32 - WebAssembly 32-bit wasm64 - WebAssembly 64-bit x86 - 32-bit X86: Pentium-Pro and above x86-64 - 64-bit X86: EM64T and AMD64
If your device architecture is not there that means
rustc doesn't support your
device. It could be that LLVM doesn't support the architecture (e.g. Xtensa,
ESP8266's architecture) or that LLVM's support for the architecture is not
considered stable enough and has not been enabled in
rustc (e.g. AVR, the
architecture most commonly found in Arduino microcontrollers).
If your device architecture is there then that means that, in principle,
supports your device. However, an architecture like ARM can be very broad
covering several ISAs and extensions. Instead, you'll want to work with a
compilation target tailored to your device. Custom compilation targets are out
of scope for this document; you should refer to the embedonomicon for more
Crate ecosystem support can range from generic support for the architecture to device-specific support. We recommend that you search on crates.io for the architecture (e.g. ARM or Cortex-M), for the microcontroller vendor (e.g. STM32), for the target device (e.g. STM32F103) and the target development board (e.g. STM32F3DISCOVERY). We also suggest that you check the awesome-embedded-rust list and the crates maintained by the embedded Working Group.
As of 2020-07-24 the support for AVR have been merged into the nightly version of
the official Rust compiler,
rustc. See the RFC for merging the avr-rust fork.
As of 2020-08-24 the official Rust compiler,
rustc, relies on LLVM for
generating machine code. It's a requirement that LLVM supports an architecture
rustc to support it.
There is no support for the Xtensa architecture in LLVM proper. You may be able
to find several forks of LLVM with varying levels of support for the Xtensa
rustc will not be able to use any of those forks due to the
maintenance and infrastructure costs of developing
rustc against different
versions of LLVM.
rustc will support the Xtensa architecture when the official LLVM gains
support for the Xtensa architecture. As LLVM is a project independent of the
Rust project we can't give you any estimate on when that might happen. A list of
submitted patches can be found on this LLVM dashboard.
We sometimes get questions like this one: "My Rust program is 500 KB but my microcontroller only has 16 KB of Flash; how can I make it fit?".
The first thing to confirm is that correctly measuring the size of your program.
rustc produces ELF files for most embedded targets. ELF files have metadata
and contain debug information so measuring their size on disk with e.g.
will give you the wrong number.
$ # 500 KB? $ ls -hl target/thumbv7m-none-eabi/debug/app -rwxr-xr-x 2 japaric japaric 554K Sep 19 13:37 target/thumbv7m-none-eabi/debug/app
The correct way to measure the size of an embedded program is to use the
program or the
cargo size subcommand.
$ # ~ 2 KB of Flash $ cargo size --bin app -- -A Finished dev [unoptimized + debuginfo] target(s) in 0.01s app : section size addr .vector_table 1024 0x8000000 .text 776 0x8000400 .rodata 208 0x8000708 .data 0 0x20000000 .bss 0 0x20000000 .debug_str 145354 0x0 .debug_abbrev 11264 0x0 .debug_info 139259 0x0 .debug_macinfo 33 0x0 .debug_pubnames 40901 0x0 .debug_pubtypes 14326 0x0 .ARM.attributes 50 0x0 .debug_frame 21224 0x0 .debug_line 117666 0x0 .debug_ranges 63800 0x0 .comment 75 0x0 Total 555960
Of the standard sections,
.data will occupy Flash /
.data will occupy RAM;
.comments can be ignored as they won't be loaded into the target device
memory. For the other sections you'll have to check your dependencies' docs.
In this examples the program will occupy
2008 bytes of Flash.
Note that most (all?) runtime crates, like
cortex-m-rt, will check at link
time that the program fits in the target device memory. If it doesn't fit you'll
get a linker error and no output binary. So, provided that you correctly entered
the size of the memory regions of your device then if it links it should fit in
the target device!
If you are measuring size using the right method and your program is still too big then check out our section on optimizations.
TODO(resources team) add link to the optimizations section
It is quite common that by oversight the linker configuration is not suitable
for the target device. Indications for such a problem are loading errors in
(gdb) load Loading section .vector_table, size 0x400 lma 0x0 Loading section .text, size 0x2064 lma 0x400 Load failed
Please note the
lma which is the loading address and needs to match up with the
start address of the flash.
openocd will indicate such a problem:
... auto erase enabled Info : device id = 0x10036422 Info : flash size = 256kbytes Warn : no flash bank found for address 0 wrote 0 bytes from file target/thumbv7em-none-eabihf/debug/examples/hello in 0.001434s (0.000 KiB/s)
If you see such a message you will need to check your linker configuration, usually in
memory.x for the correct addresses (and ideally also sizes). Please also note that
after a change you will need to
cargo clean and rebuild to use the changed addresses.
If you're using
semihosting, switch to a different input / output mechanism.
An embedded MCU will typically stop working if exceptions (which is the MCUs way
of signalling special or abnormal events) occur which are not handled and cleared,
either by an exception handler or a connected debugger. The latter case is especially
interesting because there's a method of interacting with a connected computer
semihosting which will work iff a debugger is properly connected
and debugging software running and correctly set up. This method uses special
processor instructions (e.g. a service or breakpoint call) to alert the connected
system about input and/or output requests from the device. If no debugger is
available to handle such a situation, the system either wait indefinitely or
generate an even stronger exception which can only be cleared by a reset.
There're two common scenarios which cause such a lockup unintentionally:
panicin the program with the
panic-semihostingcrate in use, however the occurence of a
panicmeans that the program is defunct anyway
Please note that examples may make use of the
semihosting concept but this
should not be used in production setups due to the lack of connected debugger and
a host running appropriate debugging software. The use of a serial interface is
often a better choice. However if you just would like to see your example running
please make sure your setup is ready to deal with the