The avrgirl project: supporting STK500v2

This is the third post in a series about avrgirl.
The first is avrgirl project: an introduction.
The second is avrgirl project: supporting Arduino.

When programming Atmel® AVR microchips, there are several communication protocols available, and it's important to choose the correct one. Adhering to the correct protocol is essential in order for your programmer of choice to understand what you want it to do.

So far, avrgirl has had to support three of these protocols: STK500v1, STK500v2, and AVR109. In this post, we'll go into detail for one of these protocols in particular: STK500v2 and the resulting avrgirl release: avrgirl-stk500v2.

Even though there is already a package available in npm for STK500v2 (thank you Ryan), I thought it would be beneficial to write an alternative version for avrgirl, as I wanted the API to look and work quite different. Not to mention that I was pretty sure I'd learn a lot from the process of writing it from scratch using the datasheet. Read it if you're interested in seeing what kind of resources I work with when developing software for general electronics!

avrgirl-stk500v2 implements a protocol only, but it still works as a standalone package to use with any USB device which speaks STK500v2. This was by design. I tried to keep it as generic as possible.

The basics

STK500v2 is quite a verbose protocol compared to others, even STK500v1. Headers and checksums are required even to send a simple request or instruction.

Here is the general communication signature for most instructions:

Message Format

Responses from the programmer follow an identical signature.

Message start

As the name suggests, this byte signifies the start of a new message. The byte value is the same each and every time - it's 0x1B.

Sequence number

This number needs to be incremented by 1 for each message sent. Once the sequence value reaches 255, it should wrap around back to 0 again.

Message length

This tells the programmer how many bytes are in the main message body you're sending. It does not count the header bytes, nor the checksum. We supply the length in both MSB (most significant byte first) and LSB (least significant byte first) formats.


Always 0x0E.

Message body

Here is where you put your instructions for the microchip. It could be asking for its signature, writing a fuse, or a number of other things that the microchip supports.

The simplest example of a message body is getting a parameter value from the programmer settings: 0x03, 0x91 - the first byte is the 'get parameter' command, and the second byte is specifically asking for the major version number of the software running on the programmer.


This is a byte that is formed with logical shifts of all of the previous bytes in the message, including the headers. This is how we signify that our message is complete.


There are, as always, exceptions to the rule. Most programmers which use STK500v2 follow the protocol exactly. However, I have found at least one programmer (made by Atmel® themselves, gah) that does not.

The AVRISP mkII, for example, wants to skip both the headers and the checksum at the end. I only found this out through trial and error after some relative frustration. It was technically in the datasheet for the programmer, but I made the wrong assumption that the author had dropped these bytes from each example for the sake of brevity.

As a side effect, this brought in the notion of 'framed' and 'frameless' messages. If a message is framed, the message is wrapped in the headers and the checksum described in the previous section of this post. If it is frameless, only the message body is sent.

The end result that I implemented - requesting frameless mode is an optional parameter in the options object passed into the module when instantiated. The library takes care of the rest.


I decided early on that avrgirl would work with only more modern programmers which use USB for communication. To offer the best support possible, using either serialport or usb packages will work with avrgirl-stk500v2.

Summing up

avrgirl-stk500v2 is published on npm!

Currently available functionality:

  • Enter / leave programming mode
  • Read programmer / chip signatures
  • Write to EEPROM and Flash memory
  • Read from EEPROM and Flash memory
  • Erase chip memory
  • Read and write fuses
  • Get and set parameters

This list isn't every single thing you can do with this protocol (for example, it doesn't currently support reading locks), but the above methods are what you'd most commonly use.

If you'd like to test out avrgirl-stk500v2, please do! So far I have only had the opportunity to test it on two devices - the Arduino Mega, and the AVRISP mkII. I'd love your feedback, and feel free to open an issue if needed.

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.


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.


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


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 is a very different protocol to STK500. You send ASCII, and receive carriage return characters back in response when everything is ok!


Sent to chip:

p // enter programming mode  

Received from chip:

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


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!

The avrgirl project: an introduction

Hi! This is the first of a series of posts about the avrgirl project that I'm working on. If you'd like to follow along, subscribe to my RSS feed!

In my personal time, I work with microcontrollers a lot. I like to use them in fun, educational or just downright silly projects. Check out my Meow Shoes or P.U.R.R. bracelet for a couple of examples and you get the idea.

But what is a microcontroller? Simply put, it's a tiny computer, much simpler than your desktop PC or laptop. Microcontrollers consist of a processor, some memory and a collection of programmable peripherals to be used as inputs and outputs. They're ideal for use in low power situations. These days you'll find them in everything from kitchen appliances, to your car, to your computer keyboard.

Below you can see what a microcontroller can look like:

atmega 8 "ATmega8 01 Pengo" by Pengo - Own work. Licensed under CC BY-SA 3.0 via Wikimedia Commons

See the rows of pins that look like legs? They are the input/output peripherals that you can connect things up to! What sort of things? Lights, sensors, motors, you name it. Heard of Arduino? An Arduino has an Atmel microcontroller similar to the one above as the brains of the board.

Below illustrates a simple example circuit you can set up with a microcontroller chip:

hello world circuit

You can see a microcontroller in the middle of the breadboard. This is an ATMEGA84V-10PU, produced by Atmel. It has 8KB of program memory, 512B of EEPROM space, and 512B of SRAM.

The greenish white circle above the microcontroller is an LED, or Light Emitting Diode. A mini light, similar to what you'd see in appliances that have an 'on' or 'off' light indicator. The LED is currently shining bright, because I uploaded some software written in C to the microcontroller. This software contains the instructions needed to tell the microcontroller to send power to the pin our LED is connected to. When electricity is allowed to flow to the LED (via the orange wire!), it turns that energy into light. There's a resistor between the microcontroller pin and the LED, to limit the amperage so we don't blow up our delicate little LED. Nice!

The microcontroller uses external power (such as the battery pictured) to run itself and also anything connected to one of its pins. In order for this to be, the black and white wires you see in the picture are actually connected to the ground (black, top) and power (red, bottom) wires of the battery. This circuit is one of the simplest, more visual demonstrations of how a microcontroller works.

But hang on, I hear you say. How did you upload the software to the microcontroller chip? I don't see any USB ports!

Good question! So the answer is - it depends.

In the example above, I connected some extra wires to some special pins on the microcontroller, with the other ends then plugged into what's called a programmer. A programmer is a device that can take software from your computer, then translates and 'uploads' it to the microcontroller. We'll go into this in more detail in future posts in this series.

My programmer of choice is the AVR ISP mkII. It's made by Atmel specifically for their AVR microcontrollers, which I almost exclusively use. Here is what it looks like:

avr isp mkii programmer

The box looks pretty sweet too:

avrisp mkii box packaging

Sorta wish the programmer actually looked like that rainbow shooting robot though. Can't be helped.

There is a USB port at one end so you can connect a cable from your computer. The other end features 6 little slots for plugging wires into for connecting to some specific microcontroller pins. I used this programmer to 'flash' or upload software to the chip above. Once programmed, we can remove the wires and the circuit can function without the main computer or programmer connected to it.

Other microcontrollers are integrated into circuits with USB sockets alongside them. Probably the most well known example of this is any Arduino:

arduino uno

These setups make it way easier to upload software to the chip, as there is no extra external device that has to act as a middleperson. Pretty neat stuff. Fun fact: you can also use an Arduino as a programmer to program other chips, and even other Arduino's! Woooaah, we'll cover this at a later stage in the series. Hold tight!

We're missing one step last though. What is the software running on the computer that helps upload the pre-compiled program to the microcontroller? That, dear reader, is getting to the meat of the avrgirl project.

Atmel offers free official IDE software that allows you to program, debug and upload to any Atmel chip. It's called Atmel Studio.
The catch? It only runs on Windows. Alternative software packages out there range in price from $150 - $1500. Ouch.

If you're just fiddling with Arduino's, the free Arduino IDE will suit most needs nicely.

Which brings us to a free upload tool that programs Atmel AVR chips very effectively - AVRDUDE, or AVRDownloader/UploaDEr.

AVRDUDE is great for a number of reasons. Firstly, it's very solid (it was written over a decade ago by Brian S. Dean), available on all operating systems, and again, free. Secondly, the Arduino IDE uses AVRDUDE for their uploading functionality which I think says good things.

AVRDUDE works as a command line (CLI) software tool that you run in the terminal/shell. An example command would look something like this:

avrdude -v -P usb -c avrispmkii -p attiny45 -U eeprom:w:myeeprom.hex:i

Here is a sample of its output when run:

avrdude: AVR device initialized and ready to accept instructions

Reading | ################################################## | 100% 0.01s

avrdude: Device signature = 0x1e9206  
avrdude: safemode: lfuse reads as 62  
avrdude: safemode: hfuse reads as DF  
avrdude: safemode: efuse reads as FF  
avrdude: reading input file "./tests/eeprom.hex"  
avrdude: writing eeprom (32 bytes):

Writing | ################################################## | 100% 0.06s

avrdude: 32 bytes of eeprom written  
avrdude: verifying eeprom memory against ./tests/eeprom.hex:  
avrdude: load data eeprom data from input file ./tests/eeprom.hex:  
avrdude: input file ./tests/eeprom.hex contains 32 bytes  
avrdude: reading on-chip eeprom data:

Reading | ################################################## | 100% 0.03s

avrdude: verifying ...  
avrdude: 32 bytes of eeprom verified

avrdude: safemode: lfuse reads as 62  
avrdude: safemode: hfuse reads as DF  
avrdude: safemode: efuse reads as FF  
avrdude: safemode: Fuses OK (E:FF, H:DF, L:62)

avrdude done.  Thank you.

Pretty cool. And widely used by both hobbyists and professionals alike. In fact, I used it to upload the program of our simple LED circuit from earlier.

I also used it recently to create some software for the lovely Public Radio project by Zach Dunham and Spencer Wright. The radio was available for a short time as a kit to be soldered and assembled. The last step of the kit was to flash the (Atmel ATtiny45) chip on the circuit board with some custom settings, such as the radio station you'd like your Public Radio to be tuned to when you turn it on.

I set up a Python GUI (Tkinter) with some inputs for the kit maker to enter in, before clicking a 'Flash' button to program their radio with their entered parameters. The programming step was taken care of by making a hidden call to AVRDUDE.

This is what it looked like (note the very 'Python UI lib' look and feel):

maker GUI

The Python GUI worked quite well, as I could package it up for all platforms in a single executable file with the help of Pyinstaller.

There were a few caveats to this approach of using AVRDUDE though. In order to not fiddle around with shipping whole binaries or libraries (except for Python modules), we had to set and document a requirement that AVRDUDE was downloaded and installed prior to using the GUI program. This is okay, but not super optimal. I like a great out-of-the-box experience, and it made me a little sad. Another issue is that AVRDUDE is command line only. It then becomes necessary to run it within a child process, introducing complexity such as piping stderr around, and checking exit codes upon close of the child process.

AVRDUDE was written in C, which I'm not overly strong in. I know enough Python to get some cool hardware stuff done and like it a lot. However I am the most comfortable in JavaScript and NodeJS.

I do a lot of hardware projects in NodeJS, using anything from just bare node-serialport, to the fabulous johnny-five library. This has eventually led me to wishing for an AVRDUDE-like NodeJS library that supports all of the Atmel chips, Arduino boards, and most of the modern programmers out there.

I got a cheeky but warranted nudge from an engineer while at a conference earlier this year, after complaining about not having a NodeJS AVRDUDE alternative. "Someone should just write this for the NodeJS hardware community," I lamented. "Yes, SOMEONE," (with a chuckle and a meaningful look) was what I got in response.

And so avrgirl was born. Well, it's currently a work in progress. Here's what I'm aiming to produce out of this:

  1. Above all, a NodeJS alternative to AVRDUDE for programming Atmel chips
  2. NOT a direct replacement or port. Software diversity and having more choices is a good thing.
  3. Break the project into small, standalone parts to avoid a monolith
  4. Support for both scripted and CLI use
  5. Easy to install and require in your project
  6. Support most modern, commonly available USB programmers (skipping the very old non USB models)
  7. Support all common Arduino boards
  8. Support all Atmel chips for custom PCB project needs

And the name avrgirl? It stands for General Isp pRogramming tooL. It's pretty tongue-in-cheek, but I like it.

What's next?

The next post in this series digs into the first avrgirl module - supporting Arduino boards.

NDC's Internet of Things Day, Oslo, 2014

ndc magazine

This week I had the privilege of being invited to Oslo to speak at Internet of Things Day, put on by the organisers of the Norwegian Developers Conference (NDC). My talk was a technical one, aimed at developers who want to get started with protoyping devices, or those who are looking for a smoother workflow if they are already doing this.

I started with a show and tell of various devices I've created, followed by an introduction to Johnny-Five, the NodeJS library for interfacing with an Arduino.

By deconstructing a common activity tracking device, I delved deeper into the technical know-how behind how the audience could go about building and programming their own similar device.

The live coding demos I did throughout the talk kept things practical and contextual, I hope!

The slides can be found here.

NDC have already published the talks on their Vimeo channel, be sure to check all of them out! I have shared my talk below if you'd like to watch.

JavaScript army – making things walk, talk, and network to do your bidding - Suz Hinton from NDC Conferences on Vimeo.

I also had the opportunity to write a short article for NDC's magazine 'The Developer'. Keep an eye out for the November issue on their editions page, it should pop up there soon it's now available here.

The other speakers were really inspiring, and I walked away having learned a lot of new things!

The organisers behind the conferences NDC puts on are the most lovely, accommodating and smart people. They made me feel very welcome and encouraged me the whole way. I want to thank them for having me.


It all started with one of those projects you never actually start on, let alone complete. You know the type I mean.

My nemesis in this scenario is to make my own watch. Not to sell, just to make one for myself. I've bought a lot of hardware for it, but every time I'm satisfied with the new approach, something else comes along that seems cooler, or smaller, or easier. Check out this photo below of only part of the 'collection' I've acquired just trying to start on this thing:

collection of bits

I am sure I'll start on it one day (hahahaha), but this nemesis project did lead me down a particularly enjoyable rabbit hole recently.

There are three OLED screens in the picture above. These screens are pretty sweet. They run on minimal power, they're compact, and very bright despite the low power draw. Most of them use a common driver/controller, and I think they look really cool when used in wearables. The current end goal is to run one as a watch display, powered by an Arduino and a rechargable LiPo battery.

Normally when I want to play with a new piece of Arduino compatible technology, I look up the class to use within the really cool hardware library Johnny-Five. Johnny-Five is a NodeJS library which enables you to write JavaScript to interface with an Arduino and any hardware attached to it, such as sensors, screens, motors etc. It's really useful to create both prototypes and end products alike.

I jump into the docs and look around only to discover that there's no class for playing with OLED screens. Bummer! A quick look through the issues confirms this, and so I'm thinking I'll have to just write Arduino code and do the sorta clumsy save -> compile -> upload workflow when developing for Arduino projects.

However I've been wanting to contribute to a large project like Johnny-Five for a while now. It's been so cool to use this framework with a number of personal projects (not to mention Las Vegas Nodebots Day each year), and I wanted to see if I could help extend its use.

And so on and off for the past six weeks I've been attempting to code a drop in library for controlling OLED screens with JavaScript. What came out the other end was oled-js.

This is my favourite project I've worked on so far. There were a few reasons for this:

  • I learned a lot of things from it
  • it was the first library I've ever written
  • I had to consider how others would use it, and what features they might want
  • it was the largest project to date that I've worked on
  • I had no idea what the heck I was doing
  • I felt super motivated and engrossed in it the whole time

Here is a photo of using oled-js to display a cat:

cat oled

Displaying text:

text oled

You can also:

  • draw lines
  • draw individual pixels
  • draw filled rectangles
  • smooth scroll the display
  • dim the display
  • invert the pixels on the display
  • clear the display
  • turn the display on and off

Oled-js supports both I2C and SPI protocols. I'd recommend I2C, as oled-js uses the Arduino Firmata library (via Johnny-Five) and there is no current support for fast SPI within Firmata. My library just flips pins over the USB cable connection to get SPI happening, which is a huge bottleneck to getting those pixels updating on the screen as fast as possible. See the oled-js readme for more in context information on how to use each protocol.

If you have a need for it, have a play! If you break it, open an issue for me.

So what did I learn?

Oh man, a lot of things. I've never really taken the opportunity to explore or teach myself some of the basic things that go on closer to the metal of how computers work in general. This project really got me started down the path, which while mysterious at times is completely fascinating. I've never had a reason to stumble into this stuff before (I did not study computer science, where it is often dropped on you). I really had a fabulous time with it.

But it's time I passed on this stuff to YOU! So below, are some of the things I now know after publishing oled-js.

How do the pixels work on an OLED screen?

If you've ever worked with Photoshop or any other form of raster/pixel based image software before, this will be super familar to you. For starters, each screen has a set pixel dimension. For example, one screen I own is 128 x 32 px in size, but you can buy other sizes too.

So let's look at a 48 x 24 px screen. This means that there are 48 pixels stretching across horizontally, and 24 pixels spanning down. That's 1152 pixels available on the screen total. Each pixel can be referenced by an x and y coordinate, like a 2d vector. See the grid below for our 48 x 24 px screen:

screen 1

Pretty straightforward. Now, if you place some pixels on the screen, you can reference their locations pretty easily:

screen 2

The first pixel is located at x0, y0, or 0,0 for short. The second pixel is located at x7, y9, or 7,9 for short. Remember that we start counting across and down from 0, not 1.

In order to tell the screen what to display, we manipulate an object called a 'framebuffer'. This framebuffer is simply an array containing all of the pixel data. Each pixel is either a 0 or a 1. A 0 dictates that the pixel is 'off', and a 1 indicates that pixel should be 'on'. We send this framebuffer (either all of it at once or only part of it) as data to the OLED screen, which can then interpret it and display our pixels correctly on the screen. We prime the screen for the data with some other commands first, but that's not important to dive into right now.

Considering we already know that a 48 x 24 pixel screen contains 1152 pixels, we can expect that our framebuffer array would also have a length of 1152, right? Wrong! It's actually 144 in length instead. Wait, what? That makes no sense at all! Let me explain.

Our OLED screen accepts our framebuffer in the form of individual bytes. So, each item in our framebuffer array is a byte to be sent to the screen. A byte is simply a unit of digital information that computers understand. It is the smallest addressable unit of memory in most computers. That's pretty small! Working with bytes means that devices don't have to have massive amounts of memory installed in them, and it's more efficient to send information across a wire.

One byte contains 8 bits. Each bit is either a 0, or a 1. So a byte is binary! A visual example of a byte is 0010110.

Hang on just one tick, you say. If a byte contains 8 bits, and there are 144 bytes in our framebuffer, that would be 144 * 8, which equals... 1152! Shut the front door! Isn't that the same number as the total amount of pixels on our screen? Does this mean that one pixel is represented in our framebuffer as one bit? Yep, you got it.

Therefore, there are 8 pixels of data in each byte of our framebuffer. And remember how we said that a pixel is either a 0 or a 1? So is a bit! This is a really effective way of storing our information.

But how does this work? How do you figure out which byte in our framebuffer contains our pixel? This is where 'pages' come in, but we'll cover that in a second.

A byte as we just discovered, has 8 pixels in the form of bits. A byte of pixels is painted on the screen in a downwards direction, taking up only one column. The following pixels highlighted below are a representation of the first byte in our framebuffer array:

one byte

The byte above has no pixels turned on in it. Therefore, the byte would read 00000000 in our framebuffer array. A shorthand way of writing this would be hex format 0x00.

But what if we put some pixels in there?

screen 4

Above shows the bit values within our byte, when 4 pixels have been filled in. So what would our byte value be now? The answer is 00011101. Notice anything? "It's written in reverse to what I was expecting!" you say. Well spotted! Why? We'll cover this in more depth later, but essentially the positions of our bits need to be counted from right to left. Our OLED device actually dictates this. Look up most significant byte (MSB) vs. least significant byte (LSB) if you're curious to know more.

To sum up: pixels are painted on the screen in sets of 8 bits, within a byte. Each byte is painted in the next column over from the last, from left to right.

Because a byte is reponsible for writing muliple pixels in a vertical fashion, a concept known as a row or 'page' enters. Each page is 8 pixels high. Our first byte is in page 0. See the picture below to understand:

screen 5

In our example screen we're using, to write an entire row or 'page' of pixels will use 48 bytes. This is the same number as the width of our screen. The next row or 'page' will need the next 48 bytes in our framebuffer array to complete it, and finally the last set of 48 bytes will take care of the last row or 'page'.

I add another byte in the picture below, which is located in page 1:

screen 6

What number byte in our framebuffer is this new byte I added? You can count from left to right in the diagram starting from byte 0. It is byte 55.

To arrive at the same answer you can also assume 48 bytes in page 0, then start counting across from page 1. Add the result to 48 from there. Always subtract 1 of course, due to our index starting at 0.

Bonus point: what is the value of our new byte?

(the answer is 10111110)

Now you understand the basics of an OLED display and how it interprets incoming data.

A closer look at the framebuffer

Here is a 48 x 24 image we might want to display on the screen:

image with noop text written within it

And here is how it is represented as bytes in the framebuffer:

[0xFF, 0xFF, 0xFF, 0x7F, 0x7F, 0xFF, 0xFF, 0x7F, 0x7F, 0x7F, 0xFF, 0xFF, 
0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0xFF, 0xFF, 0xFF,  
0xFF, 0xFF, 0xFF, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF,  
0x7F, 0x7F, 0xFF, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF,  
0xFF, 0xFF, 0xFF, 0x0, 0x0, 0x0, 0x1, 0xFE, 0xF8, 0x0, 0x1, 0x0, 0x10,  
0xEF, 0x2D, 0x7F, 0x1A, 0xF8, 0xFA, 0xF8, 0x88, 0x88, 0xB9, 0xFF, 0xE7,  
0x5, 0x27, 0x1A, 0xF8, 0xFA, 0xF8, 0x88, 0x88, 0x99, 0xAD, 0x5A, 0x5A,  
0xF0, 0xB0, 0xF2, 0x70, 0x3C, 0x20, 0x4, 0xC2, 0xC7, 0xFF, 0xFF, 0xFF,  
0xFF, 0xFF, 0xFC, 0xFC, 0xFC, 0xFC, 0xFF, 0xFF, 0xFC, 0xFC, 0xFC, 0xFE,  
0xFC, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,  
0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF5, 0xE5,  
0xED, 0xFC, 0xFC, 0xFE, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]  

We know a couple of things looking at this. One is that any byte with a value of 0xFF indicates that it contains only white or 'on' pixels. This is because when you convert 0xFF hex to binary you get 11111111. That's 8 'on' pixels, as we covered earlier.

We also know that any byte in there with a value of 0x0 or 0x00 contains only black or 'off' pixels. This is because when you convert 0x0 hex to binary you get, yep, you guessed it - 00000000.

Let's convert another. Take 0x7F for example. Converting that to binary equates to 01111111. This byte contains 1 black or 'off' pixel, and the remainder are white or 'on'.

Easy peasy!

Manipulating bits and bytes

How do we find out the bit values within a byte using JavaScript?

Let's say we're trying to read just one bit within a byte. I do this in oled-js to look for a certain bit value in a response byte I can read from the screen itself. This specific bit acts as a flag to let me know if the chip is busy or ready for more data. 0 is ready, 1 is busy.

Firstly, we need to know the position of that bit (0-7). Let's say, we want to read the bit in position 5. Position 5 is the third spot from the far left bit in our byte (we covered this briefly earlier).

Now that we know the position, we need to apply a bitwise operation to find the value. Bitwise is a very broad and complicated topic, so we'll just stick to what's happening in this specific task only. I highly recommend reading the basics on Wikipedia, then following up with the MDN explanation for the JavaScript implentation.

Bit shifting against a mask is the most common way to pull out a bit's value. Shifting a byte's bits right once looks like this:

shift right

As you can see above, a 0 is pegged onto position 7, every bit moves right 1 spot, and the bit in position 0 actually drops off and is discarded.

In this example, we're going to shift the bits in the byte right until bit 5 is sitting at position 0. You'll see why in the next step.

Let's work with this byte - 01100101, or 0x65. We'll shift the bits over 5 places so that the bit at position 5 is now sitting at position 0:

var byte = 0x65; // 01100101  
var newByte = byte >>> 5; // 00000011  

A total of 5 zeros will now be shifted in from the left, forcing the bits to the right. Bit 5's position is now position 0.

We're next going to use the '&' operator to 'compare' this bit against the binary mask of 1. The '&' operator in bitwise will return a 1 if the bit in line with it is equal to 1. It will return a 0 if not equal to a 1. Comparing anything against a 0 will return a 0. This may not make sense if you have not read the suggested resources mentioned earlier.

var byte = 0x65; // 01100101  
var newByte = byte >>> 5; // 00000011  
var busy = newByte & 1; // 1  

The comparison can be represented visually. The top number is the mask (1 in binary), and the bottom value is our shifted byte.

& 00000011

As you can see, the result is equal to the binary representation of 1. So our busy byte is equal to 1 (the chip is busy!).

This exact approach can be used to look up the value of any pixel in your framebuffer. If you can find the byte it is in, and the bit position (both calcs are pretty simple), you can use the above method to pull it out.

OMG you made it to the bottom of this

  • oled-js is published on npm!
  • there was a tonne of stuff I needed to learn along the way to write this library - embrace those moments when you have no idea what you're doing.
  • teach others what you know if you can, don't keep that fresh new knowledge to yourself
  • the grid for the screen diagrams came from here - really cool canvas app
  • thank you to Rick Waldron and the other amazing authors of Johnny-Five.
  • you are awesome.

Try before you buy - a 3D printed extruder test

Sometimes it's hard to know if a certain upgrade is worth the investment, especially when you have a bit of a Frankenstein 3D printer (in fact, 'Frankie' is the new nickname for my printer). For a while I was kicking around the idea of buying the rather sleek and beautifully simple Printrbot aluminium extruder that they've been sending out with the new Printrbot Simple Metal models. It was $55 bucks though, and I've sunk a fair bit into my printer over the last 18 months. I love the Printrbot folks though, and thought I'd do a quick 'try before you buy' kinda approach.

So what does this exactly mean? Well, Printrbot are a fabulous company for a number of reasons; one of them being that they release to open source a lot of their design files, and their flavours of Marlin firmware used on the printer controller boards. I thought if I could 3D print their extruder model, I could test out just how good it was.

Why did I think it was better? Just looking at the design I could see that the filament feeding process was a lot easier when changing it out. The previous 2 extruder designs have made it more fiddly to load and unload filament. When you're changing filament mid print, you want to do it as quickly as possible, and without disturbing any alignments of anything. The Printrbot extruder was also comparable in design to others such as the Replicator 2, and Type A Machine Series 1. I'd seen some really nice results come out of those more expensive machines, and was optimistic about Printrbot's minimalistic solution.

After hunting around, I found that gkrangan had already created the extruder model from the plans, ready to download. The other thing I needed was a new base plate to mount the extruder on, as the current holes did not line up to secure everything down. I found that also, from G0ldmember.

There was nothing else to do but start printing!

This is a quick overview of how to process went:

printing piece

printing piece

printing piece

printing piece

The final assembly:

printing piece

A video of the initial test, before securing it down better:

The verdict - it is AMAZING. Well worth the struggle to get it to fit my poor Frankie. My prints are now much better quality. I also got approximately 20 hours out of this extruder before it started biting the dust a little. Printing the parts for it in ABS instead of PLA would have helped it last longer I'm sure.

Based on this feedback, I went ahead and bought the shiny aluminium version from Printrbot. I'm excited to swap it out when it arrives!