Breaking

Post Top Ad

Friday, August 23, 2019

Arduino from the Command Line: Break Free from the GUI with Git and Vim!

Love Arduino but hate the GUI? Try arduino-cli.




In this article, I explore a new tool released by the Arduino team
that can free you from the existing Java-based Arduino graphical user
interface. This allows developers to use their preferred tools and
workflow. And perhaps more important, it'll enable easier and deeper
innovation into the Arduino toolchain itself.




The Good-Old Days




When I started building hobby electronics projects with microprocessors in
the 1990s, the process entailed a discrete processor, RAM, ROM and masses of glue logic
chips connected together using a point-to-point or "wire wrapping"
technique. (Look it up kids!) Programs were stored on glass-windowed
EPROM chips that needed to be erased under UV light. All the tools were
expensive and difficult to use, and development cycles were very slow.
Figures 1–3 show some examples of my mid-1990s
microprocessor
projects with discrete CPU, RAM and ROM. Note: no Flash, no I/O, no DACs,
no ADCs, no timers—all that means more chips!





Figure 1. Example Mid-1990s Microprocessor



""


Figure 2. Example Mid-1990s Microprocessor




""


Figure 3. Example Mid-1990s Microprocessor




It all changed in 2003 with Arduino.




The word "Arduino" often invokes a wide range of opinions and
sometimes emotion. For many, it represents a very low bar to entry into the
world of microcontrollers. This world before 2003 often required costly,
obscure and closed-source development tools. Arduino has been a great
equalizer, blowing the doors off the walled garden. Arduino now represents
a huge ecosystem of hardware that speaks a (mostly) common language and
eases transition from one hardware platform to another. Today, if you
are a company that sells microcontrollers, it's in your best interest to
get your dev boards working with Arduino. It offers a low-friction path
to getting your products into lots of hands quickly.




It's also important to note that Arduino's simplicity does not inhibit
digging deep into the microcontroller. Nothing stops you from directly
twiddling registers and using advanced features. It does, however, decrease
your portability between boards.




For people new to embedded development, the Arduino software is
exceptionally easy to get running. That has been a major reason for its
success—it dumps out of the box ready to rock. But for more seasoned
developers, the included graphical user interface can be frustrating. It
can be a barrier to using modern development tools and version control
like Git. I know the compiler and toolchain is buried deep in that GUI
somewhere. I just want to use my favorite editor, compile my code and
upload my project to a dev board using my favored workflow. For
many developers, this is a command-line or scripted process.




Enter arduino-cli




There have been a couple attempts to break out Arduino to the command
line, but most failed to get wide support. However, now the Arduino team has
alpha-released arduino-cli. This new framework not only provides
a comprehensive set of command-line functions, but the team also says it will be
used as the core underneath the next generation of the Arduino graphical
interface. This is exciting news and shows commitment to this new concept.




For me, my preferred development workflow is using Git for version control and
the Vim editor, so that's what I demonstrate in the remainder of
this article.




Installing arduino-cli




At the time of this writing, the arduino-cli is in alpha release. It's being distributed both as a
Go source package and pre-built binaries. The Go language produces very
portable binaries, so you just need to download the correct file and
put the binary somewhere in your $PATH. Most users reading this
likely will want the Linux 64-bit for Intel/AMD systems. In the examples here,
my system happens to be running Fedora 29, but any recent Linux
should work. Check the project's GitHub page for updated versions; at the time
of this writing, 0.3.2 is the latest alpha release. Finally, make
sure your user can access serial- and USB-connected Arduino devboards by
adding them to the "dialout" group (note: you'll need to re-log in to
pick up the new group membership, and substitute "me" for your user name
in the last command):





me@mybox:~ $ wget https://downloads.arduino.cc/arduino-cli/
↪arduino-cli-0.3.2-alpha.preview-linux64.tar.bz2
***downloading***
me@mybox:~ $ tar -xjf arduino-cli-0.3.2-alpha.preview-
↪linux64.tar.bz2
me@mybox:~ $ sudo mv arduino-cli-0.3.2-alpha.preview-linux64
↪/usr/local/bin/arduino-cli
me@mybox:~ $ sudo usermod -a -G dialout me





Assuming /usr/local/bin is in your $PATH, you should be able to run
arduino-cli as any user on your Linux system.




Alternatively, if you want to build the Go package from source, you can
use the get function to download, build and install the source
package from the Arduino GitHub repository:



me@mybox:~ $ sudo dnf -y install golang
me@mybox:~ $ cd ; export GOPATH=`pwd`/go
me@mybox:~ $ go get -u github.com/arduino/arduino-cli
me@mybox:~ $ sudo mv $GOPATH/bin/arduino-cli /usr/local/bin/





Arduino from the Command Line




First, let's do some housekeeping. You need to pull over the current index of
Arduino "cores" and search for the core that supports your dev board. In
this first example, let's install support for the classic UNO board
powered by an ATMega AVR processor:



me@mybox:~ $ arduino-cli core update-index
Updating index: package_index.json downloaded
me@mybox:~ $ arduino-cli core search avr
Searching for platforms matching 'avr'

ID Version Name
arduino:avr 1.6.23 Arduino AVR Boards
arduino:megaavr 1.6.24 Arduino megaAVR Boards
atmel-avr-xminis:avr 0.6.0 Atmel AVR Xplained-minis
emoro:avr 3.2.2 EMORO 2560
littleBits:avr 1.0.0 littleBits Arduino AVR Modules

me@mybox:~ $ arduino-cli core install arduino:avr
*** lots of downloading omitted ***
me@mybox:~ $ arduino-cli core list
ID Installed Latest Name
arduino:avr@1.6.23 1.6.23 1.6.23 Arduino AVR Boards





That's it. You have everything you need to create a new Arduino project
for an Arduino UNO board. Now, let's create a project called myBlinky.
You'll also initialize and set up a Git repository to manage version
control, then make your first commit:



me@mybox:~ $ arduino-cli sketch new myBlinky
Sketch created in: /home/me/Arduino/myBlinky
me@mybox:~ $ cd /home/me/Arduino/myBlinky
me@mybox:~/Arduino/myBlinky $ git config --global
↪user.email "me@mybox.com"
me@mybox:~/Arduino/myBlinky $ git config --global
↪user.name "My Name"
me@mybox:~/Arduino/myBlinky $ git init
Initialized empty Git repository in /home/me/Arduino/
↪myBlinky/.git/
me@mybox:~/Arduino/myBlinky $ ls -la
total 16
drwxr-xr-x 3 me me 4096 Nov 22 10:45 .
drwxr-xr-x 3 me me 4096 Nov 22 10:45 ..
drwxr-xr-x 7 me me 4096 Nov 22 10:45 .git
-rw-r--r-- 1 me me 35 Nov 22 10:45 myBlinky.ino

me@mybox:~/Arduino/myBlinky $ cat myBlinky.ino

void setup()


void loop()


me@mybox:~/Arduino/myBlinky $ git add -A
me@mybox:~/Arduino/myBlinky $ git commit -m "Initial Commit"
[master (root-commit) ee95972] Initial Commit
1 file changed, 6 insertions(+)
create mode 100644 myBlinky.ino

me@mybox:~/Arduino/myBlinky $ git log
commit ee9597269c5da49d573d6662fe8f8137083b7768
↪(HEAD -> master)
Author: My Name <me@mybox.com>
Date: Thu Nov 22 10:48:33 2018 -0500

Initial Commit





Nice! The tool creates the project under the same Arduino directory
structure where the graphical tools would expect to find them allowing
you to flip between tools if you wish. It also creates a template .ino
file with the familiar setup() and loop() functions.




The empty Git repository was initialized, and you can see it created the
.git subdirectory where all the version data will be kept. Time to code!




Now, simply open up myBlinky.ino in your preferred editor—which in
the interest of maximum street cred is Vim of course. Never EMACS
(joking!)...seriously, use any editor you like (I hear Eclipse is
nice)—then type in and save a classic "hello world" blinky program.
Something like this:



// Simple Demo Blinker -MEH
#define PIN_LED 13

void setup()
pinMode(PIN_LED,OUTPUT);


void loop()
digitalWrite(PIN_LED,HIGH);
delay(500);
digitalWrite(PIN_LED,LOW);
delay(500);







Now, let's compile and upload it to the Arduino UNO. Use the board
set of commands to search for the upload:



me@mybox:~/Arduino/myBlinky $ arduino-cli board list
FQBN Port ID Board Name
arduino:avr:uno /dev/ttyACM0 2341:0001 Arduino/Genuino Uno





It found the board. Now compile:



me@mybox:~/Arduino/myBlinky $ arduino-cli compile -b
↪arduino:avr:uno
Build options changed, rebuilding all
Sketch uses 930 bytes (2%) of program storage space. Maximum
↪is 32256 bytes.
Global variables use 9 bytes (0%) of dynamic memory, leaving
↪2039 bytes for local variables. Maximum is 2048 bytes.





Compile was clean. Next, upload to the board using the upload
command, board name and port you discovered earlier:



me@mybox:~/Arduino/myBlinky $ arduino-cli upload
↪-b arduino:avr:uno -p /dev/ttyACM0





As is common with command-line tools, silence is golden. The upload
command completes, and the UNO is happily blinking away. You better lock
in this good fortune with a git commit:



me@mybox:~/Arduino/myBlinky $ git commit -a -m "It works!
↪First blink."
[master 35309a0] It works! First blink.
1 file changed, 7 insertions(+)





The -m option takes a commit message; it should be a note about what's
included in this commit. If you omit the message, git will open a template
message in a text editor (the default is Vim, but you can change it by setting $EDITOR).




Support for Third-Party Development Boards




Now for something a little more ambitious, let's try to use a
non-Arduino development board and walk through the steps of adding
a third-party core. This can be tricky even with the graphical user interface,
but it's pretty simple with arduino-cli. Let's target the very
popular ESP8266.




For starters, you need to add the third-party repository to a file so
arduino-cli knows how to locate the core. This is done with a file
named .cli-config.yml. You might think this should go in your
home directory or in the project directory, and you would be right to
think that. But, one quirk of this early release of arduino-cli is that this
file lands in the same directory where the arduino-cli program lives.
For now, this is /usr/local/bin, but keep an eye on the website, as this is
likely to change in future releases! Below, you'll add a new board
config definition. This file uses YAML format, so be careful to use
only spaces in the indenting. Edit (with sudo), and place the following text
in /usr/local/bin/.cli-config.yml:



board_manager:
additional_urls:
- http://arduino.esp8266.com/stable/
↪package_esp8266com_index.json





Now, like before, update the index and install the core:



me@mybox:~/Arduino/myBlinky $ arduino-cli core update-index
Updating index: package_index.json downloaded
Updating index: package_esp8266com_index.json downloaded





You can see that it found and downloaded the index for esp8266 cores. Good.
Now, let's download and install the core itself:



me@mybox:~/Arduino/myBlinky $ arduino-cli core search esp
Searching for platforms matching 'esp'

ID Version Name
esp8266:esp8266 2.4.2 esp8266

me@mybox:~/Arduino/myBlinky $ arduino-cli core install
↪esp8266:esp8266
Downloading esp8266:esptool@0.4.13...
esp8266:esptool@0.4.13 downloaded *** much omitted ***





Now, you can rebuild your myBlinky project for the esp8266 and upload
it. You first need to edit your myBlinky.ino and change the #define PIN_LED
to whichever pin has the LED. On my dev board, it's pin 2. Make that
modification and save it:



#define PIN_LED 2





After plugging in the esp8266 dev board, you again run the board list
command to try to find it:



me@mybox:~/Arduino/myBlinky $ arduino-cli board list
FQBN Port ID Board Name
/dev/ttyUSB0 1a86:7523 unknown





It detects it, but it can't determine what it is. That is quite common for
boards like the esp8266 that require a button push or special programming
mode.




Next, compile and upload after resetting your esp8266 board while
pressing the program button. Like last time, use the board name and
port discovered during the list operation:



me@mybox:~/Arduino/myBlinky $ arduino-cli board listall
↪|grep esp8266
Generic ESP8266 Module esp8266:esp8266:generic
(omitted long list)
me@mybox:~/Arduino/myBlinky $ arduino-cli upload -b
↪esp8266:esp8266:generic -p /dev/ttyUSB0
Uploading 252000 bytes from /home/me/Arduino/myBlinky/
↪myBlinky.esp8266.esp8266.generic.bin to flash at 0x00000000
..................................................... [ 32% ]
..................................................... [ 64% ]
..................................................... [ 97% ]
....... [ 100% ]





And, it blinks! Make another git commit and save your progress:



me@mybox:~/Arduino/myBlinky $ git add -A
me@mybox:~/Arduino/myBlinky $ git commit -m
↪"Blinking on esp8266 board"
[master 2ccff1d] Blinking on esp8266 board
5 files changed, 61 insertions(+), 1 deletion(-)
create mode 100755 myBlinky.arduino.avr.uno.elf
create mode 100644 myBlinky.arduino.avr.uno.hex
create mode 100644 myBlinky.esp8266.esp8266.generic.bin
create mode 100755 myBlinky.esp8266.esp8266.generic.elf





As you can see, it saves the compiled binary versions of the compiled
code in the project directory. You can add *.bin, *.hex and *.elf to
a .gitignore file if you wish to omit these from your commits. If you
do save them, you can use the -i option and the .bin file to upload a
specific binary.




Adding Libraries




Building on your success, you should download and install a library.
Let's up the blinky game and install support for some Adafruit NeoPixels
(aka WS2812B, PL9823 and so on). First, search for it using the lib
command, then download and install:



me@mybox:~/Arduino/myBlinky $ arduino-cli lib search neopixel
(omitting large list)
me@mybox:~/Arduino/myBlinky $ arduino-cli lib install
↪"Adafruit NeoPixel"
Adafruit NeoPixel@1.1.7 downloaded
Installed Adafruit NeoPixel@1.1.7





Now you need to modify the program; edit the .ino file with these
modifications:



// Fancy NeoPixel Blinky Blinker

#include <Adafruit_NeoPixel.h>
#define PIN_LED 14

Adafruit_NeoPixel strip = Adafruit_NeoPixel(1, PIN_LED,
↪NEO_GRB + NEO_KHZ800);

void setup()
strip.begin();


void loop()

strip.setPixelColor(0,strip.Color(255,0,0))'
delay(200);
strip.setPixelColor(0,strip.Color(0,255,0));
delay(200);
strip.setPixelColor(0,strip.Color(0,0,255));
delay(200);






Next, do the same compile and upload dance, after, of course, attaching
a NeoPixel or compatible LED to pin 14:



me@mybox:~/Arduino/myBlinky $ arduino-cli compile -b
↪esp8266:esp8266:generic
Build options changed, rebuilding all
Sketch uses 248592 bytes (49%) of program storage space.
↪Maximum is 499696 bytes.
Global variables use 28008 bytes (34%) of dynamic memory,
↪leaving 53912 bytes for local variables. Maximum
↪is 81920 bytes.
me@mybox:~/Arduino/myBlinky $ arduino-cli upload -b
↪esp8266:esp8266:generic -p /dev/ttyUSB0
Uploading 252960 bytes from /home/me/Arduino/myBlinky/
↪myBlinky.esp8266.esp8266.generic.bin to flash at 0x00000000
.................................................... [ 32% ]
.................................................... [ 64% ]
.................................................... [ 96% ]
........ [ 100% ]





And, you should have a colorful blinky—pretty slick. It's another good time to commit
your changes to capture your progress:



me@mybox:~/Arduino/myBlinky $ git add -A
me@mybox:~/Arduino/myBlinky $ git commit -m
↪"Blinky with NeoPixels"
[master 122911f] Blinky with NeoPixels
3 files changed, 20 insertions(+), 13 deletions(-)
rewrite myBlinky.ino (81%)





Using GitHub





Up to now, the git repository has been completely local in your project
directory. There's nothing wrong with that, but let's say you want to publish
your work to GitHub. It's pretty quick and easy to get started.
First, log in to github.com and create an account if you don't already
have one. Then, click the button to create a "new repository".



""


Figure 4. New Repository




Fill in the details for your project, and be sure to leave unchecked the
option to initialize the repository with a README. This is because you
already have a repository created, and you'll be "pushing" your local
repository to GitHub, so you want it empty.



""


Figure 5. Create Repo




After creating it, you will be presented with some helpful options on how
to push code into GitHub. You want the commands for "push existing
repository".



""


Figure 6. Push Existing Repository




Now let's do it! Follow the instructions to create a git "remote"
entry named "origin", which will represent GitHub. Then you will push, and
it will prompt you for your GitHub user name and password (substitute your
own GitHub URL, user name and password):



me@mybox:~/Arduino/myBlinky $ git remote add origin
↪https://github.com/sysmatt/myBlinky.git
me@mybox:~/Arduino/myBlinky $ git push -u origin master
Username for 'https://github.com': sysmatt
Password for 'https://sysmatt@github.com': ******************
Counting objects: 18, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (15/15), done.
Writing objects: 100% (18/18), 825.31 KiB | 5.00 MiB/s, done.
Total 18 (delta 4), reused 0 (delta 0)
remote: Resolving deltas: 100% (4/4), done.
* [new branch] master -> master
Branch master set up to track remote branch master from origin.





Now, if you browse to the repository on GitHub.com, you'll see all your
files and every one of your commits. You can travel back in time and
look at every revision. In practice, you can use SSH keys to eliminate
having to enter your password every time.



""


Figure 7. Commit History




Time Travel (aka Breaking the Laws of Physics with Git)




Time travel, you say? Yes indeed. Let's say you want to jump back in
time and review your version of myBlinky from when you had it working with
the Arduino UNO. It seems like ages ago. It's easy! You just need to identify
the commit id and "checkout" that version.




Use the log command to list all your commits:



me@mybox:~/Arduino/myBlinky $ git log
commit 122911f99dddce2dabbb251c3b640c8c7f9f98d9 (HEAD ->
↪master, origin/master)
Author: My Name <me@mybox.com>
Date: Thu Nov 22 21:22:59 2018 -0500

Blinky with NeoPixels

commit 2ccff1d7326b1523649510f24644c96df6dc6e12
Author: My Name <me@mybox.com>
Date: Thu Nov 22 11:42:02 2018 -0500

Blinking on esp8266 board
commit 35309a0c9e90668052abc9644f77f906ab57949c
Author: My Name <me@mybox.com>
Date: Thu Nov 22 11:09:44 2018 -0500

It works! First blink.

commit ee9597269c5da49d573d6662fe8f8137083b7768
Author: My Name <me@mybox.com>
Date: Thu Nov 22 10:48:33 2018 -0500

Initial Commit





It looks like the commit starting with 35309a0c is the one you're
after. Note: you can shorten the commit hash string to as few as
four characters, as long as it uniquely identifies only one commit.
Let's explore that version:



me@mybox:~/Arduino/myBlinky $ git checkout 35309a0c
HEAD is now at 35309a0... It works! First blink.
me@mybox:~/Arduino/myBlinky $ ls -l
-rw-r--r-- 1 me me 191 Nov 22 22:01 myBlinky.ino
me@mybox:~/Arduino/myBlinky $ cat myBlinky.ino
// Simple Demo Blinker -MEH
#define PIN_LED 13

void setup()
pinMode(PIN_LED,OUTPUT);


void loop()
digitalWrite(PIN_LED,HIGH);
delay(500);
digitalWrite(PIN_LED,LOW);
delay(500);






Now let's say you're done poking around, so let's time travel forward to the current
day and get things back to before you broke the laws of physics. In the
simple git repository, this means jumping back to the current commit in
the "master" branch:



me@mybox:~/Arduino/myBlinky $ git checkout master
Previous HEAD position was 35309a0... It works! First blink.
Switched to branch 'master'
Your branch is up-to-date with 'origin/master'.
me@mybox:~/Arduino/myBlinky $ ls -l
total 1332
-rwxr-xr-x 1 me me 13956 Nov 22 22:04
↪myBlinky.arduino.avr.uno.elf
-rw-r--r-- 1 me me 2640 Nov 22 22:04
↪myBlinky.arduino.avr.uno.hex
-rw-r--r-- 1 me me 252960 Nov 22 22:04
↪myBlinky.esp8266.esp8266.generic.bin
-rwxr-xr-x 1 me me 1082905 Nov 22 22:04
↪myBlinky.esp8266.esp8266.generic.elf
-rw-r--r-- 1 me me 436 Nov 22 22:04 myBlinky.ino





Nice! You're back to the NeoPixel blinky. You see, git stores all the versions
of your committed code under the .git subdirectory. This is actually
the real location of the repository. The files you edit are just the
"work area". When you jump around between commits, git is doing all
the magic of modifying the files in the work area. If you wanted to
jump back and start modifying the old version of code, you could create
a new "branch" to contain that work and move forward with an AVR and
esp8266 fork of your code. It's very powerful.




I've barely scratched the surface here. Git, GitHub and arduino-cli
are all quite comprehensive tools. I hope this article has given you a taste of
what's possible when you harness good programming workflows for your
Arduino projects.



Resources



No comments:

Post a Comment

Post Top Ad

<script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script> <!-- LINK AD --> <ins class="adsbygoogle" style="display:block" data-ad-client="ca-pub-7660338454331337" data-ad-slot="4207993195" data-ad-format="link" data-full-width-responsive="true"></ins> <script> (adsbygoogle = window.adsbygoogle || []).push({}); </script>