Home > General > ZephyrEye: XBee Bootloader

ZephyrEye: XBee Bootloader


A bootloader is like a program inside of a program.  Almost just like a supervisory program.  Normally, when a microcontroller starts up, it boots to what’s called the “Reset Vector”, which is at address $0000 (the dollar sign means it’s a hex number).  The Mega128 has 128KB, or $FFFF bytes, of program flash, so what we want to do with the bootloader is section out a chunk of program space that works separately from the main program.  That way, the bootloader can wipe out the main program, copy a new program in its place, without wiping itself out at the same time.

The Mega128 has fuse bits that allows you to boot to a different address than $0000 at startup.  So say, for example, you set the fuse bits to boot to $FC00 on powerup.  This points the processor to the program space at 2KB before the end of your memory.  You can put a program here that does whatever it feels like, and then given certain conditions, it will “jump” program execution to the main program, which is found at $0000.

So, in our case, we want the ZephyrEye to have a simple program that waits for a period of time before starting the main program.  Two things can happen during this wait period:

  1. If it detects a particular serial pattern during the wait period, then it knows to expect an incoming program transmission, initiates a reply, and begins downloading the new program.  The new program is written to flash, starting at address $0000.  Once the program reception is complete, the bootloader program jumps to $0000, which starts the main program.
  2. If the bootloader program doesn’t detect the correct serial pattern, then after the timeout it simply jumps to the reset vector at$0000.

Pretty straightforward, right?  A major advantage of using a bootloader is that it allows you to program your device anywhere.  In the case of the ZephyrEye, it also means you don’t have to plug in a serial programmer cable to it, or even own a serial programmer to reprogram it.  This easily cut the development time in half!  It makes it so much easier and quicker to test your code.

BASCOM-AVR provides sample bootloader code.  You can modify this to make it work however you want it to, which I did.  On the ZephyrEye Rev1, I decided to use a 38400 baud rate for the XBee, and I had it connected to UART1.  The BASCOM bootloader uses the XModem protocol, which checks to ensure program integrity during transit.  I won’t dive into that part of it (see repository for full bootloader code), but here are a few excerpts.

This first chunk sets up the bootloader with a few of its settings.

$crystal = 8000000
$baud = 38400

...

$regfile = "m128def.dat"
Const Loaderchip = 128

...

#if Loaderchip = 128                                     ' Mega128
 $loader = &HFC00                                        ' 1024 words
 Const Maxwordbit = 7                                    'Z7 is maximum bit                                   '
 Open "COM1:" For Binary As #1
 Config Com1 = Dummy , Synchrone = 0 , Parity = None , Stopbits = 1 , Databits = 8 , Clockpol = 0
#endif

...

Disable Interrupts                                          'we do not use ints

So, now we’ve got a serial port open on channel #1, with the UART correctly configured to communicate with the XBee modem.  Notice that interrupts MUST be disabled.  You can’t use interrupts in the bootloader, because the interrupt vectors are near the reset vector $0000, and will cause you to haphazardly enter certain routines in the main program.  Bad news bears.

$timeout = 200000                          'we use a timeout

Bretries = 5                               'we try 5 times
Testfor123:
Bstatus = Waitkey(#1)                      'wait for the loader to send a byte

Print #1 , Chr(bstatus);                   'return the received byte to confirm reception

If Bstatus = 123 Then                      'did we received value 123 ?
  Bkind = 0                                'prepare to receive flash program
  Goto Loader
Elseif Bstatus = 124 Then                  ' EEPROM
  Bkind = 1                                ' prepare to receive EEPROM data
  Goto Loader
Elseif Bstatus <> 0 Then
  Decr Bretries
  If Bretries <> 0 Then Goto Testfor123    'we test again
End If

For J = 1 To 10                            'blink LED to indicate start of normal program
 Toggle Portb.2 : Waitms 100
Next

Goto _reset                                'goto the normal reset vector at address 0

There’s a string or two of spaghetti code in there, but it’s pretty straightforward.  We’re going to try to get a byte 5 times (Bretries).  Each time we check, we’re going to call Waitkey(#1), which is blocking code.  It won’t go any further until it either receives a byte, or the timeout is reached.  You’ve also probably noticed that this bootloader program will accept EEPROM data, I won’t dive into that either but it’s not hard to figure out.

If it got the correct byte to expect flash program data (decimal value 123, also the ASCII character “{“), then it will jump to the “Loader:” label, and begin XModem reception.

If it didn’t get the right byte, then it retries.  After five retries, it blinks an led 5 times quickly to let the user know that the normal program is starting, and then jumps to the reset vector.

BASCOM has an internal programming option that lets you transmit the binary file via the bootloader directly from the IDE.  However, you can use other terminal emulators (such as HyperTerminal) to send the “{” character, wait for the response, and then use the “Send File” menu option.  After running into some trouble using Linux terminal emulators to communicate with the bootloader (I’m not sure why, has to do with lrzsz…), I wrote a C program (that I will soon add to the repository) that can be called from a Makefile to send the program as well.

You could make the bootloader initiation signal be something other than a character coming over the UART: a button held down at startup, another serial signal, or even read an EEPROM value.

Another cool way to use the bootloader is to call it from the main program.  Since we know the address of our bootloader, we could put a bootloader menu option in the main program.  When selected, all we have to do is jump from normal main program flow to the bootloader program location $FC00.  This is pretty handy, too, because then you don’t even have to power cycle to reload your program!

Hopefully this sheds some light onto how bootloaders work, and why they’re so nice.  As I always say, if you have the chance to choose between regular heaven and bootloader heaven, choose bootloader heaven.  It may be a joke, but if not, mmmm boy!

Advertisements
Categories: General
  1. No comments yet.
  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: