The next step is customising the board files. This section walks you through each file and how to update it. Let's get started!


This file changes how the C code works through macros for the C code. It also tells the board how to set up the file system.

Open mpconfigboard.h in your editor of choice. This file contains the following:

  • Board name
  • MCU name
  • Status LED pins
  • Board flash size
  • Ignored pins
  • Default I2C, SPI and UART bus pins

PyRuler does not have an external SPI flash chip, and used the same microcontroller as the Trinket M0, so no changes were needed to NVM or flash sizes. Don't mess with this unless you know what you're doing! You can cause issues with the flash table on your board.

To update this file, you'll need to do the following:

  • You should have already updated your board name and verified the MCU name.
#define MICROPY_HW_BOARD_NAME "Adafruit PyRuler"
#define MICROPY_HW_MCU_NAME "samd21e18"
  • Identify what pin your status LED is on and update the file to reflect the appropriate pin. If you have more than one status LED, e.g. your board also includes a DotStar, you can identify that here as well.
#define MICROPY_HW_LED_STATUS   (&pin_PA10)

#define MICROPY_HW_APA102_MOSI   (&pin_PA00)
#define MICROPY_HW_APA102_SCK    (&pin_PA01)
  • There will always be at least two pins on the ignored pins list: PA24 and PA25. These pins are used for USB and are always ignored by CircuitPython. Typically, those will be the only two pins on that list. The only time that list is expanded to include more pins is if the board flash is small enough to require tweaking to make the build fit. Trinket M0 and PyRuler are examples of boards where the build must be slimmed down. That is why there is a fairly extensive list of ignored pins in this file for these boards. The pins listed here are pins on the chip that are not connected to anything.
// USB is always used internally so skip the pin objects for it.
#define IGNORE_PIN_PA24     1
#define IGNORE_PIN_PA25     1
  • Update the default I2C, SPI and UART busses. These are listed at the bottom of the file. If yours are on different pins, simply change the pin numbers to match what your board uses.
#define DEFAULT_I2C_BUS_SCL (&pin_PA09)
#define DEFAULT_I2C_BUS_SDA (&pin_PA08)

#define DEFAULT_SPI_BUS_SCK (&pin_PA07)
#define DEFAULT_SPI_BUS_MOSI (&pin_PA06)
#define DEFAULT_SPI_BUS_MISO (&pin_PA09)

#define DEFAULT_UART_BUS_RX (&pin_PA07)
#define DEFAULT_UART_BUS_TX (&pin_PA06)

If you're unsure how to find what pins are correct, you'll want to check the schematic. You'll also need to do that for pins.c. Let's take a look.


The pins.c file contains the board pin names as they will appear to the user associated with the microcontroller (MCU) pin names. This is where the board module in CircuitPython gets the board pin names that it makes available to the user for use in code, e.g. board.A1, etc. The board pins listed in this file should match the labels on the silkscreen on your board.

Use the board's schematic to identify what pins are associated with what names and enter all of them into the pins.c file, using the same format as is used for the pins already listed in the file. Be sure to verify that all pins present already are accurate, or be certain to delete them or update them to make them accurate. PyRuler has a number of different pin assignments from Trinket M0, and a number of additional pins. These were all updated and added as needed.

Understanding the Schematic to Identify Pins

Open the schematic for your board and find the symbol for the MCU. It may be labeled with the chip name.

The information you need for identifying which pins names should be associated with which pins is typically contained within this symbol. Let's take a closer look.

The MCU pins are listed along the right side of the  MCU schematic symbol outline (the red box) in the PyRuler schematic, e.g. PA00, PA01, PA03. The MCU pins are outlined in magenta.

The board pin that each MCU pin is connected to is on the outside to the right, e.g. DOTSTAR_DATA, DOTSTAR_CLOCK, D1_A0, CAP3. The board pins are outlined in blue.

Note that the pin numbers listed along the edge of the schematic symbol are not the same as the pin names! The names start at 0 and the pin numbers start at 1. The pin numbers are outlined in green.

Now you can begin to identify the associated MCU pins and board pins. Start at the top.

The first two pins are connected to the on-board DotStar LED.

This is relevant to both mpconfigboard.h and pins.c.

mpconfigboard.h includes identifying any status LEDs, which includes the DotStar LED built into PyRuler. It is included in this file so CircuitPython can use it for status information.

The entry in pins.c is for the user to be able to manipulate the LED using the board module.

pins.c has many lines all with the same format that associate MCU pins with board pins. You can copy the format to add more pins if necessary.

The DotStar clock and data pins are listed towards the bottom of the file.

    { MP_ROM_QSTR(MP_QSTR_APA102_MOSI), MP_ROM_PTR(&pin_PA00) },
    { MP_ROM_QSTR(MP_QSTR_APA102_SCK), MP_ROM_PTR(&pin_PA01) },

Continue down the list, assigning MCU pins to board pins.

Some MCU pins will have more than one board pin associated with them. Each board pin name requires its own line with the MCU pin name repeated on multiple lines if necessary. For example, MCU pin PA02 on the PyRuler is used for board pins D1 and A0.

So, there are two lines in pins.c to assign the board pin names to the MCU pin:

    { MP_ROM_QSTR(MP_QSTR_D1), MP_ROM_PTR(&pin_PA02) },
    { MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_PA02) },

Repeat this process for all the board pins that you would like to expose to the user in the board module.

The information in this file changes how the build works, and changes what files are included.

You should have already verified that the CHIP_VARIANT and CHIP_FAMILY were accurate when you did the initial test build for your board. The CHIP_VARIANT should be the full name of the chip, e.g. SAMD21E18A. The CHIP_FAMILY will be samd21 or samd51 depending on which chip your board uses.

CHIP_FAMILY = samd21

The lines you'll want to update in this file are:

  • USB_VID - This is the vendor ID.
  • USB_PID - This is the product ID.
  • USB_PRODUCT - This is the name of your board.
  • USB_MANUFACTURER - This is who makes your board.
USB_VID = 0x239A
USB_PID = 0x804C
USB_MANUFACTURER = "Adafruit Industries LLC"


A USB VID is the USB Vendor ID, and PID is the Product ID. USB VID and PID are something you cannot borrow from another board. So don't copy and paste these values from an existing board! See the FAQ page in this guide for more information on getting a VID/PID pair for your board.

Creator/Creation IDs

For boards that don't have native USB, there is still a way to identify your board uniquely. You will see mentions of CIRCUITPY_CREATOR_ID and CIRCUITPY_CREATION_ID in their files. You can register new Creator and Creation IDs at


This file handles board-specific initialisation and functionality, such as initialising a display or creating custom ways to get into safe-mode. Generally, it is empty functions. board.c is for more advanced usage. Regardless of whether you add anything to this file, it must be present or the build will not occur or be verified, and is also necessary for automatic releases and board inclusion on

A good example of making changes to this file is the Circuit Playground Express board.c file. It includes a more complex setup, such as optional safe-mode, reset configuration, and resetting the NeoPixels when the board is reset by sending the board state to the NeoPixels to turn them off after the user code is done.

sdkconfig (Espressif only)

For Espressif boards, you must also supply an sdkconfig file. The best thing to do is to copy an existing sdkconfig file for a very similar board. Modifying an sdkconfig requires a lot of knowledge about ESP-IDF compile options.

Firmware Files to Build

In each port/ file, the value CIRCUITPY_BUILD_EXTENSIONS specifies the default firmware formats to build. For instance, for atmel-samd, the defaults are


If you want to build different or more formats for your board, add an overriding value to your For instance, if you want to build .bin and .uf2 files, add


This guide was first published on Jul 18, 2019. It was last updated on Apr 09, 2024.

This page (Customizing the Board Files) was last updated on Apr 05, 2024.

Text editor powered by tinymce.