Maple Bootloader(s)

The firmware which allows the Maple to be reprogrammed via a USB connection. Every Maple board comes programmed with this by default, and it is not overwritten by regular programs (it lives lower in the Flash memory and only runs when the chip is reset).

Check out the latest source code version:

git clone git://github.com/leaflabs/maple-bootloader.git

Visit the github development project: http://github.com/leaflabs/maple-bootloader

Bootloader Schemes Explained

Maple Rev 3 and Rev 5 (Rev 5 is the version currently shipping) represents a drastic remake of the core library as well as the upload process. Thes changes to the bootloader, were implemented to resolve platform-specific issues on Windows. Before delving into how the Rev 1 bootloader worked and how the Rev 5 bootloader works now, we’ll discuss the features common to each and touch a bit on the Arduino setup.

This is a fairly involved explanation, with a lot of details that are likely only interesting to a few. If you just want to get the rough idea, skim this article. If you want to start hacking on the bootloader, get in touch with us to get even more info on how this all works. And finally, you can always check out the code at github!

Arduino

Arduino is based off of AVR series microcontrollers, most of which lack USB support. Thus, boards like the Duemilanove add USB capability via an FTDI USB-to-Serial converter chip. This chip interfaces with the AVR over an RS-232 serial interface. When you plug an Arduino into a computer, only an FTDI driver is needed. Since the FTDI chip is separate from the AVR, you can reset the Arduino without closing this USB connection with the FTDI chip.

To program an Arduino, the host machine sends a command over the USB pipe (reset DTR) which in turn resets the AVR. The AVR will boot into a bootloader, which waits for a second for any upload commands over serial. The host machine can either send those commands, or do nothing. If it does nothing, the AVR will quickly jump to user code and off you go. The whole process is quick, the bootloader doesn’t live for very long, and will exit almost immediately if no upload commands are received.

Maple Rev 1

Maple is based off the STM32 (ARM cortex M3) series chips, which do have embedded USB support. Thus, Maple doesn’t need the extra FTDI chip. Firmware is uploaded via the standard DFU protocol (also used by iPhone and openMoko). Since DFU is a standard, there is no need for custom software running on the host to upload the firmware. Any DFU compliant program will work. The maple ide is based around dfu-util, openMoko’s DFU utility. Using DFU came at a cost, however. The USB port must additionally implement a separate serial port at the same time (we use the CDC ACM class for serial functionality).

Maple Rev 1 attempted to run both DFU and CDC ACM devices simultaneously on the USB peripheral. On Linux, this worked great. The OS would service the DFU driver during uploads, and the CDC ACM for serial port transactions. There was no reset necessary for uploads. No waiting. The bootloader was always running the background, ready to receive commands.

The problem was that only Linux did this. Windows refused to attach more than one driver to a single USB device without repackaging the DFU and CDC ACM into a single IAD Compound Device. It’s not terribly important what this means, except for two things.

  1. Four drivers were necessary to make everything work.
  2. IAD is not supported by OS X.

Mac, on the other hand, only supported Compound USB, a different trick that is not supported by Windows. While a perpetual background bootloader was attractive, it became clear, after much toiling, we were going to have to write some custom drivers across several platforms to make everything work this way.

Maple Rev3/Rev5 - DFU

Maple Rev 3 takes a completely different tack, more along the lines of Arduino. In Rev 3, the device resets into bootloader mode, which stays alive for a few moments to receive commands, and then jumps to user code. The bootloader is implemented as a DFU device – just a DFU device, no serial port. This requires one driver for Windows (drivers/mapleDrv/dfu in the Windows IDE directory). As part of the libmaple library, user code is automatically supplied with serial support via some behind the scenes work that happens automatically when you compile (setupUSB() is appended to setup()). This user mode code only implements a CDC ACM class USB device, giving you functions like Usb.print(). Separating these two modes fixed the driver issue, required no complicated compound USB device nonsense, and works well across platforms, requiring only two drivers (serial and DFU) on Windows.

However, it is no longer possible to upload code at will, since there is no bootloader quietly listening in the background. Instead you have to reset the board, then initiate a DFU transaction. This reset is performed automatically by the IDE by sending a command over the USB serial port. You can generate this reset on your own using a Python script or some other scheme. All you need do is:

  1. Pulse DTR (high and then low, so that you’ve created a negative edge)
  2. Write “1EAF” in ASCII over the serial pipe. This will cause Maple to reset. Only the first 4 bytes after a negative edge of DTR are checked for this command, so it’s important you actually create a negative edge, rather than just ensuring DTR is low.

After the reset, the host OS takes a few moments (.5-2 seconds) to re-enumerate the device as DFU. This delay is unpredictable, and its the reason the bootloader on Maple Rev3 stays alive for so long. Sometimes the bootloader was exiting before the OS had even enumerated the device! Once in bootloader mode, however, dfu-util uploads your sketch into either flash or RAM (DFU alternate setting 0 or 1, respectively) and resets the board again. This time, however, no DFU transaction is initiated, and the bootloader gives way to user code, closing down the DFU pipe and bringing up the USB serial.

Flashing A Custom Bootloader

The STM32 microprocessor on the Maple comes with a built-in hardware bootloader that can be used to flash a new (software) bootloader onto the chip. This section describes how to go about this, using a Maple Rev 3 or higher (if you have a Maple Rev 1; you don’t have a BUT button, and won’t be able to follow these directions. A workaround is detailed in this forum posting).

Warning

This section is directed at users wishing to write a custom bootloader for the Maple, or update their bootloader to a more recent version. It’s generally not necessary to do so, and it is possible to make a mistake and e.g. render your Maple unable to communicate with the IDE. Know what you’re doing, and proceed with caution.

Setup

In order to follow these instructions, you will need:

  • A binary of the bootloader you want to upload
  • Hardware for communicating between the Maple and your computer over serial.
  • Python version 2.5 or higher, with the PySerial library installed.

Step 1: Obtain a bootloader binary. The first thing you’ll need to do is to compile your bootloader binary. Note that an ASCII representation of the binary, such as the Intel .hex format, will not suffice. For example, you can run (on a suitably configured system) the following to obtain a binary of the bootloader currently used on the Maple:

$ git checkout git://github.com/leaflabs/maple-bootloader.git
$ cd maple-bootloader
$ make
$ ls -lh build/maple-boot.bin # this is the compiled bootloader binary

Step 2: Connect Maple Serial1 to your computer. There are a variety of ways of doing this. We use Sparkfun’s FTDI breakout boards, but you could use another Maple, an Arduino, etc. – anything that allows your computer to communicate with the Maple you want to reprogram over a serial interface.

If you do use an FTDI breakout board, first make sure your Maple is disconnected from an external power source, be it battery, USB, or barrel jack. Then, connect the FTDI board’s TX pin to Serial1‘s RX pin (pin 8), FTDI RX to Serial1 TX (pin 7), FTDI ground to Maple’s GND, and its 3.3V pin to Maple’s Vin (use the Maple’s silkscreen for help locating these pins). At this point, you’re ready to plug the FTDI board into your computer (via USB).

The Serial1 pins are documented here.

Step 3: Put your Maple into serial bootloader mode. Do this by pressing the RESET button, then while RESET is held down, pressing and holding the BUT button. Next, making sure to keep BUT held down, release the RESET button and wait for a few seconds before releasing BUT.

Step 4: Obtain stm32loader.py. The script stm32loader.py is provided with libmaple. If you have set up the Unix toolchain, it is available in libmaple/support/stm32loader.py. Otherwise, you can download it directly from github (click the link, then save the file somewhere on your system).

Flashing the new Bootloader

We’ll use new-boot.bin, ser-port, and stm32loader.py to respectively refer to the absolute paths to the bootloader binary (from Step 1), the serial port device file or COMM port (from Steps 2 and 3), and the stm32loader.py script.

You can run

$ python stm32loader.py -h

to obtain usage information. The incantation for uploading a bootloader binary new-bootloader.bin is

$ python stm32loader.py -p ser-port -evw new-boot.bin

If all goes well, you’ll see a bunch of output, then “Verification OK”. If something goes wrong, the forum is probably your best bet for obtaining help, with IRC (irc.freenode.net, #leafblowers) being another option. If all else fails, you can always contact us directly!