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: https://github.com/leaflabs/maple-bootloader
Contents
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 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 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.
Mac OS X, 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 custom drivers across several platforms to make everything work this way.
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 (setupUSB() is called from init()). This user mode code only implements a CDC ACM class USB device, giving you functions like SerialUSB.read(). Separating these two modes fixed the driver issues 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 must reset the board, then initiate a DFU transaction. The IDE performs this reset automatically by performing a special sequence of changes on the USB serial port:
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 is the reason the bootloader on Maple Rev 3/Rev 5 stays alive for so long. (Sometimes, the bootloader was exiting before the OS had even enumerated the device.)
Once in bootloader mode, 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 port.
Warning
This section is for users who want to put a fresh or custom bootloader on their board. It’s possible to make a mistake in this process and e.g. render your Maple unable to communicate with the IDE. Know what you’re doing, and proceed with caution.
The STM32 microprocessor on the Maple comes with a built-in serial bootloader that can be used to flash a new (software) bootloader onto the chip. While the Maple bootloader is just a program, the built-in serial bootloader is part of the STM32 hardware, so it’s always available.
This means that you can always follow these instructions to put a new bootloader program on your board; it doesn’t matter if there’s already a copy of the Maple bootloader on it or not.
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.
In order to follow these instructions, you will need:
Step 1: Obtain a bootloader binary. If you want to re-flash the “factory-default” bootloader, LeafLabs hosts pre-compiled copies:
To flash a customized version of a LeafLabs bootloader, you can run (on a suitably configured system) the following to obtain a bootloader binary:
$ git clone git://github.com/leaflabs/maple-bootloader.git
$ cd maple-bootloader
$ make
$ ls -lh build/maple_boot.bin # this is the compiled bootloader binary
Note
If you plan to write a totally custom bootloader, you’ll need an actual binary to use these instructions. An ASCII representation of the binary, such as the Intel .hex format, won’t work.
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 (labeled “RX1” on the silkscreen), FTDI RX to Serial1 TX (labeled “TX1”), FTDI ground to ground (labeled GND), and its 3.3V pin to Vin. On Maple Mini, you will also need to tie BOOT1 (pin 2) to ground.
More information on Serial1 is available here.
At this point, you’re ready to plug the FTDI board into your computer (via USB).
Step 3: Run the built-in hardware serial bootloader[2]. Accomplish this using the following steps:
At this point, if you followed the instructions correctly, the board will appear unresponsive – the LED won’t blink, etc. Don’t worry. This is the expected behavior for the serial bootloader.
Do not confuse the above steps, which run the built-in serial bootloader, with the steps for perpetual bootloader mode.
Step 4: Get stm32loader.py. You can download it directly from libmaple’s GitHub page (click the link, then save the file somewhere on your system). If you have set up the Unix toolchain, it’s the file libmaple/support/stm32loader.py.
We’ll use maple_boot.bin as the path to the bootloader binary from Step 1, and ser-port as the Maple’s serial port device file or COM port.
To upload a bootloader binary, run this command from the Unix shell:
python stm32loader.py -p ser-port -evw maple_boot.bin
Or this command from the Windows command prompt:
python.exe stm32loader.py -p ser-port -evw maple_boot.bin
You can also run the following to get usage information:
# Unix:
python stm32loader.py -h
# Windows:
python.exe stm32loader.py -h
If all goes well, you’ll see a bunch of output, then “Verification OK”. Your board now has a fresh bootloader installed.
The first time you upload a program after installing a new bootloader, there is no need to select a serial port in the IDE [1]. Perform this first upload with no serial port selected. The IDE will emit a warning about not finding a serial port, but the upload will still succeed. In subsequent uploads, select a serial port as you normally would.
If something goes wrong, the forum is probably your best bet for obtaining help, with IRC (server irc.freenode.net, channel #leafblowers) being another option. If all else fails, you can always contact us directly!
Footnotes
[1] | This is because immediately after installing a new bootloader, the only program on your board is the bootloader itself. Unlike a normal sketch, the bootloader is not enumerated as a virtual serial port (it uses DFU instead; see above for more details). |
[2] | Resetting your board in this way runs a special bootloader that ST builds into their chips’ hardware, which communicates over USART. This is different from the LeafLabs bootloader, which is a normal program that runs on your board, and communicates over USB. |