This is an information page for advanced users who are curious how we get code from your computer into your Express board!

Adafruit SAMD21 (M0) and SAMD51 (M4) boards feature an improved bootloader that makes it easier than ever to flash different code onto the microcontroller. This bootloader makes it easy to switch between Microsoft MakeCode, CircuitPython and Arduino.

Instead of needing drivers or a separate program for flashing (say, bossac, jlink or avrdude), one can simply drag a file onto a removable drive.

The format of the file is a little special. Due to 'operating system woes' you cannot just drag a binary or hex file (trust us, we tried it, it isn't cross-platform compatible). Instead, the format of the file has extra information to help the bootloader know where the data goes. The format is called UF2 (USB Flashing Format). Microsoft MakeCode generates UF2s for flashing and CircuitPython releases are also available as UF2. You can also create your own UF2s from binary files using uf2tool, available here.

The bootloader is also BOSSA compatible, so it can be used with the Arduino IDE which expects a BOSSA bootloader on ATSAMD-based boards

For more information about UF2, you can read a bunch more at the MakeCode blog, then check out the UF2 file format specification. 

Visit Adafruit's fork of the Microsoft UF2-samd bootloader GitHub repository for source code and releases of pre-built bootloaders on CircuitPython.org.

The bootloader is not needed when changing your CircuitPython code. Its only needed when upgrading the CircuitPython core or changing between CircuitPython, Arduino and Microsoft MakeCode.

Entering Bootloader Mode

The first step to loading new code onto your board is triggering the bootloader. It is easily done by double tapping the reset button. Once the bootloader is active you will see the small red LED fade in and out and a new drive will appear on your computer with a name ending in BOOT. For example, feathers show up as FEATHERBOOT, while the new CircuitPlayground shows up as CPLAYBOOT, Trinket M0 will show up as TRINKETBOOT, and Gemma M0 will show up as GEMMABOOT

Furthermore, when the bootloader is active, it will change the color of one or more onboard neopixels to indicate the connection status, red for disconnected and green for connected. If the board is plugged in but still showing that its disconnected, try a different USB cable. Some cables only provide power with no communication.

For example, here is a Feather M0 Express running a colorful Neopixel swirl. When the reset button is double clicked (about half second between each click) the NeoPixel will stay green to let you know the bootloader is active. When the reset button is clicked once, the 'user program' (NeoPixel color swirl) restarts.

If the bootloader couldn't start, you will get a red NeoPixel LED.

That could mean that your USB cable is no good, it isn't connected to a computer, or maybe the drivers could not enumerate. Try a new USB cable first. Then try another port on your computer!

Once the bootloader is running, check your computer. You should see a USB Disk drive...

Once the bootloader is successfully connected you can open the drive and browse the virtual filesystem. This isn't the same filesystem as you use with CircuitPython or Arduino. It should have three files:

  •  CURRENT.UF2 - The current contents of the microcontroller flash.
  •  INDEX.HTM - Links to Microsoft MakeCode.
  •  INFO_UF2.TXT - Includes bootloader version info. Please include it on bug reports.

Using the Mass Storage Bootloader

To flash something new, simply drag any UF2 onto the drive. After the file is finished copying, the bootloader will automatically restart. This usually causes a warning about an unsafe eject of the drive. However, its not a problem. The bootloader knows when everything is copied successfully.

You may get an alert from the OS that the file is being copied without it's properties. You can just click Yes

You may also get get a complaint that the drive was ejected without warning. Don't worry about this. The drive only ejects once the bootloader has verified and completed the process of writing the new code

Using the BOSSA Bootloader

As mentioned before, the bootloader is also compatible with BOSSA, which is the standard method of updating boards when in the Arduino IDE. It is a command-line tool that can be used in any operating system. We won't cover the full use of the bossac tool, suffice to say it can do quite a bit! More information is available at ShumaTech.

Windows 7 Drivers

If you are running Windows 7 (or, goodness, something earlier?) You will need a Serial Port driver file. Windows 10 users do not need this so skip this step.

You can download our full driver package here:

Download and run the installer. We recommend just selecting all the serial port drivers available (no harm to do so) and installing them.

Verifying Serial Port in Device Manager

If you're running Windows, its a good idea to verify the device showed up. Open your Device Manager from the control panel and look under Ports (COM & LPT) for a device called Feather M0 or Circuit Playground or whatever!

If you see something like this, it means you did not install the drivers. Go back and try again, then remove and re-plug the USB cable for your board

Running bossac on the command line

If you are using the Arduino IDE, this step is not required. But sometimes you want to read/write custom binary files, say for loading CircuitPython or your own code. We recommend using bossac v 1.7.0 (or greater), which has been tested. The Arduino branch is most recommended.

You can download the latest builds here. The mingw32 version is for Windows, apple-darwin for Mac OSX and various linux options for Linux. Once downloaded, extract the files from the zip and open the command line to the directory with bossac.

With bossac versions 1.9 or later, you must use the --offset parameter on the command line, and it must have the correct value for your board.

With bossac version 1.9 or later, you must give an --offset parameter on the command line to specify where to start writing the firmware in flash memory. This parameter was added in bossac 1.8.0 with a default of 0x2000, but starting in 1.9, the default offset was changed to 0x0000, which is not what you want in most cases. If you omit the argument for bossac 1.9 or later, you will probably see a "Verify Failed" error from bossac.  Remember to change the option for -p or --port to match the port on your Mac.

Replace the filename below with the name of your downloaded .bin: it will vary based on your board!

Using bossac Versions 1.7.0, 1.8

There is no --offset parameter available. Use a command line like this:

bossac -p=/dev/cu.usbmodem14301 -e -w -v -R adafruit-circuitpython-boardname-version.bin

For example,

bossac -p=/dev/cu.usbmodem14301 -e -w -v -R adafruit-circuitpython-feather_m0_express-3.0.0.bin

Using bossac Versions 1.9 or Later

For M0 boards, which have an 8kB bootloader, you must specify -offset=0x2000, for example:

bossac -p=/dev/cu.usbmodem14301 -e -w -v -R --offset=0x2000 adafruit-circuitpython-feather_m0_express-3.0.0.bin

For M4 boards, which have a 16kB bootloader, you must specify -offset=0x4000, for example:

bossac -p=/dev/cu.usbmodem14301 -e -w -v -R --offset=0x4000 adafruit-circuitpython-feather_m4_express-3.0.0.bin

This will erase the chip, write the given file, verify the write and Reset the board. On Linux or MacOS you may need to run this command with sudo ./bossac ..., or add yourself to the dialout group first.

Updating the bootloader

The UF2 bootloader is relatively new and while we've done a ton of testing, it may contain bugs. Usually these bugs effect reliability rather than fully preventing the bootloader from working. If the bootloader is flaky then you can try updating the bootloader itself to potentially improve reliability.

If you're using MakeCode on a Mac, you need to make sure to upload the bootloader to avoid a serious problem with newer versions of MacOS. See instructions and more details here.

In general, you shouldn't have to update the bootloader! If you do think you're having bootloader related issues, please post in the forums or discord.

Updating the bootloader is as easy as flashing CircuitPython, Arduino or MakeCode. Simply enter the bootloader as above and then drag the update bootloader uf2 file below. This uf2 contains a program which will unlock the bootloader section, update the bootloader, and re-lock it. It will overwrite your existing code such as CircuitPython or Arduino so make sure everything is backed up!

After the file is copied over, the bootloader will be updated and appear again. The INFO_UF2.TXT file should show the newer version number inside.

For example:

UF2 Bootloader v2.0.0-adafruit.5 SFHWRO
Model: Metro M0
Board-ID: SAMD21G18A-Metro-v0


Lastly, reload your code from Arduino or MakeCode or flash the latest CircuitPython core.

Below are the latest updaters for various boards. The latest versions can always be found here.  Look for the update-bootloader... files, not the bootloader... files.

Getting Rid of Windows Pop-ups

If you do a lot of development on Windows with the UF2 bootloader, you may get annoyed by the constant "Hey you inserted a drive what do you want to do" pop-ups.

Go to the Control Panel. Click on the Hardware and Sound header

Click on the Autoplay header

Uncheck the box at the top, labeled Use Autoplay for all devices

Making your own UF2

Making your own UF2 is easy! All you need is a .bin file of a program you wish to flash and the Python conversion script. Make sure that your program was compiled to start at 0x2000 (8k) for M0 boards or 0x4000 (16kB) for M4 boards. The bootloader takes up the first 8kB (M0) or 16kB (M4). CircuitPython's linker script is an example on how to do that.

Once you have a .bin file, you simply need to run the Python conversion script over it. Here is an example from the directory with uf2conv.py. This command will produce a firmware.uf2 file in the same directory as the source firmware.bin. The uf2 can then be flashed in the same way as above.

# For programs with 0x2000 offset (default)
uf2conv.py -c -o build-circuitplayground_express/firmware.uf2 build-circuitplayground_express/firmware.bin

# For programs needing 0x4000 offset (M4 boards)
uf2conv.py -c -b 0x4000 -o build-metro_m4_express/firmware.uf2 build-metro_M4_express/firmware.bin

Installing the bootloader on a fresh/bricked board

If you somehow damaged your bootloader or maybe you have a new board, you can use a JLink to re-install it.

Here's a Learn Guide explaining how to fix the bootloader on a variety of boards using Atmel Studio

Here's a short writeup by turbinenreiter on how to do it for the Feather M4 (but adaptable to other boards)

This guide was first published on May 27, 2018. It was last updated on Mar 14, 2024.

This page (UF2 Bootloader Details) was last updated on Mar 08, 2024.

Text editor powered by tinymce.