Skip to content lives in the root of your keyboard when mounted as a storage device. There is a more detailed explanation in the CircuitPython Documentation, however there are some common use cases for your keyboard listed on this page.

KMK's builtin boot configurator

KMK ships with a handy boot configuration function that does all the hard work for you. The interface may change in the future, but there is a safety mechanism in place: if anything goes wrong, it'll boot into a mountable and debuggable configuration.


from kmk.bootcfg import bootcfg

    # required:
    sense: [microcontroller.Pin, digitalio.DigitalInOut],
    # optional:
    source: Optional[microcontroller.Pin, digitalio.DigitalInOut] = None,
    boot_device: int = 0,
    cdc_console: bool = True,
    cdc_data: bool = False,
    consumer_control: bool = True,
    keyboard: bool = True,
    midi: bool = True,
    mouse: bool = True,
    nkro: bool = False,
    pan: bool = False,
    storage: bool = True,
    usb_id: Optional[tuple[str, str]] = None,
) -> bool

All optional parameters are set to reflect common CircuitPython defaults, however they may differ from board specific defaults.


sense accepts either uninitialized Pins or DigitalInOut instances for maximum flexibility. The boot configuration is only applied if sense reads True or "high", and skipped if it reads False or "low". If sense is an uninitialized Pin, it'll be configured as pulled-up input; it wont be further configured if it is a DigitalInOut.


source accepts either uninitialized Pins or DigitalInOut instances for maximum flexibility. It's the "source" of the test voltage to be read by the sense pin. If source is an uninitialized Pin, it'll be configured as a "low" output; it wont be further configured if it is a DigitalInOut.

Common matrix and direct pin configurations (see also the examples below):

diode_orientation sense pin source pin
COL2ROW column row
ROW2COL row column
direct pin direct pin None


Boot HID device configuration for usb_hid, see the usb_hid documentation for details.


This will enable or disable the USB endpoint for the serial console with REPL.


This will enable or disable the USB endpoint for the data serial.


Enable the HID endpoint for consumer control reports. Those are extra keys for things like multimedia control and browser shortcuts.


Enable the keyboard HID endpoint. Why would you disable that? For a split half that isn't connected to USB and needs extra memory for a massive display maybe?


It's MIDI over USB. Enabled by default in CircuitPython, but most keyboards don't use it.


Enable the HID endpoint for a pointing device. A pointing device, or mouse, is like a keyboard, but with continuous instead of binary keys... which also go sideways.


Enable n-key rollover support. If the default keyboard is enabled, this option will replace the standard 6-key rollover endpoint with an n-key rollover one. This is technically not a standard HID endpoint, but if you want this, you probably know what you're doing.


Enable panning, aka horizontal scrolling, for the pointing device, aka mouse, hid endpoint.


Disable storage if you don't want your computer to go "there's a new thumb drive I have to mount!" every time you plug in your keyboard.


A recent addition to CircuitPython 8 is the ability to give your keyboard an identity other than "MCU board manufacturer" - "CircuitPython device".

return value

bootcfg returns true if boot configuration applied successfully and false if it was skipped, in case you want to use the sense pin mechanism for other custom boot configurations. Any unexpected errors are intentionally not handled, in order to be recorded to the boot_out.txt file for easier debugging.

Example 1

  • diode direction from columns to rows,
  • disabled storage
  • disabled midi
  • disabled mouse
  • custom vendor and device names
import board

from kmk.bootcfg import bootcfg

    sense=board.GP0,  # column
    source=board.GP8, # row
    usb_id=('KMK Keyboards', 'Custom 60% Ergo'),

Tip: for a diode direction from rows to columns, switch row and column GPIOs when assigning them to sense and source.

Example 2

Dedicated switch to disable boot configuration, connected to ground:

import board

from kmk.bootcfg import bootcfg

bootcfg(sense=board.GP22, ...)

Example 3

Shut-in mode: Always apply boot configuration and disable any contact to the outside world. Caution: this an example for a DigitalInOut sense pin, and probably an unwise thing to do in actuality.

import board
import digitalio

from kmk.bootcfg import bootcfg

sense = digitalio.DigitalInOut(board.GP42)
sense.direction = digitalio.Direction.OUTPUT
sense = True


We generally advise against importing your keyboard definition and using rows/columns to define sense and source pins, because that essentially loads the firmware twice, almost doubling boot times.