Rust actually gives me some hope that we might see better low-level code portability between some of these microcontrollers.
In theory I could develop a project on a beefy TI microcontroller using higher-level Rust primitives/libraries and port it over to the cheapest microcontroller I can find that still fits my I/O budget/speed/memory/timer constraints. All that without having to use a RTOS or having to drastically re-write interrupt/timer code to whatever system the new controller uses.
I really hope rust gains a foothold in the embedded market. We need these features badly. As uCs get more powerful (you can get 200mhz chips for a few dollars) with more RAM and complicated networked peripherals, it's a no-brainer to have these features available in a safe way. Currently if you have an application relying on dynamic memory usage, for instance, most developers will write their own simple memory management, usually in which you have an array that various things hold pointers to and get's freed all at once. All that just to spread some memory around, and concurrency is an even dirtier word than the heap...
You're not wrong, but this is sort of like saying that CPU's cost nothing, so just replace your i5 with 4 celerons.
Distributed programming is even harder than multi-threaded programming if you need tightly coupled communication. Imagine you need to read an ADC (think oscilloscope output if you're not familiar) at 1MB/s and also need to be analyzing the data while talking to other devices on various peripherals about what you've found. You'll have to use Direct Memory Access most likely so communicating that data stream over SPI to another microcontroller might not be the best idea unless you have a lot of extra RAM to buffer everything in.
Edit: and the real reason you don't want to do this is because the EEs and manufacturing engineers on your project will try to kill you. Two uCs means two codebases and two devices to program during production, plus extra testing, more complicated design, and more parts to place (uC, crystal, caps, etc)
All problems disappear with enough speed. Eventually the main loop is fast enough that you can poll.
If you're doing something truly cutting edge your competitors aren't better than you are so you can afford that second uC and more parts.
Most of engineering judgment is finding the point where the goal is ambitious enough to keep up with or pass the competition while conservative enough that it'll likely work, or at least you won't get sued.
In abstract this is true, but in real life, you get presented with a microcontroller and are told to make X happen in Y time. The current trend is where microcontrollers are becoming fast enough to essentially be bare-bones computers. Maybe they're so fast that you can poll a dozen sensors fast enough to respond to an event, but now clients want you need to drive a graphic display with all the system performance stats in real time and stream cat videos via UDP to it whenever the user gets bored.
Being able to squeeze the full potential out of these devices is getting harder and harder with current methods. Safe concurrency and memory management can allow developers to fully utilize their hardware without needing a grey beard to write some unreadable assembly that you later find out was just a plagiarized version of the Windows ME memory manager.
Never trust a sentence with the word "just" in it.
Duplicating the microcontroller on a project where people spend all afternoon arguing about 10 cents on the BOM is not a welcome idea. Also, the most eye-opening required course I took as an undergrad was reliability engineering. After you learn to do the reliability math, adding several solder joints to the product purely out of laziness looks profoundly stupid. Neither idea makes you look good to the old grey-beards on the other side of the table at the design review.
On the other hand building a system out of a lot of small processors tends to lead to very complex systems in the end, since the different parts almost always need to communicate at some point. In the end it doesn't buy you much since you end up having to write message passing systems and their associated handlers everywhere.
Good point :)
I probably should have stuck to picking on Java. Ada is a pretty good example of a language that handles real time use cases with concurrency and memory pools well. That said, it's fallen out of favor in "recent" years.
I've never heard of "real time Java" before—is it soft real-time, like Erlang; or hard real-time, like QNX? What are the concurrency primitives? (Threads? Actors?)
...to get a Wikipedia summary, standards body, a tutorial, and probably some products. It's more useful than Google usually is on some terms like this that might muddy up search results.
Those go through certification processes. It's been against the rules to use a GC even if it's hard-real-time. Here's an example where the author points out the real-time Java was designed for DO-178B (safety-critical aerospace) but it wasn't until DO-178C that they even considered allowing a GC:
The companies that develop reusable solutions for multiple markets tend to pick something easy to certify or sell to all of them. So, if Java wasn't allowed, they'd lean toward something else in their products targeting highest-assurance just to reduce costs. That's mostly been assembly, C and Ada that I've seen.
Meanwhile, we do have proof it can be done in things such as the Sandia Secure Processor that they'll use for some of highest-assurance applications. The first-pass silicon they got was also nice. The best articles by Wickstrom et al on SSP are paywalled in ACM and IEEE if you have access. If not, there's a link below on how they built it with brief description of it under "Score processor," another name.
"The Aegis Weapon System is the premier naval defense system and the sea-based element of the U.S. Ballistic Missile Defense System. Its precision SPY-1 radar and integrated command and control system guides the interceptor and uplinks target track information to the missile for terminal homing. Its ability to detect, track, and engage targets ranging from sea-skimming cruise missiles to ballistic missiles in space is proven."
Good enough for mission critical system, hypersonic rockets, combat system firing at me?
If not, I can provide other ones, better suited to your use cases.
It's called real-time, garbage collection. It occurs predictably on regular intervals before enough leaks happen to blow missiles up or whatever other tragedy. Aonix and some other vendors have had it for a long time now. Meanwhile, mainstream found out in the past, few years that Go could achieve "low-latency" garbage collection. The field can do more than many of them think given the countless person-years invested in so much GC research and product development. I can't even track all of the GC's especially once they started using genetic algorithms and such to automatically make them.
EDIT to add: It says "Ada" and "Rational." That's an Ada forum. That language has little protection for temporal safety in the 1990's. More than many but not at Rust level or full leak prevention.
I don't see anything about safety for dynamic, memory management in that link. It just talks about correctness. I'm specifically wanting affine types and ownership system that let SPARK go from static to dynamic.
I do like them splitting it into several levels, though. That worked under Orange Book for security.
My bad, slides are not available yet... There's a mention in there about some rust-like ownership proof mechanism in their roadmap. I thought about our last exchange on SPARK & rust when I saw this :-).
It seems they're adding a little bit of it for SPARK but not critical, dynamic part. I asked him at the end if they plan to go full, dynamic safety for full Ada if the SPARK experiment succeeds. Awaiting the reply.
Hey thanks for the pointer to this thread. Allowing pointers in SPARK would be incredible... Today SPARK is so interesting because it's not all-or-nothing. So some parts can be SPARK (with different levels of proof), others Ada, etc.
One of the main limitations of the tech is 'no pointers' in SPARK mode. There are some tricks to hide pointers (you may want to look up the SPARK deployment guide : http://www.adacore.com/knowledge/technical-papers/implementa... ) but it would allow so much more code to be SPARK-compatible. Even in the embedded space sometimes you need pointers and linked-lists and hashmaps (and the new formal containers don't do it for you)... Frama-C allows (and seems to work with) pointers, I don't know how Well.
For Ada you can already go a long way (memory safety and data races) with protected object (nice semantics, check performance), not null pointers, controlled-types... But we're far from Rust's borrow-checker and move semantics. The name Unchecked_Deallocation (to instantiate 'Free') says it all.
Well it all depends how 'hard' your real-time is. If you go with Atego/aonix, you can get down to almost-C-Ada-like latencies but be ready to change your java coding style. Sliced-time GC works OK until you put too much pressure on it (concatenating logging strings that you're not going to record or display... allocating tons of small objets for local uses... Programming in 'Classic' java...) and it can't clean up fast enough... In the end you code in a small and sad watered down subset of java... I mean : java is everything (almost, except for primitive types) on the heap ! Avoid java collections (use javolution or hppc-rt instead), avoid auto-boxing, no local allocation, no String concatenation, no Selector API ('select' in java nio...) because it allocates like mad... God help you if you need to stream some amount of data via TCP. And be prepared to spend some time to fine tune the GC. You also take a hit on performance and compilation time compared to hotspot (you need aot compilation for real-time, the java runtime seems not as optimised... Not as many man-decades of work on it).
All in all I'd rank it 'easier' than C in developer comfort and proficiency but frankly, if you don't do C, I'd just go directly to Ada...
I would just argue that un these domains 'Classical C' isn't used, given the constraints regarding language features, using stuff like MISRA-C and similar.
Fully agree with Ada comment, even better if using SPARK.
In any case, many military seem more focused on being easy to hire recruits that already know how to program than training them, hence the ramping up of Java adoption.
Well the argument seems to be that it's easier to hire 'experienced' java developers (hear: have 'java' on their resume...). But the people you get are for the most part either inexperienced (fresh out of school) or you have to break all their classic-java muscle memory. Not sure about the tradeoff here, when you compare training in Ada/SPARK.
You're right about Misra C. Even with Ada you'll end up banning dynamic memory allocation and some stack-exploding stuff, but you still have alternatives like storage pools ('looks-like-dynamic' memory allocation) and Controlled types, and at least you get a stack for structured data types and not just for primitive types...
Each of them is a company making serious money in embedded systems. A few do safety-critical. I'll let you wonder whether they were in their right mind for building Java apps and using Java runtimes that don't seem to fail in high-stakes circumstances.
Nice article. Some good insights, as well as beginner how-to steps.
The embedded industry has proven to be very resistant to innovations and modern code-writing practices. Some platforms I coded for didn't even support/allow C99 standard. C++ is gaining some foothold (mbed, for example). Developers don't feel the urge to catch on with times, like in other industries. And yet, now they are expected to write secure IoT systems.
Hopefully Rust can demonstrate its worth and convert key industry specialists who would blog about it. Personally, I'm still waiting for perfect opportunity to apply it on medium-sized project before I fully commit (secretly I'm still rooting for Nim).
I don't think that article is particularly outdated. The subsequent development of and cost drops for ARM Cortex-M processors has changed the scene a bit - but they had ARM V7 TDMI units then which were comparable.
But at no time has UML tooling been the driving factor behind the industry's adoption or lack of adoption of a language.
The problem with C++ and other high-level languages has always been that it's hard to see how much a line of code costs. Incrementing a pointer to an array in C has a transparent, short runtime, compared to moving to the next element in a C++ collection which may accidentally invoke a dizzying indecipherable mess of template objects, overloaded operators, and STL dependencies. Or in other languages, you may need a large operating system and runtime to be loaded.
High level languages do handy magic things for you under the hood. If your engine bay is measured in terabytes of storage, gigabytes of RAM, gigaflops of computational power, hundreds of watts of electrical power, and seconds of acceptable interaction time, those magic things that let programmers build useful features faster are nice.
But when you're trying to get guaranteed responses in microseconds from milliwatts of electrical power in a few kilobytes of RAM, you're likely going to be hand-picking everything under the hood. No magic allowed.
Embedded C++ has been a thing for a while. The bigger issue is that one of the major compiler vendors only provides pre-standard C++ with no namespace std. C++11 is a pipe dream if you can't switch to a modern compiler. Still good enough for C with classes.
I didn't glean that the author is implying UML influenced language choice, just that UML vendors tried to sell to C developers.
But to answer your question, C++ is gaining a larger foothold in embedded if anything. More and more libraries are written in C++, and it's becoming more supported in the various toolchains.
From a very recent hackaday article -
"Modern C++ allows us to write cleaner, more concise code, and make the code we write more reusable. The following are [...] new features of C++ that don’t add memory overhead, reduce speed, or increase size because they’re all handled by the compiler [...] after reading this you’ll be more aware of the newer features as we start to see them roll out in Arduino code."
And also, because I was poking around their github today, here is Flybrix's source code, a lego-drone startup writing C++ on a Kinetis K-20 microcontroller (100 MHz ARM Cortex-M4). They use the teensy bootloader, which is why you see a mix of Arduino and C++ files
"The embedded industry has proven to be very resistant to innovations and modern code-writing practices .... And yet, now they are expected to write secure IoT systems."
I second that. Conservative nature of embedded industry led to lots of investment into things like static analysis, WCET's, and automated testing of few languages or platforms they use. Embedded is one of few sectors that can benefit from most deliverables in high-assurance field as well since they structure their stuff simple enough for that vs piles of Linux, containers, bloated apps, etc. The innovation happens outside of the coding mostly. That's why the coding keeps the quality that engineers intended to put into it. :)
Hi There. A number of factors.
1) FreeRTOS is ineffective, in many cases you have to code around the kernel to get sufficiently good response times.
2) FreeRTOS does not offer any means to schedulability analysis, as the internal overhead is very hard to predict and data dependent (and lacks proper characterisation).
3) The threading model as such is not particularly suited to concurrent programming (RTFM is event driven, reflecting the reactive nature of the hardware as well as the application).
4) Thread based programming is hard to get right, see e.g., https://www2.eecs.berkeley.edu/Pubs/TechRpts/2006/EECS-2006-...).
5) Regarding FreeRTOS, the current license disallows to make comparisons with FreeRTOS without their permission, how about that for starters!!! /Per
So, the author learned from it, ported it to a safer language, and release the results. Although Ada/SPARK Ravenscar did embedded concurrency, the author certainly builds on modern methods for achieving similar (possibly better) results in Internet of Things. Good work. :)
Thanks! RTFM-core embeds C code, and is as such not particularly safe. However, as an experiment an object (component like) abstraction RTFM-cOOre was drafted (along with a prototype implementation). The cOOre language "could" be safe (just using rtfm-core/C as an intermediate representation). But developing and "selling" a new language requires huge amount effort and resources. Many of the sought features for the cOOre language are already in place with Rust (just that the concurrency model was not there). So that is where it all started, RTFM for Rust, is at present just a subset of the rtfm-core language, but extensions towards timing semantics and object orientation are already in the making. Disclaimer: Myself being fairly new to Rust, so all the Rust type system wizardry is due Mr. Japaric. /Per
That's a very nice use of Rust's safety. This tasking model is a common way to write programs for very small machines, but with this, it's safe. People have a very hard time getting all that priority-level adjustment right.
It's not concurrency, though. It's asynchrony. Two things never happen at at the same time.
Modula I for the PDP-11 did do all this in 1979. In addition, it computed the worst-case stack for each task, so you were sure you couldn't run out of memory if enough preemption occurred. Today this is mostly an issue on very low-end machines, but this code is for machines like very low end ARM processors, where you might run out of stack. Some test fixture to force worst case stack use, with all the priorities stacked up, would be useful.
"Its not concurrency". I would argue that. Its not parallelism (at least not in the current state, but the RTFM-core language that originated this work offers true parallelism, implemented onto of Windows Threads, and Pthreads (Linux/OSX). On multicores, deadlock freeness is not guaranteed, but the rtfd-compiler detects potential deadlocks at compile time for the implementer to fix (so no spurious deadlocks from a system passing compilation). As the multicore implementation is being based on threads, response time analysis for such systems are basically out the window... (Also such multicore systems are very hard to predict, due to cashes, etc...) /Per
51 comments
[ 5.1 ms ] story [ 80.7 ms ] threadRust actually gives me some hope that we might see better low-level code portability between some of these microcontrollers.
In theory I could develop a project on a beefy TI microcontroller using higher-level Rust primitives/libraries and port it over to the cheapest microcontroller I can find that still fits my I/O budget/speed/memory/timer constraints. All that without having to use a RTOS or having to drastically re-write interrupt/timer code to whatever system the new controller uses.
Does Rust support Atmel AVR through LLVM yet?
See http://dylanmckay.io/blog/rust/avr/llvm/2017/02/09/safer-mic... for an overview; 4.0 has been merged, but see https://github.com/rust-lang/rust/issues/37609#issuecomment-...
Edit: and the real reason you don't want to do this is because the EEs and manufacturing engineers on your project will try to kill you. Two uCs means two codebases and two devices to program during production, plus extra testing, more complicated design, and more parts to place (uC, crystal, caps, etc)
If you're doing something truly cutting edge your competitors aren't better than you are so you can afford that second uC and more parts.
Most of engineering judgment is finding the point where the goal is ambitious enough to keep up with or pass the competition while conservative enough that it'll likely work, or at least you won't get sued.
Being able to squeeze the full potential out of these devices is getting harder and harder with current methods. Safe concurrency and memory management can allow developers to fully utilize their hardware without needing a grey beard to write some unreadable assembly that you later find out was just a plagiarized version of the Windows ME memory manager.
Duplicating the microcontroller on a project where people spend all afternoon arguing about 10 cents on the BOM is not a welcome idea. Also, the most eye-opening required course I took as an undergrad was reliability engineering. After you learn to do the reliability math, adding several solder joints to the product purely out of laziness looks profoundly stupid. Neither idea makes you look good to the old grey-beards on the other side of the table at the design review.
Or the word 'never'. There are no absolutes! :)
But yeah, more options is even better.
- Oberon, http://www.astrobe.com/default.htm
- Java, http://www.microej.com/resources/supported-platforms/
- Pascal and Basic, https://www.mikroe.com/stm32/
- Ada, http://blog.adacore.com/tag/STM32
For instance, what will your hypersonic rocket do while garbage collection is running instead of it's real-time control loops?
I can also provide examples for energy motoring, copiers, factory control systems and phone infrastructures.
https://www.google.com/#q=real-time+java
...to get a Wikipedia summary, standards body, a tutorial, and probably some products. It's more useful than Google usually is on some terms like this that might muddy up search results.
One actual combat system - not a terminal for use on base, but something you have to rely on when people are shooting at you.
One.
http://www.aicas.com/papers/EmbeddedWorld2009-Andy-Walter.pd...
The companies that develop reusable solutions for multiple markets tend to pick something easy to certify or sell to all of them. So, if Java wasn't allowed, they'd lean toward something else in their products targeting highest-assurance just to reduce costs. That's mostly been assembly, C and Ada that I've seen.
Meanwhile, we do have proof it can be done in things such as the Sandia Secure Processor that they'll use for some of highest-assurance applications. The first-pass silicon they got was also nice. The best articles by Wickstrom et al on SSP are paywalled in ACM and IEEE if you have access. If not, there's a link below on how they built it with brief description of it under "Score processor," another name.
http://www.sandia.gov/LabNews/LN01-11-02/key01-11-02_stories...
https://www.researchgate.net/publication/236425094_Sandia_se...
ftp://ftp.cs.kent.ac.uk/people/staff/phw/.old-1999/tmp2/443-cpa2007-wickstrom.pdf
USS Bunker Hill ballistic missile defense system weapons control.
http://www.militaryaerospace.com/articles/2010/04/aonix-perc...
"The Aegis Weapon System is the premier naval defense system and the sea-based element of the U.S. Ballistic Missile Defense System. Its precision SPY-1 radar and integrated command and control system guides the interceptor and uplinks target track information to the missile for terminal homing. Its ability to detect, track, and engage targets ranging from sea-skimming cruise missiles to ballistic missiles in space is proven."
Good enough for mission critical system, hypersonic rockets, combat system firing at me?
If not, I can provide other ones, better suited to your use cases.
Also some military think memory leaks are irrelevant on missiles, given the ultimate garbage collector.
"Memory leaks on missiles don't matter, so long as the missile explodes before too much leaks."
EDIT to add: It says "Ada" and "Rational." That's an Ada forum. That language has little protection for temporal safety in the 1990's. More than many but not at Rust level or full leak prevention.
I do like them splitting it into several levels, though. That worked under Orange Book for security.
https://forge.open-do.org/plugins/moinmoin/parasail/FrontPag...
https://news.ycombinator.com/item?id=14346032
https://groups.google.com/d/msg/comp.lang.ada/H35QcYiWR1Y/jJ...
It seems they're adding a little bit of it for SPARK but not critical, dynamic part. I asked him at the end if they plan to go full, dynamic safety for full Ada if the SPARK experiment succeeds. Awaiting the reply.
One of the main limitations of the tech is 'no pointers' in SPARK mode. There are some tricks to hide pointers (you may want to look up the SPARK deployment guide : http://www.adacore.com/knowledge/technical-papers/implementa... ) but it would allow so much more code to be SPARK-compatible. Even in the embedded space sometimes you need pointers and linked-lists and hashmaps (and the new formal containers don't do it for you)... Frama-C allows (and seems to work with) pointers, I don't know how Well.
For Ada you can already go a long way (memory safety and data races) with protected object (nice semantics, check performance), not null pointers, controlled-types... But we're far from Rust's borrow-checker and move semantics. The name Unchecked_Deallocation (to instantiate 'Free') says it all.
Can't wait to see some progress on this !
All in all I'd rank it 'easier' than C in developer comfort and proficiency but frankly, if you don't do C, I'd just go directly to Ada...
I would just argue that un these domains 'Classical C' isn't used, given the constraints regarding language features, using stuff like MISRA-C and similar.
Fully agree with Ada comment, even better if using SPARK.
In any case, many military seem more focused on being easy to hire recruits that already know how to program than training them, hence the ramping up of Java adoption.
You're right about Misra C. Even with Ada you'll end up banning dynamic memory allocation and some stack-exploding stuff, but you still have alternatives like storage pools ('looks-like-dynamic' memory allocation) and Controlled types, and at least you get a stack for structured data types and not just for primitive types...
https://en.wikipedia.org/wiki/Embedded_Java
A particular vendor (formerly Aonix) that always had interesting innovations in runtimes, tradeoffs, FFI's, and so on:
http://www.businesswire.com/news/home/20050307005203/en/Aoni...
https://www.ptc.com/developer-tools/perc
Each of them is a company making serious money in embedded systems. A few do safety-critical. I'll let you wonder whether they were in their right mind for building Java apps and using Java runtimes that don't seem to fail in high-stakes circumstances.
The embedded industry has proven to be very resistant to innovations and modern code-writing practices. Some platforms I coded for didn't even support/allow C99 standard. C++ is gaining some foothold (mbed, for example). Developers don't feel the urge to catch on with times, like in other industries. And yet, now they are expected to write secure IoT systems.
Hopefully Rust can demonstrate its worth and convert key industry specialists who would blog about it. Personally, I'm still waiting for perfect opportunity to apply it on medium-sized project before I fully commit (secretly I'm still rooting for Nim).
Is this changing now?
But at no time has UML tooling been the driving factor behind the industry's adoption or lack of adoption of a language.
The problem with C++ and other high-level languages has always been that it's hard to see how much a line of code costs. Incrementing a pointer to an array in C has a transparent, short runtime, compared to moving to the next element in a C++ collection which may accidentally invoke a dizzying indecipherable mess of template objects, overloaded operators, and STL dependencies. Or in other languages, you may need a large operating system and runtime to be loaded.
High level languages do handy magic things for you under the hood. If your engine bay is measured in terabytes of storage, gigabytes of RAM, gigaflops of computational power, hundreds of watts of electrical power, and seconds of acceptable interaction time, those magic things that let programmers build useful features faster are nice.
But when you're trying to get guaranteed responses in microseconds from milliwatts of electrical power in a few kilobytes of RAM, you're likely going to be hand-picking everything under the hood. No magic allowed.
But to answer your question, C++ is gaining a larger foothold in embedded if anything. More and more libraries are written in C++, and it's becoming more supported in the various toolchains.
From a very recent hackaday article - "Modern C++ allows us to write cleaner, more concise code, and make the code we write more reusable. The following are [...] new features of C++ that don’t add memory overhead, reduce speed, or increase size because they’re all handled by the compiler [...] after reading this you’ll be more aware of the newer features as we start to see them roll out in Arduino code."
http://hackaday.com/2017/05/05/using-modern-c-techniques-wit...
And also, because I was poking around their github today, here is Flybrix's source code, a lego-drone startup writing C++ on a Kinetis K-20 microcontroller (100 MHz ARM Cortex-M4). They use the teensy bootloader, which is why you see a mix of Arduino and C++ files
https://github.com/flybrix
Those are opposing goals.
I'm curious how they determined FreeRTOS wasn't appropriate for their use cases?
https://news.ycombinator.com/item?id=14294408
So, the author learned from it, ported it to a safer language, and release the results. Although Ada/SPARK Ravenscar did embedded concurrency, the author certainly builds on modern methods for achieving similar (possibly better) results in Internet of Things. Good work. :)
It's not concurrency, though. It's asynchrony. Two things never happen at at the same time.
Modula I for the PDP-11 did do all this in 1979. In addition, it computed the worst-case stack for each task, so you were sure you couldn't run out of memory if enough preemption occurred. Today this is mostly an issue on very low-end machines, but this code is for machines like very low end ARM processors, where you might run out of stack. Some test fixture to force worst case stack use, with all the priorities stacked up, would be useful.