Photo by rawpixel on Unsplash

You are writing embedded code on a microcontroller board. That almost always means that you're interacting with the outside world through some of the board's pins. How do you know which ones do what, and which ones to use in your code? 


Before compiling in the Arduino IDE, you select which board you're using. That basically tells the compiler information it needs to compile specifically for the MCU and configuration of that specific board. That doesn't help with knowing what pins to use, however. You have to look at the documentation for the board and figure it out. The Arduino hardware platform provides some standards that help. You'll always have some pins prefixed with "D". These are for digital I/O. Some will be prefixed with "A". Those can be used for analog signals, but not all support real analog output.

There will be I2C (SCL and SDA) and SPI (MOSI, MISO, and SCK) pins. In your code you'll use the appropriate pin numbers although some boards have predefined values for those pins available when the board is selected in the Arduino IDE.


CircuitPython takes a very different approach to dealing with the various supported boards. First of all, CircuitPython lives on the board whereas Arduino is a set of tool on your computer that generate a binary file that then lives on the board.

Part of making this work is making versions of CircuitPython that are specific to each supported board. For example, if you want to use CircuitPython with a Feather M4 Express, you get the Feather M4 Express build of CircuitPython and put that onto your Feather M4 Express board. See this guide for the details.

The reason this is significant is that CircuitPython knows what board it's running on, and it knows what the capabilities of that board are, and it knows what the pins on that board are and what they can do.

To make this available, there is the board module that you can import. This module contains constants for the pins on the specific board. The board module in CircuitPython for a different board will have different constants specific to that board. The user does not have to tell CircuitPython what board it is running on, it knows.

All this makes using the board module the safest, most reliable way to use your board's pins. It allows you to not worry about what MCU pins the board pins are connected to. This is more of an issue with more complex MCUs built around ARM cores (such as the SAMD or nRF52 families of MCUs).

For example, I2C signals could be connected to the MCU in various ways (which we will not go into) but using the board module you can simply do:

import board
import busio

i2c = busio.I2C(board.SCL, board.SDA)

This will work in CircuitPython on any supported board.

So how do you know what pins are available on your board? And what they're called? You can use CircuitPython's dir function. This is on a Circuit Playground Express:

>>> import board
>>> dir(board)
['A0', 'A1', 'A2', 'A3', 'A4', 'A5', 'A6', 'A7', 'A8', 'A9', 
 'D10', 'D12', 'D13', 'D2', 'D3', 'D4', 'D5', 'D6', 'D7', 
 'D8', 'D9', 'I2C', 'IR_PROXIMITY', 'IR_RX', 'IR_TX', 'LIGHT', 

And this is on a Gemma M0:

>>> import board
>>> dir(board)
['A0', 'A1', 'A2', 'APA102_MOSI', 'APA102_SCK', 'D0', 
 'D1', 'D13', 'D2', 'I2C', 'L', 'RX', 'SCL', 'SDA', 'SPI', 
 'TX', 'UART']

You can see that there are some pins in common, but also ones that are board specific.

This guide was first published on Oct 22, 2018. It was last updated on Oct 22, 2018.

This page (The board Module) was last updated on Oct 14, 2018.

Text editor powered by tinymce.