The avrgirl project: supporting Arduino

avrgirl logo + arduino logo

This is the second post in a series about the avrgirl project. I highly recommend reading The avrgirl project: an introduction first.

The first part of avrgirl I wanted to tackle and complete was Arduino support. There were a couple of reasons for this:

  1. The Arduino platform feels like it's the most popular use case by developers for Atmel chips, at least in the NodeJS community.
  2. I am more familar with the Arduino platform than non Arduino integrated chip boards/projects.
  3. There are some exising tools in the NodeJS ecosystem that I knew I could either use or learn from.

In the end, I wrote a resuable, standalone module called avrgirl-arduino. This will stand as the foundation for Arduino support in avrgirl.

Why bother?

The Arduino IDE exists to provide users with a place to write, compile and upload code, so why write a NodeJS module that uploads code to Arduino's?

  1. Not everyone wants to use the Arduino IDE. It's a great piece of software, but we're all used to our own workflow and tools when coding/compiling. Alternative choices are good to have.
  2. Shipping repos and libraries with pre-compiled Arduino sketch files is a genuine use-case. Being able to program an Arduino without having to direct a user to install the Arduino IDE makes for a better experience for those using your library.
  3. Using Makefiles to compile your Arduino sketch upon file save can go hand-in-hand with then using avrgirl to upload to the Arduino. Think of using something such as gulp to perform this and things feel nicer already. Leo seeks to accomplish something of this nature on the CLI, for example. I took some inspiration from that ecosystem when considering how avrgirl could be dropped into larger workflow toolsets.

Research

A few questions needed answering first:

  1. Which Arduino boards should be supported? A: as many as possible, start with most common
  2. Do all Arduino boards use the same USB interface method? A: yes
  3. Do all Arduino boards follow the same communication procotol? A: no
  4. Are there any existing NodeJS packages out there that can help do some of the required tasks? A: yes

All USB enabled Arduino's can have a connection opened to them via node-serialport. This is really fortunate because node-serialport is a fantastic NodeJS package. This was the most straightforward part of writing avrgirl-arduino.

However, not all Arduino's feature the same microcontroller chip, and therefore can differ in communication protocols. An Arduino will generally follow one of three protocols:

For example, the Uno follows STK500 v1, the Mega follows STK500 v2, and the Leonardo follows AVR109. This is largely dictated by which Atmel chip is used on the Arduino board. It's important to do your research and only try to speak the 'language' that the chip is set up to understand. I lost some time (and hair) to this!

Very fortunately, the packages stk500, stk500-v2, and chip.avr.avr109 exist on npm. They were a really good starting point to do a lot of the heavy lifting. I ended up forking one to make some big changes to just for avrgirl. I then opened pull requests on the other two featuring some subtle changes to improve ease of use in avrgirl, which were later merged (thank you Elijah and Eric/Ryan!). Open source <3

Communication Protocols

Most chips follow some variation of 'send command code to chip - receive response code from chip'.

STK500 v1

STK500 v1 works with one byte representing one command or parameter. It is 'frameless' style communication. This simply means that you do not need to prepare the chip with a heads up string of details such as "I'm about to send you a command" and "the command length is x" before you send the command itself.

Example

Sent to chip:

0x50 // enter programming mode  

Received from chip:

0x10 // 'OK'  

If you are sending more than just one command byte, you'll need to notify the chip when you end the sequence of bytes.

Sent to chip:

0x55 // load address  
0x00 // address (MSB)  
0x00 // address (LSB)  
0x20 // signify end of command sequence  

Received from chip:

0x14 // 'I got the whole message'  

STK500 v2

STK500 v2 is similar in command structure, but a little more formal than STK500 v1. Commands are framed with more information for the chip.

Both sent and received commands follow this format:

Message Format
MESSAGE START
SEQUENCE NUMBER
MESSAGE LENGTH
TOKEN
MESSAGE BODY
CHECKSUM

Example

Sent to chip:

0x1B // message start  
0x01 // sign onto chip  
0x00 // sequence number  
0x00 // Message length (MSB)  
0x01 // Message length (LSB)  
0x0E // token  
0x01 // message body ('sign on' command byte)  
0x14 // checksum  

Received from chip:

0x1B // message start  
0x01 // command received (sign onto chip)  
0x00 // response length (MSB)  
0x0B // response length (LSB)  
0x0E // token  
0x01 // command answer (sign on)  
0x00 // 'OK'  
0x00 // signature length (MSB)  
0x08 // signature length (LSB)  
AVRISP_2 // signature of device  
0x4A // checksum  

AVR109

AVR109 is a very different protocol to STK500. You send ASCII, and receive carriage return characters back in response when everything is ok!

Example

Sent to chip:

p // enter programming mode  

Received from chip:

'\r' // 'OK' (carriage return)

Challenges

There were a couple of interesting things that had to be solved along the way.

Leonardo reset issue

Arduino Leonardo (and compatible) boards use the ATmega32u4 chip. This chip is pretty neat, because it can create its own virtual com port, rather than having to rely on an external FTDI chip to handle the USB connection on the board.

In order to reset the device into bootloader mode (so we can start sending commands to it), you need to establish a serial connection with it at a baud rate of 1200, then immediately disconnect. The chip will then hang out in bootloader mode for around 8 seconds, waiting for a first command. If it doesn't receive anything, it then just starts running the script that is currently uploaded to it.

I wrote the reset functionality mostly without a hitch, but hit a snag with node-serialport. In some cases (sometimes operating system related), calling serialPort.close() doesn't truly close the connection. This means that it's possible for the board to never reset correctly. No reset = no bootloader mode, and you're going to have a sad time trying to program the chip.

One thing that works however, is when you end the running NodeJS process, the serialport will close properly. I observed the reset happening when I exited my process after connecting at 1200 baud. Moving the reset script to a separate node file and running it as a child process which exits after 'closing' the serialport worked a treat. A funny little hack.

Keeping the barrier to entry low

Choosing the level of abstraction of the tool you're designing can be difficult. I went back and forth in my head many times, trying to settle on something that felt good. You want to give advanced consumers of your tool a certain amount of control, but keep some of that control optional so as to not deter beginners either.

An example of this is something like knowing the port address that the Arduino is connected to. I really like that johnny-five doesn't require a user to know ahead of time which port their Arduino will be plugged into. So in similar fashion, I added an auto 'port sniffer' in the event that a developer using avrgirl-arduino does not supply the port to find the Arduino on. The option to specify the port is still available, howver it is not necessary in order to get up and running. I think that's a nice balance.

I was able to briefly test out avrgirl-arduino with an Arduino and NodeJS novice recently. They arrived with an Arduino and their laptop at a hack night I was attending. One of the first steps needed to use johnny-five with an Arduino is to have the StandardFirmata sketch uploaded to it. They didn't have the Arduino IDE installed, and we were mostly just messing around in the terminal, npm install-ing stuff. We quickly installed avrgirl-arduino as a global package, and ran the CLI version of the tool to upload StandardFirmata. I had published avrgirl-arduino to include a version of StandardFirmata compiled for all the Arduino types supported, thinking it may come in useful for quickly testing out avrgirl-arduino when people first install it. We pointed avrgirl-arduino to the correct StandardFirmata sketch file, and it uploaded the sketch in a matter of seconds. We then got back to the business of hacking on robots. This was great validation, and allowed me to be in the shoes of a beginner, seeing their experience first-hand.

It is humbling to see your tool get used from that perspective. It's an opportunity to find any points of friction that you can improve on.

What's next?

avrgirl-arduino is published on npm. If you have use for it, please give it a try and let me know what you think.

avrgirl is getting support for some programmers! First up is the AVRISP mkII. That's the next post in this series.

Thanks for reading!

Suz Hinton
Hi! I'm a web developer and tech enthusiast living in Brooklyn, NY. I like to work on weird stuff. noopkat.com
comments powered by Disqus