Here are the full details for how to enable and disable the CIRCUITPY, MIDI, and serial USB devices. HID devices are more complicated, and we'll cover them on their own page.

USB Setup and Configuration is Done in boot.py

All the code examples on this page must be put in boot.py. If you try to use them in code.py, you'll get an error, because by the time code.py runs, the USB devices are already set up.

Hard Reset Required After Changing boot.py

boot.py runs only after a hard reset. So if you change boot.py, you'll need to reset the board to have it re-run. Just editing boot.py or typing ctrl-D in the REPL will not cause it to re-run again. Make sure your changes are completely written out before you reset, to avoid confusion and filesystem corruption.

CIRCUITPY Mass Storage Device

The CIRCUITPY drive is normally visible on the host computer. To disable it showing up as a USB device, use code like this in boot.py:

import storage

storage.disable_usb_drive()

Note that disabling the USB device does not make the drive not work. It's still available for use by your program, and is still read-only by default. If you need to write to CIRCUITPY in your program, you need to use storage.remount("/", readonly=False) to remount it as read/write. See this guide page for more details.

There is also a storage.enable_usb_drive() function, but you normally don't need to use it, unless your build has CIRCUITPY disabled by default or you want to re-enable it after disabling it in boot.py.

import storage

storage.disable_usb_drive()
storage.enable_usb_drive()   # Changed my mind :)

MIDI

The USB MIDI device is enabled by default on most boards. To disable MIDI, do this in boot.py:

import usb_midi

usb_midi.disable()

Some microcontrollers, such as the STM32F4 and ESP32-S2, do not provide enough USB endpoints (details here) to allow MIDI to be enabled all the time. On those boards, MIDI is disabled by default, but is available. If you want to enable it, you'll need to disable some other USB device to free up a pair of endpoints to accommodate MIDI. For example, you could do this:

import usb_hid, usb_midi

# On some boards, we need to give up HID to accomodate MIDI.
usb_hid.disable()
usb_midi.enable()

USB Serial: Console (REPL) and Data

CircuitPython normally provides a USB serial device which lets you talk to the CircuitPython console, where you can use the Python REPL. On Windows, this device shows up as a numbered COM port, such as COM5. On Linux, it shows up as /dev/tty device, often /dev/ttyACM0. On MacOS, it shows up with a name starting with /dev/cu, such as /dev/cu.usbmodem14301.

The serial device is called a CDC device, which stands for "Communications Device Class". The CircuitPython module that controls serial devices is called usb_cdc.

CircuitPython can also optionally provide a second serial device, which is not connected to the console. It's called the data serial device. You can send and receive arbitrary binary data on this device, so it's very useful if you want to exchange data or commands without worrying about the REPL interfering or a ctrl-C character stopping your program. The second serial channel will appear as a second COM port or /dev/tty or /dev/cu device, with a different name.

For details about how to use the second serial device, see the usb_cdc documentation.

Note that some microcontrollers have hardware limitations which can make using the second serial device awkward or impossible. See this page for more information.

You can enable and disable the console device and the data device independently. The console device is enabled by default, but the data device is not.

import usb_cdc

usb_cdc.disable()   # Disable both serial devices.

usb_cdc.enable(console=True, data=False)   # Enable just console
                                           # (the default setting)
  
usb_cdc.enable(console=True, data=True)    # Enable console and data

usb_cdc.enable(console=False, data=False)  # Disable both
                                           # Same as usb_cdc.disable()

Which Serial Port on the Host?

Since turning on the data device presents another serial port to the host, you want to be able to determine which serial ports correspond to which CircuitPython devices. You can use the Adafruit_Board_Toolkit Python library, which is available for installation via pip3 install adafruit-board-toolkit.

You can list the available usb_cdc.data serial ports using adafruit_board_toolkit.circuitpython_serial.data_comports(). Similarly, to get a list of the usb_cdc.console (REPL) serial ports, use adafruit_board_toolkit.circuitpython.repl_comports(). Full documentation is here.

Don't Lock Yourself Out!

If you turn off both CIRCUITPY and the REPL in boot.py, and don't provide a way to turn them back on, you will lock yourself out of your board: you won't have any way to edit files anymore. You can recover by forcing the board to start in safe mode, which skips running boot.py. But it's easier and better to provide yourself an out: for instance, allow button push to skip disabling the devices.

This kind of code will lock you out:

import storage, usb_cdc

# DON'T DO THIS!
storage.disable_usb_drive()
usb_cdc.disable()

The code below is safer. It skips turning off both devices if a button is pushed. The first vesion of the code is for buttons that are grounded when pressed.

# This example is for the MacroPad,
# or any board with buttons that are connected to ground when pressed.

import storage
import board, digitalio

# On the Macropad, pressing a key grounds it. You need to set a pull-up.
# If not pressed, the key will be at +V (due to the pull-up).
button = digitalio.DigitalInOut(board.KEY12)
button.pull = digitalio.Pull.UP

# Disable devices only if button is not pressed.
if button.value:
   storage.disable_usb_drive()

 The second version is for buttons that are connected to +V when pressed.

# This example is for a Circuit Playground,
# or any board with buttons that are connected to +V when pressed.

import storage, usb_cdc
import board, digitalio

# On the Circuit Playground, pressing an on-board button
# connects the button to +V.
button = digitalio.DigitalInOut(board.BUTTON_A)
button.pull = digitalio.Pull.DOWN

# Disable devices only if button is not pressed.
if not button.value:
	storage.disable_usb_drive()
	usb_cdc.disable()

This guide was first published on May 20, 2021. It was last updated on May 20, 2021.

This page (CIRCUITPY, MIDI, and Serial) was last updated on May 20, 2021.

Text editor powered by tinymce.