The new LUFA bootloader
So I’ve been feeling a little down lately, saddened by my lack of enthusiasm for developing new projects. Stuck in a rut, that sort of thing. A few weeks ago I thought I’d try something simple, new and fun to rekindle my love of developing — and who doesn’t love a good joke?
A long, long time ago I was thinking about Bootloaders for LUFA. Right now there’s three in the current LUFA distribution:
- A DFU class bootloader, compatible with Atmel’s FLIP software, or the open source dfu-programmer code. Fits into 4KB, robust, EEPROM programming support and popular. On the downside, you need special host software and drivers.
- A HID class bootloader, compatible with a modified version of Paul’s excellent cross-platform TeensyLoader command line utility. Fits into just 2KB on some devices, requires no non-standard drivers but it doesn’t really do EEPROM (unless you count my hack to sort of, kind of do it).
- A CDC class bootloader, compatible with AVRDUDE as it implements the fairly popular AVR910 protocol. This is the one appropriated (and modified) by Arduino for their Leonardo board, and the one everyone else seems most eager to use in their own creations. Sadly due to Windows being Windows it needs a special driver file which requires a paid signing certificate as of Windows 8 to function.
But a while back, I had plans for a forth. A crazy, crazy idea: bootloading…over MIDI. Actually, MIDI bootloading turned out to be a rather old idea, and one that’s actually popular in a number of commercial instruments, using MIDI SYSEX commands. My idea was to encode the data as a series of note commands with hard-coded delays — that way the end-user could reprogram a board by literally just playing a MIDI file sent from the manufacturer, with no device-to-host feedback being required (thus no special host software). No drivers needed either, since all modern operating systems include them just like they do for a number of other standard classes.
Unfortunately, revisiting this the other week I was left disappointed; it seems Windows 7 simply doesn’t do proper MIDI mapping to hardware MIDI devices any more, and I’m not the first one to be disappointed by it. Of course you can use dedicated software for it, but that would take away from the simplicity of the implementation. Bang goes that idea.
However, as OK Go say, All is Not Lost. I had another idea up my sleeve; none of than the humble Printer class. Yes, I’m being totally serious. Let’s skip ahead a bit and start with the end result:
That might look like just a humble printer from the 1980’s, but in actual fact you’re looking at what might just be the first bootloader-over-USB-printer-class in the world. Need to reprogram a device? Just “print” a new HEX file to it. Whee.
That’s not to say the journey was easy; first I had to re-visit the specifications for the USB Printer class. It’s actually a deceptively simple specification, if only because it’s just like the Mass Storage one: a thin wrapper defining a generic data transport and a few error feedback mechanisms, and a “data sent is implementation defined” style catch-all. That’s fairly common in the USB world for class specifications – in many cases it’s only the transport that’s covered, and the actual encapsulated data is just whatever the hell the host and client agree to send to each other. In the real world, that can mean PostScript, Epson Command Language, pre-rasterized images, who knows.
So, first I had to make the host see a USB printer device. That’s just a matter of setting the Device Descriptor’s Class, Subclass and Protocol fields, plus a basic implementation of the status and error reporting control requests. I really, really didn’t want to mess with custom printer drivers, so originally I just use my own custom IEEE 1284 description string, and forced the driver manually under Windows to one of the basic generic PostScript drivers it has inbuilt, since that’s a well known standard printer language.
Let me tell you; PostScript is NOT for the faint-hearted. I was hoping to see something vaguely structured with the plain text of the printed source visible so I could pick it out, but alas the received data was just a mountain – seriously, several kilobytes worth – of pure PostScript craziness with no obvious payload in sight. Luckily thanks to receipt printers and ye-olde daisy-wheel printers of yesteryear, Windows also ships with a “Generic Text-Only” printer driver that does away with all the crazy and just outputs exactly whatever text you print with no formatting at all. Success!
Well, partially – with the new driver, I could get a completely plain text representation of whatever I printer from the host (pictures didn’t work, obviously). However, I still wanted the drivers to be plug-and-play, since I wanted the end-result to be as streamlined as possible. After a bit of searching, I ended up finding the answer buried on (embarrassingly) a Microchip support forum post. Plugging in the magic IEEE 1284 identification string now gave me an automatically installing printer under Windows 7 with the desired generic text only driver.
But, what to do now? Should I invent a crazy command format, and have users “print” it to the bootloader? Is there a better way? Of course there is:
Yup, good old Intel HEX. In the AVR world (and in most embedded engineering circles) HEX files are king, and the file format is simple enough that making a parser for it isn’t too difficult. It’s also the native output format for most AVR build scripts and tools, and the one users are more familiar with.
I admit, the end result parser isn’t the prettiest code I’ve ever written, but it is (arguably) the most amusing. You’ve heard it here first folks; the world’s first AVR bootloader where you just compile, then print your HEX file in Notepad. On Linux, you can just cat the HEX file to the low level LPR printing subsystem to re-flash your board.
Sometimes the best jokes are the ones that turn out to have a somewhat practical use.