Getting Started

Introduction

Nerves defines an entirely new way to build embedded systems using Elixir. It is specifically designed for embedded systems, not desktop or server systems. You can think of Nerves as containing three parts:

Platform - a customized, minimal Buildroot-derived Linux that boots directly to the BEAM VM.

Framework - ready-to-go library of Elixir modules to get you up and running quickly.

Tooling - powerful command-line tools to manage builds, update firmware, configure devices, and more.

Taken together, the Nerves platform, framework, and tooling provide a highly specialized environment for using Elixir to build advanced embedded devices.

Common Terms

In the following guides, support channels, and forums you may hear the following terms being used.

TermDefinition
hostThe computer on which you are editing source code, compiling, and assembling firmware
targetThe platform for which your firmware is built (for example, Raspberry Pi, Raspberry Pi 2, or Beaglebone Black)
toolchainThe tools required to build code for the target, such as compilers, linkers, binutils, and C runtime
systemA lean Buildroot-based Linux distribution that has been customized and cross-compiled for a particular target
assembleThe process of combining system, application, and configuration into a firmware bundle
firmware bundleA single file that contains an assembled version of everything needed to burn firmware
firmware imageBuilt from a firmware bundle and contains the partition table, partitions, bootloader, etc.

Creating a New Nerves App

Before you start using Nerves, it is important that you take a minute to read the Installation Guide. It will help you get your machine configured for running Nerves.

Let’s create a new project. The nerves.new project generator can be called from anywhere and can take either an absolute path or a relative path. The new project generator requires that you specify the default target you want the project to use. This allows you to omit the --target option when building firmware for the default target. Visit the Targets Page for more information on what target name to use for the boards that Nerves supports.

$ mix nerves.new hello_nerves --target rpi3
* creating hello_nerves/config/config.exs
* creating hello_nerves/lib/my_app.ex
* creating hello_nerves/test/test_helper.exs
* creating hello_nerves/test/my_app_test.exs
* creating hello_nerves/rel/vm.args
* creating hello_nerves/rel/.gitignore
* creating hello_nerves/.gitignore
* creating hello_nerves/mix.exs
* creating hello_nerves/README.md

Nerves will generate the required files and directory structure needed for your application. The next step is to cd into your hello_nerves directory and fetch the dependencies

$ cd hello_nerves
$ mix deps.get

It is important to note that Nerves supports multi-target projects. This means that the same code base can support running on a variety of different target boards. Because of this, It is very important that your mix file only includes a single nerves_system at any time. For more information check out the Targets Page

Once the dependencies are fetched, you can start to compile your project. The goal is to make a Nerves Firmware (a bundle that contains a Nerves-based Linux platform and your application). As a first step, you need to fetch both the System and Toolchain for your Target. This task is done for you by Mix using the nerves_bootstrap utility in a special stage called precompile. This means that the first time you ask any dependencies or your application to compile, Nerves will fetch the System and Toolchain from one of our cache mirrors. Lets start the process and get a coffee…

$ mix compile
Nerves Precompile Start
...
Compile Nerves toolchain
Downloading from Github Cache
Unpacking toolchain to build dir
...
Generated nerves_system_rpi3 app
[nerves_system][compile]
[nerves_system][http] Downloading system from cache
[nerves_system][http] System Downloaded
[nerves_system][http] Unpacking System
...
Nerves Env loaded
Nerves Precompile End

At this point, the Nerves System and Toolchain have been pulled down to your host machine and your Mix environment has been bootstrapped to use them when you build a firmware. You can verify that Nerves is ready with the correct System and Toolchain by getting it to print out the locations of these new assets.

$ NERVES_DEBUG=1 mix compile
Nerves Env loaded
------------------
Nerves Environment
------------------
target:     rpi3
toolchain:  _build/rpi3/dev/nerves/toolchain
system:     _build/rpi3/dev/nerves/system
app:        /Users/nerves/hello_nerves

You’ll notice that subsequent calls to compile will not fetch or build the system because they’re already cached on your host computer.

Making Firmware

Now that you have a compiled Nerves application, you can produce firmware. Nerves firmware is the product of turning your application into an OTP release, adding it to the system image, and laying out a partition scheme. You can create the firmware bundle with the following command:

$ mix firmware
Nerves Env loaded
Nerves Firmware Assembler
...
Building _images/rpi3/hello_nerves.fw...

This will eventually output a firmware bundle file _images/rpi3/hello_nerves.fw. This file is an archive-formatted bundle and metadata about your firmware release. To create a bootable SD card, you can use the following command:

$ mix firmware.burn
Burn rpi3-0.0.1 to SD card at /dev/rdisk3, Proceed? [Y/n]

This command will attempt to automatically discover the SD card inserted in your host machine. There may be situations where this command does not discover your SD card. This may occur if you have more than one SD card inserted into the machine, or you have disk images mounted at the same time. If this happens, you can specify which device to write to by passing the -d <device> argument to the command. This command wraps fwup, so any extra arguments passed to it will be forwarded along to fwup.

$ mix firmware.burn -d /dev/rdisk3

Note: You can also use -d <filename> to specify an output file. This will allow you to create a binary image that you can burn later using dd or some other image copying utility.

Now that you have your SD card burned, you can insert it into your device and boot it up. For Raspberry Pi, connect it to your HDMI display and USB keyboard and you should see it boot to the IEx Console.

Note: If you are sure there is only one SD card inserted, you can add the -y flag to skip the prompt making sure it is the right SD card.

$ mix firmware.burn -y

Nerves Examples

To get up and running quickly, you can check out our collection of example projects. Be sure to set your NERVES_TARGET environment variable appropriately as the examples use this to determine the target when building firmware. Visit the Targets Page for more information on what target name to use for the boards that Nerves supports.

$ git clone https://github.com/nerves-project/nerves-examples
$ cd nerves-examples/blinky
$ NERVES_TARGET=rpi3 mix do deps.get, firmware

The example projects contain an app called Blinky, known as “The Hello World of Hardware”. If you are ever curious about project structuring or can’t get something running, it is advised to check out Blinky and run it on your target.