Arduino without the GUI
The first attempt to start playing around with Arduino’s on my machine had
involved installing the arduino
:octocat: package from
nixpkgs :octocat:.
After a few pathetic attempts to use the Arduino IDE with my current window manager (XMonad), I gave up on the GUI route. Basically the IDE seems to be okay, but menus exhibit really weird behavior requiring me to keep the mouse depressed while navigating towards the drop-down menu which appears way out of reach of the menu bar. Furthermore, the IDE doesn’t seem to play well with XMonad dictating which dimensions to assume.
To be honest, I wasn’t serious about using the IDE anyways. CLI tools are more user-friendly when it comes to automation anyways so fvck :fu: the UI.
So here is an account of several ways to build code for the Arduino boards covering
- the easiest (least flexible) using the
arduino
tool which does it all, - the harder (more flexible) option which utilizes the
arduino-build
tool in combination withavrdude
and someday… - the hardest option which I haven’t come around to document but
involves custom Makefiles to build source, and link objects and subsequently
upload the whole she-bang using the
avrdude
tool. :hourglass:
1
The easiest way to circumvent the painful IDE experience is by simply using the
arduino
CLI tool.
In NixOS, one can install the arduino
toolset system-wide by adding the
package arduino
or arduino-core
, conversely one may also define a custom
nix-shell. The nix-shell options is pretty neat since one defines shell.nix
and or default.nix
inside the project directory within which one may specify
all needed dependencies for that project. This makes it really easy for other
Nix* users to get setup in no time.
# shell.nix
{ system ? builtins.currentSystem }:
let pkgs = import <nixpkgs> {};
in pkgs.callPackage ./default.nix {}
The shell.nix
file in this case, just defines a derrivation in which system
defaults to the builtins.currentSystem
and where the
derivation defined in default.nix
is loaded.
# default.nix
{ stdenv, pkgs }:
stdenv.mkDerivation rec {
name = "arduino-dev-${version}";
src = ./.;
version = "0.1.0";
ARDUINO_PATH="${pkgs.arduino-core}";
buildInputs = with pkgs; [
arduino
];
shellHook = ''
export PATH="$PATH:${pkgs.arduino-core}/share/arduino/"
'';
}
The default.nix
file basically sets up an environment containing the
arduino
package – essentially arduino-core
with the GUI enabled as evident
in the code :octocat:. In order to simplify things, we
define an environment variable ARDUINO_PATH
which points to the location
where Arduino-related files may be found and add the path of the arduino
binaries to the $PATH
environment variable in the shellHook
, allowing us to
call commands such as arduino
and arduino-builder
:wink:.
Start the shell represented by the descriptions captures in shell.nix
and
default.nix
by running nix-shell
within the directory where these files are
stored.
In order to figure out how to use the arduino
CLI tool, consult the
manpage or see the examples but
basically, provided that we have a sketch named Blink.cpp
, one may run
arduino --verify Blink.cpp
to build the sketch.
In order to compile and upload the sketch in one go, one may run
arduino \
--board arduino:avr:leonardo \
--port /dev/ttyACM0 \
--upload Blink.cpp
in case the board in question is an Arduino Nano donning the ATMega168 AVR
chipset and connected to port ttyACM0
. In case you’re dealing with some other
hardware, please explore the boards.txt file located in the
$ARDUINO_PATH/share/arduino/hardware/arduino/avr
directory and adjust the
parameters accordingly.
Usage of the --verbose-build
and --verbose-upload
arguments
arduino \
--board arduino:avr:leonardo \
--port /dev/ttyACM0 \
--verbose-build \
--verbose-upload \
--upload Blink.cpp
could be helpful in case :poop: hits the fan in order to aid in sleuthing :mag:.
To conclude this section, observe how I change into a directory which contains the default.nix and shell.nix, spawn a nix-shell and shoot an application to an Arduino Leonardo :wink:.
2
:flushed: The process described in the previous section should be enough to get going. For whichever reason you decided to read on, things are about to get a bit more involved. For convenience’s sake, I assume that you have read through the section above.
The arduino
tool uses the arduino-builder
under the hood. Given the
default.nix
and shell.nix
files presented above. We could run the
arduino-builder
by executing
arduino-builder \
-build-path ${PWD}/out \
-debug-level 10 \
-fqbn arduino:avr:leonardo \
-hardware ${ARDUINO_PATH}/share/arduino/hardware/ \
-libraries ${ARDUINO_PATH}/share/arduino/libraries/ \
-tools ${ARDUINO_PATH}/share/arduino/tools/ \
-tools ${ARDUINO_PATH}/share/arduino/tools-builder/ \
-tools ${ARDUINO_PATH}/share/arduino/hardware/tools/ \
-verbose \
-warnings all \
Blink.cpp
which is quite a handful but essentially compiles the Blink.cpp file, given the
parameters specified, to produce a collection of build artifacts in the
${PWD}/out
directory. The build artifcats directory is a step up from the
arduino
approach. If you like studying the machine code like these guys you’ll have something to study and play with
when using arduino-builder
:wink:.
After building one would still need to flash the Arduino. This could be done
by using the avrdude
:books: tool. Since this wasn’t installed
before, we would have to modify the default.nix
file by adding the avrdude
package to the mix.
# default.nix
{ stdenv, pkgs }:
stdenv.mkDerivation rec {
name = "arduino-dev-${version}";
src = ./.;
version = "0.1.0";
ARDUINO_PATH="${pkgs.arduino-core}";
buildInputs = with pkgs; [
arduino
avrdude
];
shellHook = ''
export PATH="$PATH:${pkgs.arduino-core}/share/arduino/"
'';
}
At this stage, one may run
avrdude \
-C${ARDUINO_PATH}/share/arduino/hardware/tools/avr/etc/avrdude.conf \
-patmega32u4 \
-cavr109 \
-v -v -v -v \
-P/dev/ttyACM0 \
-b57600 \
-D \
-Uflash:w:${PWD}/out/Blink.cpp.hex:i
to upload the prior generated binary to the board.
:boom: In case you run into the
avrdude: ser_recv(): programmer is not responding
avrdude: butterfly_recv(): programmer is not responding
errors please
- verify that the specified port is actually the correct port as explained earlier,
- verify that the specified board and/or the processor correspond to the board and processor plugged into the machine and
- ensure that the board switches “bootloader mode”
which would generally lead to resolution.
For demonstrative purposes you can have a glance at a Makefile
which I wrote to simplify the build and flash process with arduino-builder for a
something I was fooling around at home with :stuck_out_tongue_closed_eyes:. The
make rules build
, clean
and flash
should be sufficient for basic workflows.
3
I would have to write a custom Makefiles to call gcc
while including the
Wiring library and all other required libs, while perform all linking activities
myself. I would also have to provide a main function that calls the setup
and
loop
functions, unless the Wiring library has off-the-shelf method of handling
this which I don’t remember. I did this a while ago in university, but have am
too lazy to look into my archives (which I don’t have within reach at the moment
anyways). So let’s just call this a work in progress. Hopefully some day I’ll
get around to it. :rainbow: