7 ms·
Fearless concurrency in your microcontroller
- mmastrac 9y agoAmazing writeup. Note the previous submission here as well: https://news.ycombinator.com/item?id=14225614 https://news.ycombinator.com/item?id=14225614 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. Does Rust support Atmel AVR through LLVM yet?
- steveklabnik 9y ago> Does Rust support Atmel AVR through LLVM yet? See http://dylanmckay.io/blog/rust/avr/llvm/2017/02/09/safer-microcontrollers-almost-here.html 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-297031521 https://github.com/rust-lang/rust/issues/37609#issuecomment-...
- pdelbarba 9y agoI 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...
- amelius 9y agoOtoh controllers cost almost nothing, so you can get safe concurrency just by duplicating the CPU.
- pdelbarba 9y agoYou'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)
- VLM 9y agoAll 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.
- pdelbarba 9y agoIn 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.
- veli_joza 9y agoNice 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).
- qntty 9y agoIt was my understanding that C++ was being abandoned in the embedded world in favor of C due to the failure of UML. See for example, the intro of this (possibly outdated) article: http://embeddedgurus.com/state-space/2008/01/object-based-programming-in-c/ http://embeddedgurus.com/state-space/2008/01/object-based-pr... Is this changing now?
- LeifCarrotson 9y agoI 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.
- carapace 9y ago(That font! My eyes! Small grey thin sans-serif body text means you hate your readers' eyes.)
- mechatrocity 9y ago> The RTFM language was created ... to develop real time systems for which FreeRTOS didn’t fit the bill. I'm curious how they determined FreeRTOS wasn't appropriate for their use cases?
- PerLindgrenRTFM 9y agoHi 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-1.pdf 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
- nickpsecurity 9y agoNeat to see given I submitted RTFM-core recently: https://news.ycombinator.com/item?id=14294408 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. :)
- PerLindgrenRTFM 9y agoThanks! 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
- Animats 9y agoThat'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.
- PerLindgrenRTFM 9y ago"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