6 ms·
I would absolutely love to throw my lot down behind something other than C/C++ for embedded development, but after investigating Lua and Rust I could only come
by contingencies 8y ago
I would absolutely love to throw my lot down behind something other than C/C++ for embedded development, but after investigating Lua and Rust I could only come to the conclusion that they're currently inappropriate for resource constrained commercial development... particularly if you use a broad range of sensors, have higher-level protocol communication requirements, etc. Re-implementing this stuff isn't just a minor drag, it's commercial insanity.
1. Example hardware in this book costs around 98RMB and has a huge form factor. AVR / ATmega328P based platforms like Arduino Nano are currently ~10RMB, which can be beefed up to full ethernet connectivity with prebuilt hardware modules for another 20RMB. So in short it is possible to procure over three(!!!) embedded, ethernet capable AVR platforms for the same price as this hardware, no soldering required. Why not use something cheaper and more broadly available? It would help more people get on board (no pun intended). Oh wait, there's no AVR support. I see...
2. The nominal target hardware in the book seems overpowered/overpriced/out of date. For example, the target used in the early book is LM3S6965, which is NRND (Not Recommended for New Designs). Probably as a result of NRND status (I guess people buying up stock to keep old designs in manufacturing) it costs over 125RMB for the chip alone. The manufacturer's recommendation for replacement is TM4C12x, the cheapest development board for which is MINI-M4FORTIVA @ 22RMB (which features JTAG). ICs in this series begin at 22RMB or so, still many times AVR chip price, and with IMHO far too much hardware for novices (64KB flash, 12KB RAM, 12x12bit ADC channels, 49+ GPIO channels...). A direct quote from later in the book is In this example, let's assume we have an Texas Instruments TM4C123 - a middling 80MHz Cortex-M4 with 256 KiB of Flash. That's not middling, that's ridiculously overpowered for almost anything embedded.
3. See example code at https://rust-embedded.github.io/book/start/registers.html https://rust-embedded.github.io/book/start/registers.html and compare C and Rust Volatile Access examples at https://rust-embedded.github.io/book/c-tips/index.html https://rust-embedded.github.io/book/c-tips/index.html and see which syntax you prefer...
- Matumio 8y agoIs there seriously still a commercial reason to use the ATmega328 (an 8-bit microcontroller with 2000 bytes of RAM) for new projects? I've been working on 3D printing firmware, and it's so easy and silly to reach the limit of this CPU. Been shaving bytes of RAM by reducing queue sizes, running into performance limits even with a few 32bit additions in the stepper loop. That was 6 years ago. The only semi-valid reason to use this chip IMO is because people want to keep using existing firmware as-is.
- contingencies 8y agoIn fact many embedded requirements are not as complicated as a 3D printer and essentially consist of basic logic and state, sensors and effectors, potentially with some external communication. It may surprise you but 8 bit micros are absolutely fine for this and can serve HTTP at well over a hundred requests per second without breaking a sweat. If you read the Stepper code for Marlin @ https://github.com/MarlinFirmware/Marlin/blob/1.1.x/Marlin/stepper.cpp https://github.com/MarlinFirmware/Marlin/blob/1.1.x/Marlin/s... you will see it's nontrivial... bunch of PhDs implementing nontrivial maths in a highly constrained environment. That's cute but not demonstrative of real world concerns. In such cases, you would absolutely throw more hardware at the problem, eg. for motion systems maybe dedicating one 'dumb' MCU per axis and outsourcing planning to a more rational/powerful environment.
- howard941 8y agoCost and temperature. Albeit not the ATmega 328 MCUs in the even more resource constrained ATTINY series go for under $.30 in quantity and run in 125C environments https://octopart.com/search?q=avr%208%20bit&sort=median_price_1000&sort-dir=asc https://octopart.com/search?q=avr%208%20bit&sort=median_pric... . It's going in new products.
- contingencies 8y agoOnly $0.13 for 2000+ ATTINY25-20SU according to http://www.hqchip.com/search/ATTINY.html http://www.hqchip.com/search/ATTINY.html
- bsder 8y agoUm, look that up on findchips/octopart/etc. It's a buck and change on those--same as ARM Cortex M series.
- hajile 8y agoA rather small team of 10 people (with only 4-5 devs) will cost 10K per week at some generic corporation. Let's say your project takes 12 months to make on a beefy processor ($2 per unit) and 15 months on a cheap processor ($1 per unit). That extra dev time to deal with those issues directly costs 120K. That automatically means you have to be shipping at least 120K units just to break even with those costs. But you are also getting to market 3 months later which itself has huge business costs which means you probably need to be shipping 200K or more units. That's a pretty big number for a lot of embedded device designers. If you double your chip constraint from $0.13 to $0.26, then that same team must now ship a million devices to break even.
- DecoPerson 8y agoIt's easy to mix C/C++ with Lua or Rust. Lua requires you to write a C library or use LuaJIT's FFI library. There's a number of Rust crates that let you include arbitrary C/C++ code, such as the cc crate [0]. This approach allows you to have the advantages of the higher-level language while still being able to utilize existing libraries. While not for an embedded project, I used this approach to write a Rust application that interfaces with the Helix Perforce C++ API. Also, regarding your point #3, I prefer the Rust version by far. Code is written once and read many times. Without needing to jump between places or rely on good IDE contextual information, the Rust version says: - SIGNALLED is intended to be modified. - ISR must conform to the rules of an interrupt handler -- be careful what you do in this method. - The write to SIGNALLED is unsafe and volatile. - The read of SIGNALLED is unsafe and volatile. You can be sure the while condition check won't be optimized away because you see the use of the "read_volatile" -- if you're tracking down a bug, no need to go look to see if SIGNALLED is marked volatile. Plus, in the comments of the Rust sample, the author recommends using a higher-level primitive, to avoid the direct calls to read/write_volatile. A good IDE would show type hints: "volatile bool" for C and "Atomic<bool>" for Rust, or something similar. [0] https://crates.io/crates/cc https://crates.io/crates/cc .
- scoutt 8y agoAs a C firmware developer always trying to learn something new I looked into Rust for embedded, but cases like this hold me back to delve deeper. So, to set a value into a (volatile) boolean I have to call a function passing a pointer within an unsafe block? Why on earth it's clearer than or preferred over the C code? I know, you'll list several reasons, but please, it's not clearer and it's voodoo magic. In fact, it is the last thing I would (intuitively) think about doing, since it's known that you cannot operate from a pointer to a volatile variable because it may be UB in C++. >> the author recommends using a higher-level primitive Again, to read/write a boolean? Are we talking embedded here? From https://doc.rust-lang.org/core/ptr/fn.write_volatile.html https://doc.rust-lang.org/core/ptr/fn.write_volatile.html >> Rust does not currently have a rigorously and formally defined memory model, so the precise semantics of what "volatile" means here is subject to change over time. WHAT!? I cannot bring Rust to any serious development yet...
- jononor 8y agoYou can get one of the STM32F103C8T6 devboards "bluepill" and use that instead for Rust. Under 2 USD, almost at the level of Arduino Nano knockoffs. The AVR backend for LLVM was merged recently. So Rust support for AVR might happen if someone pitches in and does the work. Lots of Arduinos lying around, so it would make it more accessible.
- spatular 8y agoAbsolutely this. The same price and the Bluepill has much more powerfull CPU. The problem is HAL support. Some periphery is supported, other is not. ADC and DMAs for UARTs were merged just recently. Stuff like SPI / I2C slave modes is missing, I think HAL interface is not fleshed out yet. Stuff like usb stack would probably take a lot time to complete.
- jononor 8y agoHow does it work to call C for the missing peripherals? For instance using the exiting vendors libraries. The book in question does not seem to cover this, unfortunately. I think for a long time we will have to accept that Rust and C are going to co-exist on these devices. So that story should be workable. My embedded code tends to have a strong split between application logic (in platform-independent, data-driven functional code, with automated tests) and underlying hardware-dependent "app host" (as little custom code as possible), with a data-based interface. I would be quite happy doing C for the hardware layer and Rust for the application logic layer.
- spatular 8y agoI haven't tried it, but it should be doable. A lot of linux-based rust libs wrap C libs and link to them, or compile their own embedded version during build. Same thing here too, though there could be some problems regarding what C compiler is used and where it expects to find its libs.
- thezoq2 8y agoI'm not sure how well it would work, the rust embedded HAL crates like to be in control of all peripherals in order to give nice guarantees of things being properly initialised. Calling C would also have to touch the same structures which would, if nothing else, change the state of some peripherals to something that will break the rust guarantees.
- davidrm 8y ago> That's not middling, that's ridiculously overpowered for almost anything embedded. well you obviously have a different idea of embedded. Sure, there are different requirements for different systems, but in IoT, my previous company shipped tens of thousands of devices (fleet monitoring, smart sensor networks etc) and everyhing was based on STM32 L & F series, Cortex M0, M3 & M4. Now, in automotive we have MPC57xx. > Re-implementing this stuff isn't just a minor drag, it's commercial insanity absolutely agree. if there will be an adoption it will be incredibly slow. Logical but extremely frustrating.
- stusmall 8y agoI used to do a lot of embedded work and found it really interesting where people draw the line on what is "embedded" Around 2009ish, I had a coworker who swore anything over 16 bits wasn't embedded. We were working on a MMU-less uClinux ARM7 system with 16mb of RAM and no networking and that didn't meet his criteria for "true embedded". The next job I had was a piece of customer premises equipment that ran a fairly high powered ARM board with dual gigabit ethernet links and a lot of user space written in PHP. No one on that team questioned that it was an embedded system. It always seemed like a strange thing to gatekeep on. Personally, I base my definition more on the use case than the power of the machine.
- keithnz 8y agohighly resource constrained, real time, bare metal (or micro kernel) embedded programmers tend to think what they do as "embedded programming". There's a certain element of truth to it if you make the distinction between "embedded system" and "embedded programming". "Embedded programming" loosely groups a bunch of techniques for dealing with real time, bare metal, resource constrained devices. But there is no real formal distinction between those things.
- taneq 8y ago> Around 2009ish, I had a coworker who swore anything over 16 bits wasn't embedded. When I were a lad, if you had more than a dozen bytes of RAM it wasn't REAL embedded. /shakes-cane I generally use your definition, though. Any computer that the end user doesn't think of as a computer (and isn't expected to maintain or directly use) is embedded, whether it's a camera with touchscreen GUI or an ABS processor in a car.
- stefan_ 8y agoATmega are a commercial failure, and frankly, outmoded toys. They are not covered because they have no relevance outside of Arduinos.
- contingencies 8y agoI agree at this price bracket STM32 is better value. My point was not about particular chips, but rather a better platform for promoting embedded Rust development in terms of price and focus for most basic circuits than the stuff of the article, which in terms of tooling and clock speed is more like a general purpose processing platform: higher cost, less distribution, less relevance. What Rust or Lua needs to take off for embedded IMHO is an Arduino-like IDE, a bunch of libraries (Arduino's library manager is crap), and lots of people with hardware. That's not going to happen if the entry level hardware costs are 5x and the current stock of hardware in broadest distribution (AVR based) remains unsupported.
- albru123 8y agoI'm wondering if that's going to cut it though, since target audience for embedded rust isn't someone who wants to play with his Arduino, but people who write real world applications and are fed and tired of C/C++.
- contingencies 8y agoThere seems to be a common misconception here amongst traditional desktop and server software people that embedded programming requires vast software complexity. In fact, most real world electronics are very simple software wise. There's just a lot of them, they're a pain to get to, and they have alternative and nuanced challenges and context (cost, speed, debugging, stability, environmental considerations, etc.). Now regarding language, let me illustrate an area in which C/C++ sucks balls for embedded. Using a cheap MCU is generally considered good practice if you have many target systems to produce and they are possible to execute on that cheap MCU, because using a pricier one will quickly add up and retargeting a team costs a lot. The problem is that on a cheap MCU sometimes you run out of basic resources, such as physical interfaces (pins). In the embedded world there are multiple solutions to most problems, just as there are in the conventional software one (ie. classic perl quote TMTOWTDI) and one of these is connecting IO expansion chips via alternate (particularly shareable) interfaces such as I2C/SPI. Such chips provide various types of interfaces by proxy, for example additional GPIO pins. The issue with these is that many libraries, such as those written to control motors, those written to control MOSFETs/relays, those written to control serial devices will not work by default on these proxied interfaces. Therefore, you need to either hack or rewrite the respective libraries in order to use them. Coming from a software background myself, this is a basic interface abstraction, and the current solution is ridiculous. Reflectance would go a long way to solving the issue. Lua frankly appeals more than Rust in this regard when dealing with third party, existing libraries which were not constructed explicitly with the requisite abstraction. Alternatively, I believe some software people here on HN recently announced they are attempting a generative approach for embedded circuits and software, sort of a 'ruby on rails' shake-n-bake approach to the whole problem space. The issue with such approaches tends to be that you wind up with a whole lot of deployable product but nobody who understands the intricacies, a vast cognitive overhead for your higher level generation specification languages, there are frequently incompatibilities in devices which are based upon timing, clock frequency or other hard to model aspects of a proposed system, and iterations in hardware cost a lot more in time and money than those in software. Both approaches are used in embedded development, but it is a vast space whose tooling usually differs by target hardware, as if you needed a new IDE, compiler, command line, development workflow and physical interface type for every language you wanted to write on a desktop, and interpreted languages didn't exist. Some of the tooling is prohibitively expensive. I hope you can now see the problem space is not that similar to desktop software, although the conventional software world does have a lot it could further contribute to electronics. As usual for those outside of an area, the perceived simplicity of established solutions belies the complexity, nuance and outright effectiveness of their current, if ugly, state.
- spatular 8y agoAFAIK LM3S6965 is used in the book as a target for QEMU, and no one endorses to use the chip in actual hw.
- nh2 8y agoRust can run on the Arduino Nano. Here is one example I ran on it: https://github.com/nh2/quadcopter-simulation/blob/master/arduino-accel-rust/src/main.rs https://github.com/nh2/quadcopter-simulation/blob/master/ard...
- shepmaster 8y agoWe are slowly working on AVR support both in LLVM and Rust. https://github.com/avr-rust/rust https://github.com/avr-rust/rust
- contingencies 8y agoI did find that but described as a fork, it is 11 commits ahead, 5210 commits behind rust-lang:master. The only activity in the last month is https://github.com/avr-rust/rust/pull/137 https://github.com/avr-rust/rust/pull/137 ... which seems to be you talking to the void. Honestly, and I don't mean this to sound rude, I assumed it was a dead project. Well done for persisting!
- pjmlp 8y agoAnother part winning the hearts over the religious movement against anything but C and Assembly on embedded, even tool vendors, which even C++ in spite of its copy-paste compatibility with C faces, let alone languages that require other approaches.