Programming ARM Cortex-M Microcontrollers with Rust
github.com
github.com
- svd2rust (https://docs.rs/svd2rust/) generates register-level APIs from SVD files, an XML format provided by most ARM microcontroller vendors. This gets you the equivalent of the low-level C header files for manipulating the hardware registers.
- cortex_m (https://docs.rs/cortex-m/), which provides APIs for the core ARM peripherals in every Cortex-M MCU.
- f3 (https://docs.rs/f3/) - High level APIs for the peripherals and external sensors on the STM32 F3 Discovery board.
It's a mess. A couple of languages like Rust, D, etc. can be hacked on micros due to their compiler suite, but it is always messy. Above guide uses inline assembly to blink a GPIO. Hardware access is on register level. None of this makes your live easier.
In order to be viable for microcontrollers you need two things: * a compiler or interpreter for your target * a Hardware API
There are some projects, like MicroPython and Espruino who realized the importance of the Hardware API. They basically transcend micro-interpreters and RTOS (especially given the languages asyncio features).
Microcontroller vendors ship C/C++ libraries for their hardware. You either have to wrap that, like the micro-interpreters do, or your language has to be able to use them natively.
What Rust on microcontrollers need is a Kickstarter campaign with a nice dev-board as perk to finance a project that implements a nice API for that specific micro.
In my experience most bundle their own compiler suite. Nothing like learning what parts of C++03 are/aren't implemented.
Especially in the RTOS space where most the time your program is just an object file being injected into the OS.
I only have experience with AVR and ARM (STM) to be honest.
0. https://github.com/jamesmunns/bluepill
1. https://gist.github.com/uxp/35c9d5d51b2229f5c4c2e5b11c3341e5
Also don't expect much. I'm a Mechanical Engineer and it was a bit out of my league, so it didn't go very deep.
The paper will hopefully soon be published: ISBN 978-3-8007-4395-7 "Evaluation of MicroPython as Application Layer Programming Language on CubeSats" in the "ARCS 2017 Conference Proceedings"
On the other hand, mcu companies make a significant amount of their profit based on lock-in(since mcu's are mostly commodities). And the higher level the API's and the rapid development is, the less lock-in companies get.
That together with the fact it costs a lot to develop quality libraries are the main reason to the state we're in today.
As for solutions:
1. ARM did face that problem once, with cores, and played it hand well , they came to mcu vendors and told them - the carrot: using our core will save you money on development(core/compilers/etc). The stick: a startup called luminary-micro , who could do cheap mcu's since all that was free.
- So can this move be played again, today, with peripherals ? maybe build a nice peripheral set, with libraries, well tested, etc - and offer it cheaply to the risc-v guys , and other mcu vendors, including Chinese mcu vendors ?
- Maybe the place to look for quality libraries is at mcu startups ? the last one was the acquired energy-micro , are their libraries better ?
2. The IOT is a big shift. Shifts create different leverage points sometime. Is there something that open-source community can do together to push the vendors towards great libraries in that niche , even if vendors don't like it much?
For example, what if the open-source community focused on one of the hardest building block of the IOT - security ? what if we created a highly proven security IP, proven by the community to a great extent, but used it licensing to push mcu vendors ?
Are there any other ideas how to solve this conflict ?
Rewiring and redesigning all electronics around a new MCU is just an insane undertaking. Irrelevant of API change in the software.
https://www.slideshare.net/MTKDMI/2013-embedded-market-study...
Many of the reasons we're regarding software, indicating that software lock-in is a significant factor.
[1]they called it microprocessors , but pages 54, 60 hint we're talking about mcu's.
It could be that the software is the thing they think first, if you ask the people writing it.
That's the major reason I stay away from embedded development.
No, the only inline ASM in this guide is to cause a debugger breakpoint. You also need inline ASM to enable/disable interrupts, and that's about it.
The code in this guide looks ugly because it's written to show how to use the hardware without any abstraction. Higher level APIs like f3 (https://docs.rs/f3/0.3.1/f3/) exist, though not nearly for every chip or peripheral. Even in C, for anything outside the popular Arduino/mbed/etc boards, your choice is usually between buggy vendor bloatware and using the registers directly after carefully reading the datasheet.
https://spin.atomicobject.com/2015/05/21/generate-embedded-r...
And even before the coding starts, defining good abstractions for complex peripherals is very difficult. Counter/timer modules are the poster child for that. Heck, if you look at the Micropyothon issues on github you will find pages of vigorous debate about GPIO pullup configuration, much less anything complex.
They also ship Basic, Pascal, Ada, Oberon and Java, here's a small selection for those curious about the offerings.
http://www.astrobe.com/default.htm
http://www.adacore.com/press/8-bit-avr-microcontroller/
I have a presentation under http://plamauer.space/presentation.html - hard to follow without moderation, but pros and cons are at the end.
Compared to these early rust attempts they've written a port of ArduPilot in ivory/tower called smaccmpilot (http://smaccmpilot.org/).
In one of the papers they even compare ivory with rust in terms of memory safety.
I'm now trying to port ODriveFirmware written in C (+CubeMX/CMSIS) to ivory and so far I'm pretty surprised how well it goes. I'm going to start documenting this process on a blog soon, if interested I've created a wiki page collecting resources about embedded programming in Haskell at https://wiki.base48.cz/EmbeddedHaskell
ex:
(this guy has done examples on a ton of boards!) https://github.com/fpiot
www.metasepi.org/doc/metasepi-icfp2015-arduino-ats.pdf
In addition to the HAL annoyances that turbinerneiter talked about, I wound up giving up this time because I could find no way to manipulate strings in a static buffer. In C I could just allocate two 17 byte strings statically and then `sprintf` to them, but there seems to be no equivalent in Rust.
I'd be curious to know what limitations others have run into when trying this and if I was just doing it wrong.
use std::io::Write;
static mut S1: [u8; 17] = [0; 17];
fn main() {
unsafe {
write!(&mut S1[..], "Hi: {}", 5).unwrap();
let s = std::str::from_utf8_unchecked(&S1[..5]);
println!("string: {}", s);
}
}This is unsafe specifically because of the mutable static; you can deal with that in a few different ways, but that wasn't the point of the example.
Sadly, the repository posted by the OP is not up to date. That's not to say it's wrong but just that doesn't contain recent developments. Also, this repository documents every single part of putting together a microcontroller project from scratch. Although interesting, this is not the fastest way to "Hello World". That's why I have put together a nicely packaged Cargo template [1] [2] to quickly start a new microcontroller project. This template works for any Cortex-M microcontroller and paired with the svd2rust code generator [3] you can easily get full device support (register level API) for any microcontroller for which the vendor has released a CMSIS-SVD file [4]. There's a database of such files in this repo. [5]
For some, directly working with registers may be too low level. In that case you can look at my Discovery book [6] which showcases a higher level API and several examples for the STM32F3DISCOVERY board. The API is documented here. [7]
What's missing from all this is a good concurrency history. (All the examples in the Discovery book are single task.) So, I have been working (not alone) on a multitasking framework that's suitable for real time systems and the focus has been minimizing overhead while guaranteeing memory safety. At this point, we have pretty much reached the goal and we are currently working on the ergonomics. I hope that we'll have something show Soon (TM).
I'm happy to answer questions about Rust on microcontrollers. I may take some time answer, though, as it's weekend :-).
P.S. I hope I got the formatting right. First time posting on HN.
P.P.S. Congratulations for reading the whole thing! As a reward, here's a robot [8] built with the framework I mentioned.
[1] https://github.com/japaric/cortex-m-template
[2] It seems that the Cargo template feature got removed recently (due to not having gone through a RFC process) but you can easily rollback your Rust installation to get an older Cargo that supports templates: `rustup default nightly-2017-04-01`
[3] https://docs.rs/svd2rust/0.5.1/svd2rust/
[4] http://www.keil.com/pack/doc/CMSIS/SVD/html/index.html
[5] https://github.com/posborne/cmsis-svd/tree/master/data
[6] https://japaric.github.io/discovery/
[7] https://docs.rs/f3/0.3.1/f3/
[8] https://mobile.twitter.com/japaricious/status/84569793557265...
http://www.st.com/en/evaluation-tools/stm32f0discovery.html
http://www.silabs.com/products/development-tools/mcu/32-bit/...
The STM32 board includes an STLink programmer which you can use via OpenOCD. The EFM32 board includes a J-Link programmer and the IDE comes with the JLink command line tools. You may be able to use it via OpenOCD too, but I haven't tried that.
I prefer the EFM32 peripheral library (efmlib) to what's available for the STM32, which is either the old clunky Standard Peripheral Library or some new thing that's closely tied to their awful IDE.
If you use the EFM32 and the JLink software you can log using RTT (https://www.segger.com/jlink-rtt-viewer.html), which is much faster than using semihosting, which is the most straightforward option with the STM32.
The STM32 board has the advantage that you can set it up as a programmer by removing a jumper, whereas to set the EFM32 board as a programmer you have to load the horrible IDE and click buttons.
It's generally fairly easy to compile code for these chips using the arm embedded gcc toolchain:
https://launchpad.net/gcc-arm-embedded
The only tricky part is finding (or writing) a suitable '.ld' file. You can usually find one by poking around the files included with the IDE or with the peripheral libraries. In principle you can just write it yourself, if you know enough about ARM architecture, but that's above my pay grade.
Anyway, take all the advice above with a pinch of salt -- I'm no expert on this stuff. But sometimes the perspective of a relative newbie can be useful too.
There are also other fully open options for STM32- libopencm3 (just HAL) or ChibiOS (an RTOS with HAL).
Fair enough. I'm sure the library itself isn't literally tied to the IDE, but it's not easy to find as a separate download, and there is little example code available online for the HAL library.
> libopencm3
It's a nice project, but I prefer to use vendor-supplied libs unless there's a good reason not to. Efmlib has a permissive license and seems pretty nice from my relatively limited experience of it.
>You can also use plain old make if that's what you prefer.
This is the thing. I really want to be able to easily set up a project just using GNU make and the regular arm gcc toolchain. I've found it easier to do that on the whole with the EFM32.
After this is done you'll get /dev/ttyACM0 and ACM1 for GDB interface and UART bridge. From GDB you can connect to it directly with 'target extended-remote /dev/ttyACM0' (no need for OpenOCD middleware).
https://wiki.base48.cz/STM32#Running_BMP_on_Discovery_boards
Genuine question, I've never used the ST-Link for more than flashing the image and some debugging, so what am I missing?
Also UART bridge is nice but this might be supported newer in ST-Link too. I haven't used STLink for a while - flashing all the stuff with blackmagic right away.
https://docs.micropython.org/en/latest/pyboard/reference/spe...
https://docs.micropython.org/en/latest/pyboard/reference/asm...