aboutsummaryrefslogtreecommitdiffstats
path: root/docs/source/bootloader.rst
diff options
context:
space:
mode:
Diffstat (limited to 'docs/source/bootloader.rst')
-rw-r--r--docs/source/bootloader.rst682
1 files changed, 682 insertions, 0 deletions
diff --git a/docs/source/bootloader.rst b/docs/source/bootloader.rst
new file mode 100644
index 0000000..57833ed
--- /dev/null
+++ b/docs/source/bootloader.rst
@@ -0,0 +1,682 @@
+.. highlight:: sh
+
+=====================
+ Maple Bootloader(s)
+=====================
+
+.. TODO: add a section on flashing your own bootloader
+
+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
+
+.. contents:: Contents
+ :local:
+
+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
+<http://github.com/leaflabs/libmaple>`_!
+
+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
+:command:`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.
+
+.. _bootloader-rev3:
+
+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
+(:file:`drivers/mapleDrv/dfu` in the Windows IDE directory). As part
+of the :ref:`libmaple <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,
+:command:`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.
+
+.. .. _bootloader-rev6:
+
+.. Maple Rev6 - The Serial Bootloader (Tentative)
+.. ----------------------------------------------
+
+.. .. note:: This section documents an in-progress version of the Maple
+.. bootloader. **No Maples yet sold use this bootloader protocol**.
+.. It has not been yet been publicly released, and its interface is
+.. not stable.
+
+.. The bootloader in Rev3/Rev5 works well on Linux, acceptably on Mac,
+.. but was unsatisfactory on Windows. Unlike the other operating systems,
+.. Windows needed to be manually pointed to both the driver to use for
+.. programming (DFU, via `libusb <http://www.libusb.org/>`_) and the
+.. driver to use for serial communication (usbser.sys, built in to
+.. Windows). Since Maple operates in only one of these modes at a time,
+.. driver installation was unnecessarily complicated. It was necessary to
+.. bring Maple into the correct mode before installing each of the
+.. drivers. Furthermore, because libusb is not bundled with Windows, and
+.. its driver is not signed, Windows 7 users have been forced to
+.. laboriously disable driver signing checks. Finally, Windows hates the
+.. constant switching of the device between Serial and DFU modes (during
+.. programming), and often prompts users to install drivers that are
+.. already installed. We have therefore decided to abandon DFU.
+
+.. In our new bootloader scheme, Maple is simply a serial device.
+.. Windows comes bundled with usbser.sys, so no driver signing is
+.. required. The IDE installation process is greatly simplified, there
+.. is no more switching back and forth between "modes", and we can build
+.. in new functionality outside the DFU spec.
+
+.. The first incarnation of this serial-only bootloader leaves libmaple
+.. and user code untouched. However, during programming, instead of
+.. calling :command:`dfu-util` to upload code we will now call a newly
+.. written utility script similar to `avr-dude
+.. <http://savannah.nongnu.org/projects/avrdude/>`_. The high level
+.. operation of the bootloader will remain the same - come on at startup,
+.. wait for an upload operation or timeout, and jump to user code.
+
+.. The second version of this bootloader will eliminate this dependence
+.. on resetting and timing out by having the bootloader run in the
+.. background. It will additionally own the serial port. In this scheme,
+.. sending data over the COM port while DTR is pulled low results in that
+.. packet being captured by the bootloader and interpreted as a
+.. bootloader command. When the user uploads a new program, the
+.. bootloader will overwrite the old one, reset the various peripheral
+.. registers, and jump to user code. All of this will occur without
+.. resetting the chip and thus causing Maple to connect and disconnect
+.. from your computer (which seems to cause many problems).
+
+.. The final version of this bootloader scheme will involve a separate
+.. microcontroller, whose responsibilities are to drive the USB port,
+.. program the main processor, and offer some amount of debugging
+.. capability. This will allow user sketches to run on the bare metal of
+.. the main processor, without any bootloader hiding underneath. This
+.. approach is similar to the approaches taken by mbed and the Arduino
+.. Uno.
+
+.. Regardless of which generation of the new serial bootloader you are
+.. working with, the command interface is the same. The low level
+.. communication protocol is inspired by STK-500, the protocol used to
+.. program many AVR-based development boards. The protocol is a
+.. packetized query-response scheme. The host PC initiates every
+.. transaction, and for every query sent to the bootloader, a single
+.. response will be returned (or the system times out). Data is
+.. transmitted over 115.2kbps, 8 data bits, 1 stop bit, no parity
+.. bit. Every query or response follows the same packet format that looks
+.. like this:
+
+.. .. _bootloader-packet-structure:
+
+.. Packet Structure
+.. ^^^^^^^^^^^^^^^^
+
+.. A bootloader packet is composed of a sequence of fields, as follows.
+
+.. .. list-table::
+.. :header-rows: 1
+
+.. * - Field
+.. - Length (bytes)
+.. - Value
+.. - Description
+
+.. * - START
+.. - 1
+.. - 0x1B
+.. - Magic constant, indicates bootloader packet
+
+.. * - SEQUENCE_NUM
+.. - 1
+.. - 0--0xFF
+.. - Queries and responses must have the same sequence number; rolls
+.. over to 0 after 0xFF
+
+.. * - MESSAGE_SIZE
+.. - 2
+.. - 0--0xFFFF
+.. - Size of message body, currently limited to a 1024B=1KB maximum
+
+.. * - TOKEN
+.. - 1
+.. - 0x7F
+.. - Differs from STK500 value of 0x0E
+
+.. * - MESSAGE_BODY
+.. - Variable, determined by MESSAGE_SIZE field
+.. - Command query or response
+.. - See :ref:`next section <bootloader-commands>`
+
+.. * - CHECKSUM
+.. - 4
+.. - XOR of all other 32-bit words in packet
+.. - See :ref:`below <bootloader-checksum>`
+
+.. .. _bootloader-checksum:
+
+.. .. highlight:: cpp
+
+.. .. note:: When computing the checksum, the words in a packet are
+.. interpreted big-endian (as if the packet were a sequence of 32-bit,
+.. big-endian unsigned integers). If the end of the MESSAGE_BODY is
+.. not aligned with a four-byte boundary, then the checksum will treat
+.. it as if it was padded with zero bytes to a four-byte boundary.
+
+.. As a concrete example, an entire GET_INFO query (see :ref:`below
+.. <bootloader-get-info>`), including the packet structure, is
+.. comprised of the byte sequence ::
+
+.. {0x1B, 0x7F, 0x00, 0x01, 0x7F, 0x00, 0x64, 0x7F, 0x00, 0x01}
+
+.. The SEQUENCE_NUM of this query is 0x7F.
+
+.. .. highlight:: sh
+
+.. .. _bootloader-commands:
+
+.. Commands
+.. ^^^^^^^^
+
+.. The packet structure overhead is for reliability. The actual queries
+.. and responses are transacted inside of the message body. Following
+.. the STK-500 protocol, each query or response begins with the single
+.. byte command field. For each query, the resultant response must begin
+.. with the same CMD byte. For each type of command, the structure of
+.. queries and responses is of fixed size.
+
+.. Also following STK-500, fields longer than 1 byte are transmitted MSB
+.. first (big-endian). However, READ and WRITE commands operate byte-wise
+.. (not word-wise); it is up to the host PC to ensure that alignment and
+.. ordering issues are handled appropriately.
+
+.. .. _bootloader-get-info:
+
+.. GET_INFO
+.. """"""""
+
+.. Used to query device characteristics.
+
+.. GET_INFO Query:
+
+.. .. list-table::
+.. :header-rows: 1
+
+.. * - Field
+.. - Bytes
+.. - Comments
+
+.. * - GET_INFO
+.. - 1
+.. - Value 0
+
+.. GET_INFO Response:
+
+.. .. list-table::
+.. :header-rows: 1
+.. :widths: 4 2 10
+
+.. * - Field
+.. - Bytes
+.. - Comments
+
+.. * - GET_INFO
+.. - 1
+.. - Value 0
+
+.. * - Endianness
+.. - 1
+.. - 0 indicates little-endian, 1 indicates big-endian.
+.. (Currently returns 0; this field allows for future
+.. expansion).
+
+.. * - Available Ram
+.. - 4
+.. - In bytes
+
+.. * - Available Flash
+.. - 4
+.. - In bytes
+
+.. * - Flash Page Size
+.. - 2
+.. - In bytes
+
+.. * - Starting Address (FLASH)
+.. - 4
+.. - Usually 0x08005000
+
+.. * - Starting Address (RAM)
+.. - 4
+.. - Usually 0x200000C0
+
+.. * - Bootloader Version
+.. - 4
+.. - Current version 0x00060000 (MAJ,MIN)
+
+.. .. _bootloader-erase-page:
+
+.. ERASE_PAGE
+.. """"""""""
+
+.. Used to erase flash pages.
+
+.. ERASE_PAGE query:
+
+.. .. list-table::
+.. :header-rows: 1
+.. :widths: 4 2 10
+
+.. * - Field
+.. - Bytes
+.. - Comments
+
+.. * - ERASE_PAGE
+.. - 1
+.. - Value 1
+
+.. * - ADDRESS
+.. - 4
+.. - Will erase whichever page contains ADDRESS
+
+.. ERASE_PAGE response:
+
+.. .. list-table::
+.. :header-rows: 1
+.. :widths: 3 2 10
+
+.. * - Field
+.. - Bytes
+.. - Comments
+
+.. * - ERASE_PAGE
+.. - 1
+.. - Value 1
+
+.. * - SUCCESS
+.. - 1
+.. - Either 0 (failure) or 1 (success)
+
+.. WRITE_BYTES
+.. """""""""""
+
+.. Used to write to RAM or flash.
+
+.. WRITE_BYTES query:
+
+.. .. list-table::
+.. :header-rows: 1
+.. :widths: 4 4 10
+
+.. * - Field
+.. - Bytes
+.. - Comments
+
+.. * - WRITE_BYTES
+.. - 1
+.. - Value 2
+
+.. * - Starting Address
+.. - 4
+.. - Can address arbitrary RAM, or :ref:`cleared
+.. <bootloader-erase-page>` flash pages.
+
+.. * - DATA
+.. - MESSAGE_SIZE - 5
+.. - See :ref:`Packet Structure <bootloader-packet-structure>`
+
+.. WRITE_BYTES response:
+
+.. .. list-table::
+.. :header-rows: 1
+.. :widths: 2 2 10
+
+.. * - Field
+.. - Bytes
+.. - Comments
+
+.. * - WRITE_BYTES
+.. - 1
+.. - Value 2
+
+.. * - SUCCESS
+.. - 1
+.. - Either 0 (failure) or 1 (success). Will fail if writes were
+.. made to uncleared pages. Does not clean up failed writes
+.. (memory will be left in an undefined state).
+
+.. READ_BYTES
+.. """"""""""
+
+.. Used to read from RAM or flash.
+
+.. READ_BYTES query:
+
+.. .. list-table::
+.. :header-rows: 1
+.. :widths: 2 2 10
+
+.. * - Field
+.. - Bytes
+.. - Comments
+
+.. * - READ_BYTES
+.. - 1
+.. - Value 3
+
+.. * - ADDRESS
+.. - 4
+.. - Start of block to read. Must be a multiple of 4.
+
+.. * - LENGTH
+.. - 2
+.. - Maximum number of bytes to read (currently, this may be at most
+.. 1024 = 1KB). Must be a multiple of 4.
+
+.. READ_BYTES response:
+
+.. .. list-table::
+.. :header-rows: 1
+.. :widths: 2 2 10
+
+.. * - Field
+.. - Bytes
+.. - Comments
+
+.. * - READ_BYTES
+.. - 1
+.. - Value 3
+
+.. * - DATA
+.. - MESSAGE_SIZE - 1
+.. - Contains read bytes. The actual number of bytes read may be
+.. less than the LENGTH field of the corresponding READ_BYTES
+.. query. If this section is of length 0, this should be
+.. interpreted as a read failure. See
+.. :ref:`bootloader-packet-structure`.
+
+.. JUMP_TO_USER
+.. """"""""""""
+
+.. Causes the bootloader to jump to user code's starting address.
+
+.. JUMP_TO_USER query:
+
+.. .. list-table::
+.. :header-rows: 1
+.. :widths: 2 1 10
+
+.. * - Field
+.. - Bytes
+.. - Comments
+
+.. * - JUMP_TO_USER
+.. - 1
+.. - Value 4
+
+.. * - Location
+.. - 1
+.. - 0 means jump to flash starting address, 1 means jump to RAM
+.. starting address. See the :ref:`bootloader-get-info` command
+.. for more information.
+
+.. JUMP_TO_USER response:
+
+.. .. list-table::
+.. :header-rows: 1
+.. :widths: 2 1 10
+
+.. * - Field
+.. - Bytes
+.. - Comments
+
+.. * - JUMP_TO_USER
+.. - 1
+.. - Value 4
+
+.. * - SUCCESS
+.. - 1
+.. - Either 0 (failure) or 1 (success). If successful, after the
+.. response is sent, the bootloader ends this session and jumps to
+.. the user code in flash or RAM as specified in the query's
+.. Location field.
+
+
+.. SOFT_RESET
+.. """"""""""
+
+.. Engages a full software reset.
+
+.. SOFT_RESET query:
+
+.. .. list-table::
+.. :header-rows: 1
+.. :widths: 2 1 10
+
+.. * - Field
+.. - Bytes
+.. - Comments
+
+.. * - SOFT_RESET
+.. - 1
+.. - Value 5
+
+.. SOFT_RESET response:
+
+.. .. list-table::
+.. :header-rows: 1
+.. :widths: 2 1 10
+
+.. * - Field
+.. - Bytes
+.. - Comments
+
+.. * - SOFT_RESET
+.. - 1
+.. - Value 5
+
+.. * - SUCCESS
+.. - 1
+.. - Either 0 or 1 (FAILED and OK, respectively). Will end this
+.. bootloader session and reset the processor.
+
+.. _bootloader-reflashing:
+
+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
+<http://forums.leaflabs.com/topic.php?id=32#post-126>`_).
+
+.. 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.
+
+.. highlight:: sh
+
+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 <http://python.org>`_ version 2.5 or higher, with the
+ `PySerial <http://pyserial.sourceforge.net/>`_ 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 :ref:`suitably configured
+system <unix-toolchain>`) 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 <http://www.sparkfun.com/products/718>`_, 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 :ref:`here <lang-serial>`.
+
+**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 :ref:`Unix toolchain <unix-toolchain>`, it is available in
+libmaple/support/stm32loader.py. Otherwise, you can download it
+directly from `github
+<https://github.com/leaflabs/libmaple/raw/master/support/stm32loader.py>`_
+(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.
+
+.. highlight:: sh
+
+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`_!