Here you will read the story of my attempt to create a serial bootloader that is robust enough to be used over both wired and wireless connections to program HUGE programs (>30k code words). While not drop-in compatible with the Arduino IDE (please help out!), this wireless bootloader will work with Arduino Sketches (with an extra piece of Windows software).
How to setup and use this thing:
Things you need:
The following tutorial was written for the ATmega168 but has been updated to work with the ATmega328 as well. This is perfect for the Arduino Mini Pros.
I need your help! I am a very bad Visual Basic scripter, not a Windows programmer. Screamer (the software that runs on the computer) currently only works under Windows. But the command structure should be portable to anything. I need help from someone to write a python script or other program that allows a command line interface to this bootloading system. Call it ScreamerCommand or some such. That way we can run Screamer from a command line, allowing implementation from Arduino IDE or from Programmer's Notepad. If you don't have VB, don't worry. The VB files listed above are readable with any test editor (search for cmdDownload_Click).
I have a printf debug style of programming. I'll program a small change, upload it to my target, then debug the program flow using printf statements. This requires two things : a good serial link, and a quick and easy way to upload new firmware.
When I decided to build a vehicle for the Autonomous Vehicle Competition, I realized it would be rather painful to be working on the rover during field testing. A laptop might get you outside, but when the rover gets more than a few feet away from you, I'm lazy and don't want to walk over to the bot just to plug in my 25' programming cable. A tethered robot is no fun. We've got these XBee units, and I keep reading about wirelessly bootloading an Arduino, so why not just use this wireless bootloader?
The problem arose when I started googling around. It seems like many people are having timeout issues with the stock stk500 serial bootloader. It simply wasn't designed to be used as a wireless bootloader. I tried. I really did! All I ever got was errors or partial loads that timed out:
avrdude.exe: stk500_getsync(): not in sync: resp=0x59
avrdude.exe: stk500_disable(): protocol error, expect=0x14, resp=0x59
In the end, I scrapped the avrdude+stk500 serial bootloader in place of my own. The resulting bootloader is lightning fast over a wired connecting (the terminal window is extremely handy!), pretty fast over a wireless connection (can't get around the XBee overhead), and able to program any size program (tested using a 14,000 code word program - around the max size of the code space including the bootloader on an ATmega168).
That's great and all, but how do I use this thing?
How to setup and use this thing:
You will need to configure the remote XBee module (connected to the AVR) and the base XBee module (connected to the computer) slightly differently. The Digi X-CTU software is a handy windows application to configure the large amount of settings on the XBee. To download, try this link or search for "x-ctu download". If you really can't find it, we have version 220.127.116.11 (25MB!) here.
Plug the first XBee unit into the XBee-Explorer and attach it to the computer. You may have to install FTDI Serial drivers. Now you need to figure out what COM port it got assigned to:
Right click on My Computer, then Properties. Click on the Hardware tab, and finally on the Device Manager button. You can also get to this by running "devmgmt.msc" from the Run command or a command line prompt. Once the device manager is open, expand 'Ports'. You will see the USB Serial Port that is the XBee Explorer. COM 109?! Wow. That is a bit high. For Screamer to work, you need to have a COM port that is 1 through 4. To force XBee Explorer from 109 to 3, right click on the USB Serial Port (COM109), and click on Properties.
Once complete, open the X-CTU software.
If you've got fresh XBee units, by default, they are set to communicate at 9600bps. Be sure to select your correct USB COM port!
Now click on Modem Configuration tab and click 'Read'. If you're firmware version is not up to date, I recommend choosing the latest version and upgrading both modules.
I chose a new PAN ID so that my XBees would not interface with any other default XBees in the area. Pick any ID that you like and can remember. You'll have to set the same PAN ID on the second module.
Scroll down and set the serial interface rate to 19200.
Scroll down and set DIO3 Configuration to '5 - DO HIGH'. This will cause the DIO3 pin to act as an output and toggle whenever the base unit sees a change in its DIO3 pin.
Set the I/O Output Enable to '0 - Disabled'. This setting will suppress the XBee module from outputting serial bytes every time the DIO3 pin changes.
Finally, you will need to set the I/O line passing 'Input Address' to FFFF. Click on write and make sure the settings are written successfully.
Now remove this XBee unit (from now on, it's the remote unit) from XBee Explorer and set it near your XBee breakout board and sockets.
Attach a second XBee unit to the XBee Explorer. I hot swap (I don't unplug the Explorer from USB) because I am a bad, lazy engineer.
Click Read to pull in the contents of the new module's settings.
Set the PAN ID to match the first unit's PAN ID.
Scroll down and set the Serial Interface to 19200bps.
Scroll to I/O settings and set DIO3 to '3 - DI'. If these images look a bit different then your X-CTU, you've probably got a different firmware version loaded onto the XBee. Probably won't make a difference so don't worry!
Set the DIO Change Detect to 8. This will monitor 0x08 or pin 3 (in binary: 0000.1000) for any changes. Now click write and be sure the parameters are written successfully.
Leave this XBee unit in the Explorer - this is your base unit. Now whenever you power up these XBee units, they will search each other out and automatically form a direct point-to-point serial link!
You'll need to download and program this hex file onto an ATmega168. Connect your programmer to the AVR. If you're unsure how to attach a programmer to an AVR, we've got the tutorial for you over here. From a command line, navigate to the directory that contains Wireless_Bootloader_ATmega168.c and the Makefile and type:
(This will compile the bootloader so that you have a current HEX file)
(This will use attempt to use the parallel stk200 programmer over the LPT port)
Be sure that everything completes without errors (as shown above). This version of the bootloader currently only works with the internal 8MHz oscillator but you can tweak the make file to your heart's content. I know programming it can be tricky, but once you have successfully loaded the bootloader onto the AVR, you'll never have to do it again!
One of the great features of this bootloader is the remote reset trick. This is based on Limor's Arduino wireless bootload tutorial.
Solder a jumper between the RTS pin and DIO3 on the XBee Explorer.
Now we need to attach the various lines from the remote XBee to your target ATmega168. There are 5 lines that need to be wired:
Here you can see the five wires soldered into an old prototype I had sitting around. You should really use a XBee Breakout Board and XBee sockets. Solder in the XBee sockets so that the XBee can live happily in the breakout board. Solder five wires from the five pins on the breakout board (DIN, DOUT, 3.3V, GND, DIO3). Remeber, XBees run at 3.3V not 5V so you will need to regulate down if your system runs at 5V.
Pin on XBee / Pin on ATMega:
The DIO3 will toggle every time the RTS pin is wiggled on the base XBee. This is used to reset the ATmega and kick off the bootloader. In order to make this work, you need to put a 0.1uF in between the DIO3 pin and the reset pin on the ATmega168. This will prevent the XBee from holding the ATmega in the constant reset state.
The above image shows the 0.1uF cap wired inline with the Reset pin of the ATmega.
Download Screamer and unzip to one directory. Run Screamer-v2.exe. If windows yells at you about missing MSCOMM32.OCX or comdlg32.ocx, these extra VB files are included in the zip.
Now power your remote unit. Make sure the XBee Explorer is hooked up and happy. From Screamer, open blink-v10.hex. This is a demo program that demonstrates blink and printf commands. Select the correct COM port in Screamer (whatever your USB port may be). Then hit download! Screamer should reset the remote unit setting off the bootloader and the unit should start downloading blink-v10.hex.
Congrats! You've made it through. If you're now bootloading wirelessly, enjoy! If you'd like to learn more about how we cobbled this thing together, keep reading.
I'm not entirely sure how avrdude works. It might use checksums, and it might use timeout control, but I could not make a solid download work no matter how I modified the original STK500/Arduino bootloader. And since I'd rather not dig into the avrdude source, I wrote my own wireless bootloader to work with my own Windows program (complete cheating).
That's a breadboard with ATmega168, a parallel port connection to program the bootloader onto the AVR, a serial connection for testing a wired serial download, and two XBees for wireless downloading. Madness.
The SparkFun Wireless bootloader does a couple of things:
Binary only data:
Why transmit more than we need to? I rip out all the extraneous parts of the intel hex file on the computer side and transmit only firmware codewords.
Open any HEX file. You'll see it is visible ASCII characters.
Historically, bootloaders will transmit the line length, memory address, whether or not it is the last line of the file, ~16 bytes of firmware, and a checksum. For each line. Old bootloaders would transmit 43 bytes to convey 16 bytes of firmware! This is wasteful.
The AVR needs 128 bytes to program a page. Screamer strips out all the extra information and transmits a total of 133 bytes to convey 128 bytes of firmware.
Checksums protect the wireless link from corruption. If the remote unit receives a payload where the checksum is not 0, it will reject those 128 bytes and request the payload to be sent again. The SparkFun wireless bootloader uses a standard 8-bit checksum for each payload of 133 bytes. This might be a bit on the low side (16-bit would be more protection) but I haven't experienced a false positive yet.
Control characters and timeout:
The problem with many bootloaders is they are too inflexible to deal with the latency often associated with wireless links. RF is not perfect and packets can be lost. A good wireless module will buffer bytes on either end with a protocol that attempts to assure delivery. What this means is the XBee modules might have to transmit a few bytes, a couple times before they are successfully delivered to the opposite end of the link. All the while, you are throwing tons of data at their serial pins expecting data to arrive in a timely fashion. The humble XBee units are buffering all sorts of stuff, making sure the data gets where it needs to be but the protocol overhead causes time delays between delivery of data. Any RF link will make a fast data connection stream seem irregular in throughput.
So our bootloader doesn't expect data to arrive in a regular manner. The remote unit will happily sit and wait for data. In the current version, Wireless_Bootloader_ATmega168.c waits for enough time for 15 characters to come through before it starts calling the transmission a timeout. If the XBee units (try hard! but) fail to deliver the payload that Screamer sent out, the remote AVR will ask for the last line to be resent. It's sort of a check-in/check-out system. Even if two XBee units are in a harsh RF environment, if they have thick walls between them, or if they are very far from each other, this bootloader will do its best to get the firmware there, correctly, every time.
Jumps directly to terminal window:
This is one of the great features of this bootloader. If you've used Arduino and you've been annoyed with the serial port view window (Bad java script! Bad!), you'll be pleasantly surprised by the Screamer terminal window.
No need to worry about closing hyperterminal every time you want to re-program, Screamer automatically closes the port before starting a new download, then re-ports the port in the terminal window. Seamless debugging!