Project tutorial
UF2 Bootloader: Creating Custom Boards

UF2 Bootloader: Creating Custom Boards © GPL3+

Want to remove the hassle of using command-line every time you need to upload a new firmware? Now you can!

  • 1 comment
  • 4 respects

Components and supplies

Apps and online services

About this project


Over the past six months I have spent a lot of time porting different libraries to the Robo HAT MM1 board developed by Robotics Masters. This has lead to discovering a lot about these libraries, how they work behind the scenes and most importantly - what to do to add new boards in the future.

This is the third in a series of write-ups I will be doing to help others who wish to port libraries for their boards. Many of the sources of information can be vague or difficult for outsiders to understand. I hope to ‘demystify’ and explain how to achieve a successful port for everyone.

Today, we will be looking at the UF2 bootloader pioneered by Microsoft's developer team. It can be used by some Arduino boards, most of Adafruit's Feather range, and others.

What is UF2?

UF2 is a file format developed by Microsoft. The UF2 firmware allows for flashing microcontrollers over USB and appears as a Mass Storage Device (USB Drive) when attached to your computer.

Simply put: you can copy firmware to a USB drive instead of having to burn it using other tools like openocd.

Before you begin

Before you begin with porting a software library or firmware to your board, you must know a few key points about the technology you are using and be able to answer the questions below.

  • What processor are you using?
  • What architecture does it use?
  • Do I have access to the datasheet for this microprocessor?
  • Is there a similar board on the market that uses the same microprocessor?

These are very important. It will impact on many aspects of how you approach the development process.

The datasheet for a microprocessor is absolutely vital to ensure that the board responds as expected when you compile the firmware. Without it, you will not be able to set the correct pin output functions or configure serial ports.

Let’s be honest here: the only pin you really need to know for this process is the Boot LED on your custom board.

Once you have all the information you need about the processor you are using, you can start to look at the software and modify it to work for your custom board.


The process is relatively simple if you have all the information you need:

  • Boot LED pin
  • Processor model

Here is a short summary of what you will have to do:

  • Clone repository
  • Copy existing board
  • Update board configuration
  • Compile

Each step will be explained in detail below.

For this tutorial, I will be showing you how to create a custom board for SAMD processors. More specifically, the SAMD21G18A - which is the microprocessor used on the Robo HAT MM1 board which I was porting.

I also assume you already have some kind of text editor (nano, TextEdit) and using some UNIX distribution (I was using Ubuntu 16.04.5).

Step 1 - Clone Repository and Set Up Environment

Step one is to grab the uf2-samdx1 repository from either Microsoft or Adafruit. I am yet to determine the difference between these two forks (except that the Adafruit one works with more boards) but I have chosen Adafruit for this tutorial.

git clone
cd uf2-samdx1

Install ARM-Cross Compilers

sudo add-apt-repository ppa:team-gcc-arm-embedded/ppa
sudo apt-get update
sudo apt-get install gcc-arm-embedded

ARM-Cross Compiler: Since we are going to be using Ubuntu to compile CircuitPython firmware for the board, we need to install the correct compilers for ARM boards (SAMD boards are ARM based). I am assuming you already have or this command will download all the required compilers for your device.

Build a Test Board

You are now set to build a test board to check your environment is set up correctly. Building boards is a straightforward process once they exist. Starting in the root of the cloned repository, run the following command:

make BOARD=feather_m0

You should see lots of output and the make script may fetch other repositories in the process - this will only happen once. If you run the command again, it will be very fast.

If the build is successful, you should be able to find a lot of files in the /build/board_name folder.

Step 2 - Creating a New Board

As with the other tutorials I have published, we are going to start by copying another board's settings and then changing to suit. Today we are going to choose the Feather M0 Express board as it is closest matched to the Robo HAT MM1 board. You can choose a different board that is closest to your board.

cd boards/
cp -r feather_m0_express/ robohatmm1/

Inside the folder that you just created, you will find only two files.


Step 3 - Customise the New Board

This file contains information about the processor. In most cases you will not need to change this file if you choose an existing board similar to yours.

CHIP_FAMILY = samd21


This is where most of the customisation will be taking place today. Below is a sample file for the Robo HAT MM1. Each section is explained below.

#define CRYSTALLESS    1
#define VENDOR_NAME "Robotics Masters"
#define PRODUCT_NAME "Robo HAT MM1"
#define INDEX_URL ""
#define BOARD_ID "SAMD21G18A-v4"
#define USB_VID 0x1209
#define USB_PID 0x4D44
#define LED_PIN PIN_PA21

The first two lines are C semantics - asking the compiler if the board config is already defined, otherwise, define it here. The last line is similar. It matches with the second line. So don't worry too much about these.

#define CRYSTALLESS    1

Crystal: Some boards use only the internal crystal for timing operations. Others have an external crystal. Whether to use the internal or external crystal is dependant on the applications of your board. Most people can manage without it. Check that your board either includes or excludes the external crystal and set accordingly.

#define VENDOR_NAME "Robotics Masters"
#define PRODUCT_NAME "Robo HAT MM1"
#define INDEX_URL ""

Vendor Name: This is what is presented to your computer when you attach your board to the USB port. It will show as the "Vendor Name" in the USB settings (you can check it out in Device Manager on Windows).

Product Name: This is what is presented to your computer when you attach your board to the USB port. In Windows 10, it may appear when installing the device drivers. It will show as the "Product Name" in the USB settings (you can check it out in Device Manager on Windows).

Volume Label: This is the name that will appear on the USB Drive. On Mac OS, this is what appears on your desktop when you connect the board to the USB port. On Windows this is the name of the USB Drive running on the board in File Explorer.

Index URL: The bootloader creates a few files that live on the USB Drive. One of them is a shortcut / link to a website or product page. You can set this to your own website or a help page for setting up your board here.

#define BOARD_ID "SAMD21G18A-v4"

Board ID: This distinguishes your board from others. You are able to set this text to anything you like, however, it is recommended you follow a similar format to the existing boards. That is: processor model (dash) board name (dash) version number.

#define USB_VID 0x1209
#define USB_PID 0x4D44

This is where all the USB information about your board is set. Every board should have a unique Vendor ID (VID) and Product ID (PID) combination.

#define LED_PIN PIN_PA21

LED Pin: Arguably the most important line in the whole of the configuration... this is where you must set the correct pin for the boot led. Consult your datasheet or schematic diagram to ensure that you have the right port and pin. For the Robo HAT MM1, Pin 21 on Port A (PA21) is where the boot LED is connected.

This is so that the bootloader can give you feedback about the state of the board. Whether the bootloader is running, restarting or in an error state.

Step 4 - Compile Board

We are nearly complete! Next is to compile your custom board's firmware. This is as easy as running the same commands as the end of Step 1.

make BOARD=robohatmm1

Replace robohatmm1 with your custom board folder name!

Step 5A - Pushing Firmware to Blank Chips

This should really have it's own tutorial. It can be a bit complicated and is very set up dependant.

We used Open OCD running on a Raspberry Pi to flash the UF2 bootloader to SAMD21 blank chips. Other people have used programmers for Arduino or development boards.

If you want to check out the documentation here for using a Raspberry Pi - otherwise wait for a tutorial to pop up!

Step 5B - Updating UF2 Firmware

Putting a new load of firmware onto a device that already has UF2 running is easy! You just need copy the update-bootloader-boardname.uf2 file onto your board. Below is an example case for Robo HAT MM1:

1. Connect the Robo HAT MM1 to your computer's USB port.2. Double Press the "Reset" button quickly, the LED should start to pulse and a ROBOBOOT drive will appear on your computer.3. Copy the update-bootloader-boardname.uf2 file onto the USB.4. The board will reset and new bootloader should be successfully installed.


This has been yet another fun experience learning out UF2 and how bootloaders work on different boards. Of all the tutorials published so far, this in my opinion was the easiest software library to get working. The documentation is the best out of all the libraries.

Be sure to check out the Crowd Supply campaign for the Robo HAT MM1 as well. It ends on June 11, 2019.

I hope this helped you or you had fun reading along!




Similar projects you might like

Creating Images Using One LED

Project tutorial by Arduino “having11” Guy

  • 11 respects

Protected Switching Power Supply for Development Boards

Project showcase by Akash Kollipara

  • 5 respects

Ball Tracking Robot

Project showcase by Rohan Juneja

  • 97 respects

Creating an IoT Dashboard with Xkit, Sigfox & AWS

Project tutorial by Daniel Thomas

  • 9 respects
Add projectSign up / Login