Recently one of my customers brought to my attention Nerves. It aims to simplify use of Elixir (functional language leveraging Erlang VM) in embedded systems. This system has couple interesting features that are worth of research and blog post.
First is booting directly to application which is running in BEAM (Erlang VM). Nerves project replace systemd process with programming language virtual machine running application code. Concept is very interesting and I wonder if someone tried to use that with other VMs ie. JVM.
Second Nerves seems to utilize dual image update procedure. In my opinion any development of modern embedded system should start with update system. Any design that you can to your system update arsenal will be useful.
Third, Nerves use Buildroot as build system, which will I’m familiar with. Using popular build systems means simplified support for huge set of platforms (at point of writing this article Buildroot have 142 config files).
Let’s start with documentation
If you don’t want to go through all installation steps and you use Debian testing, you can run:
Checking exact Erlang version for non Erlang developers is trivial:
Checking Elixir version:
Unfortunately Nerves Project requires at least
1.4.0, what can be solved by:
fwup have to be installed from
I don’t understand why Nerves Projects used
fwup, when software like
swupdate from Denx is available. I don’t see difference in feature set and
would say that
swupdate is more flexible and covers more use cases. It looks
like Nerves Project is main user of
Maybe it would be worth to consider comparison of
hello_nerves for BeagleBone Black
Flashing to SD card
It look that things work out of the box and Elixir started and D2 LED blinks continuously.
It looks like developers configured Linux kernel
bootargs used by U-Boot to
elrinit as init process.
erlinit is relatively simple application that
can parse configuration file and do some basic system initialization. Depending
on needs this may be considered quite weird approach. Of course adding
systemd is not best approach for all solutions. For sure having custom init
binary remove need for complex init system and makes updates much smaller. Also
this solution targets dedicated embedded systems that whole purpose is running
Using custom init binary also limit attack vector to small amount of code. In typical build from Buildroot or Yocto final image contain quite a lot of process run by default. Nerves limit that to one that is needed for very specific use case that can be fully handled by Elixir application. Of course still some hardware setup is needed. In that case only Linux kernel or Elixir application can be attacked.
As one of my associate mention this is very similar approach to
although here we replace shell with Elixir interpreter, but idea is similar to
have one application that is entry point to the system.
From performance perspective this is also good solution since there a no daemons working in background that consuming resources. Lack of additional processes means that all server type of work have to be written in Elixir.
It would be very interesting to see how this approach can work for other VMs and if there are real world use cases for that.
erlinit & erlexec
erlinit is MIT licensed
/sbin/init replacement. In general it:
- setup pseudo-filesystems like
- setup serial console
- register signal hendlers (
- forks into cleanup process and new that start
elrexec is mix of C++ and Erlang that aim to control OS processes from Erlang
Source code can be found on Github: erlinit and erlexec.
Note about building natively
Recently I’m huge fan of containers and way this technology can be utilized by
embedded software developers. Installing all dependencies in your environment
is painful and can cause problems if you do not pay attention. Containers give
you ability to separate tools for each project. In that way you create one
Dockerfile for whole development environment and then share it with your
peers. I believe Nerves Project shall share containers to build system images
instead of maintaining documentation explaining how to setup development
for lot of various environments.
For example steps for Debian required more of jumping between pages and googling then it was worth since correct set of packages solve issue.
Do you plan to use Nerves in your next embedded systems project ? Maybe you struggle with adapting similar approach for different VM ? Feel free to share your ideas and issues in comments. If you think content valuable please share this help us in providing more content to our blog.