Building CircuitPython with Dan Halbert
S05:E40

Building CircuitPython with Dan Halbert

Episode description

CircuitPython core developer Dan Halbert joins the show and shares how to build CircuitPython from source.

Dan was previously a guest on episode 28.

Follow the show on Mastodon or Bluesky and join our newsletter.

00:00 Intro

00:24 When would someone want to build CircuitPython?

2:23 The pre-requisites for building CircuitPython and the Building CircuitPython Learn Guide

5:15 Building for different hardware ports using git submodules

6:46 Usage of Python in the build process and virtual environments

9:11 Asking for help in the Adafruit Discord

9:34 Adding a new board to CircuitPython and How to Add a Board Learn Guide

13:58 Obtaining a vendor ID and product ID

16:49 Adding the board to circuitpython.org and its Learn Guide

18:13 Advice for building CircuitPython (XKCD)

21:10 Wrap-up

Download transcript (.srt)
0:00

Welcome to the CircuitPython Show. I'm your host, Paul Cutler. This episode I'm joined by CircuitPython Core Developer Dan Halbert. Dan first visited the show back in episode 28, which I've linked to in the show notes. Dan, welcome back to the show.

0:17

Thank you very much, Paul. It was great to be on last time and I'm really looking forward to this session as well.

0:23

In the last episode, I chatted with Brayden Lane about designing a PCB. That's a time when someone might want to build CircuitPython for their new board.

0:31

When else would someone want to build CircuitPython from source?

0:35

There are a bunch of different reasons why somebody might want to build CircuitPython. I mean, one is just to see how it's done.

0:42

But usually somebody has some motivation.

0:45

One thing that happens often is that they want to turn a feature on or off.

0:49

or they need to make room, they want to turn on a feature and we say oh that feature doesn't fit,

0:54

but if you turn on this off this other thing you can turn on this thing and so that's a common

1:00

reason to do that. Another common reason is that they've got some new board that they want to

1:05

support and so they want to try to make a build for it and test it and then maybe submit it as

1:12

a pull request if they think that other people would be interested as well. Another reason is

1:17

because they want to add some frozen modules, because they want a build that comes with some

1:23

libraries already built in. For instance, they want to distribute a build to some other, to

1:28

like users of their software, for instance, something like that. And yet another reason is

1:35

that there's a problem and they want to debug it. So there's, it could just be that they want to

1:42

run a debugger or put in some logging printouts. We might suggest that if they're having trouble.

1:50

Or they might want to do what's called a git bisect, where you take two versions and you like

1:56

take some versions, you know, have a version that you know works and to say the latest version

2:00

doesn't work. And then you want to find out, well, where was the change that broke it? So what git

2:05

bisect does is that it divides things up. It'll go to the middle of that range of commits.

2:12

And then you say, it did work or it didn't work. You build it and say it did work or it didn't work.

2:16

And then it keeps dividing. It does a divide and conquer thing until you get down to the commit.

2:22

So let's dive in. What is the process for building CircuitPython? What are the prerequisites?

2:27

What should someone think about before they start?

2:29

Sure. Well, first of all, I would say before you start building it, you have to look

2:33

at the building CircuitPython guide, which you can find on learn.adafruit.com. And we try to

2:40

keep that guide up to date. Just before this podcast, I was reviewing it and I found a bunch

2:46

of things that I wanted to update. So if you find something that's broken, tell us.

2:52

We do development of CircuitPython on Linux. I use Ubuntu version 24.04. Jeff uses Debian,

3:02

but it's very close to that version because Ubuntu is a Debian-based distribution. Scott uses Arch,

3:09

which is kind of more up to date, but he also knows how it differs from kind of more vanilla

3:15

distributions. So in all cases, it's easiest if you start with a Linux distribution. And that's

3:22

what I'd recommend if you're at all familiar with command line stuff, even if you're already

3:27

familiar with command line stuff, say on Mac OS, you can build on Mac OS, but there are always

3:33

things that change. So I'd say start with Linux. And there's some descriptions about how to do

3:39

Then, just go through that build guide. There's a bunch of pages under the introduction page

3:46

about how to set up your system to build. You have to install a bunch of packages, both

3:52

system packages and also Python packages. There's a page about setting up for Linux.

3:58

There's a page for setting up under Mac OS, which details some idiosyncrasies. There's

4:09

basically Linux running inside Windows, and it really is pretty much just like using Linux.

4:15

So it's kind of a substitute for setting up Linux instead of using a virtual machine.

4:20

In many ways, it's somewhat easier. So there's a page for that. And then there's some stuff

4:26

about, well, if you had some more idiosyncratic Linux distribution, how you use that. And

4:32

I'll also say that there's something that which I haven't tried, but there's a technique

4:36

for using GitHub Codespaces, which lets you use kind of a pre-packaged Linux environment,

4:42

and there's a link to that. User Bablock B has described how to do that. There are a

4:48

whole bunch of steps of getting things set up, and then it's best if you fork CircuitPython.

4:55

You could use the Adafruit, you could clone the Adafruit thing, but if you're thinking

4:59

of making any pull requests or anything like that, it's probably easier if you fork it.

5:03

a branch right away and then just start building and follow the instructions. If you're building

5:11

on Espressif, there's a special page for that as well. So what are some of the different things

5:17

that someone might want to know between the different ports between a Broadcom build and

5:22

an Espressif build? Are there any big gotchas that come to mind? Sure. So many of the ports

5:27

are straightforward. We use git submodules a lot which pull in various pieces of third-party

5:35

software. So for each port, in most cases, there's some port-specific submodules that you need to add.

5:44

There's a description in the build guide of how to fetch submodules. You can fetch all the

5:49

submodules for all the ports. That takes a long time, and if you're on a slow network connection,

5:54

you might not want to do that.

5:56

You can also fetch the sub modules for just a specific port

6:00

and that's explained in the guide.

6:02

So once you have the sub modules,

6:05

then you can just pick a board in that port

6:08

and type make capital board equals

6:11

and the name of the board.

6:13

And it will start building that.

6:15

If you typed make in a ports directory without,

6:19

without a board name,

6:20

but actually will list you all the board names,

6:22

Which for say the Espressif port, there can be, there's more than a hundred or

6:27

hundreds even, that's an easy way.

6:30

If you don't remember the board name, or you could look in the boards directory

6:33

and find the directory name, that's the board name.

6:36

For example, on the Espressif builds, it actually pulls in its own Python virtual

6:41

environment and builds within that.

6:43

So the user doesn't have to do that.

6:44

Is that correct?

6:45

You have to run some scripts to set up what it needs for Python.

6:51

I'll back up a little bit to say that we use Python a lot in the build process.

6:57

It used to be say in Ubuntu 22.04 that we just install various Python

7:03

modules and libraries right into your own user space, okay, where you, and you'd

7:09

share that with all your other uses of Python beginning in Ubuntu 24.04.

7:16

You can't do that.

7:17

You have to create what's called a virtual environment or a VM.

7:21

There are directions for how to do that in the build guide. So you're right, Espressif sets up its own VM. And if you have one already set up, you can't set up a VN inside of VN. So the Espressif build tools will complain and say, you can't do that. And so I describe in the Espressif builds page how to get out of your VM and get into their VM that they create.

7:44

For the Broadcom ports, those are very unusual. Those are these, they run on bare metal Raspberry Pi, you know, 345 say and Pi Zero. We're not talking about Pi Pico, okay? There are a lot of things named Raspberry Pi, but we're talking about the boards that can run Linux.

8:05

And in that case, you need a separate version of the GCC compiler and its associated tools that specialize for that Broadcom chip. Or it's called a Cortex-A chip. It's a kind of ARM chip. Most of the other boards are Cortex-M ARM chips. Not all of them, but many, many of them are.

8:28

So, to back up a little bit, one of the things you have to do to do a setup is install the

8:36

GCC toolchain that's maintained by ARM in most cases.

8:41

The Expressif build tools do that for you, but in most cases you have to do it by hand.

8:46

And we describe how to do that and which version to use, because if you use the wrong version

8:49

of the compiler, too old or too new, then you're going to get compiler errors.

8:54

You're going to get compilation errors when you do a build.

8:56

So pay attention to that in the build guide.

9:00

It's definitely something that people need to pay attention to.

9:02

It's very easy to get the wrong version of GCC.

9:05

Yeah, exactly.

9:07

And I also would say that this is a detailed, very complicated process, and you're probably

9:15

going to get stuck at some point.

9:17

And feel free to ask for help in Discord in the CircuitPython dev channel, which is where

9:24

the developers hang out and we can help you along and get you over whatever stumbling block that

9:30

you're encountering. That's good advice as well. So we've gone through the guide and we've got

9:36

CircuitPython building from source and we've got our PCB that we designed in our last episode as

9:41

well. What needs to happen next to add that board to CircuitPython? So what you might want to do is

9:48

find a board that's kind of like your board. You made a simple SAMD21 board, say. And I think

9:55

Bradan Lane's board, I'm not sure which chip it is. I think it's one of the SAMD chips.

10:00

>> I believe so.

10:00

>> Yeah. So find a board that's like your board, look in the boards directory in the port for your

10:08

chip and, or chip family, and just find one that's pretty similar. And in that boards directory,

10:14

you'll find a bunch of files. There's mpconfigboard.h, mpconfigboard.mk, pins.c, and board.c.

10:26

And those all need to be customized for your particular board. In some cases, you can use the

10:32

boilerplate version of those and change just a few things. But the easiest thing to do is create a

10:38

directory for your new board, give it a name, put the manufacturer name at the front of the name,

10:43

and then the name of the board and separate them with underscores. And then copy some board files

10:51

from the most similar board and then start editing them. It's always better to start by

10:57

changing an existing thing than starting from scratch. There's also for expressive boards,

11:02

there's yet another file called SDK config that you also need to copy and change. So

11:13

and its USB identifiers and some other things like how much flash there is, which flash chips

11:21

you're using. Pins.c gives the name of the pins and also other things that are in board,

11:29

like board.i2c or board.stemi2c if you have a stem connector. And board.c has optionally routines

11:39

that set up the board. Like you have an if you have an on board display, then you want to write

11:44

some code that runs as soon as the board starts that sets up the display so you can see the REPL

11:50

output on the display. On many boards that don't have display, board.c is just empty. It uses some

11:58

default routines. So all those things happen and then you can do a build and then try to copy the

12:05

the UF2 or the dot bin onto your board and see what happens.

12:11

Usually you can just do run make over and over again.

12:15

If you make certain kinds of changes,

12:17

like you add new strings or new error messages

12:21

or a new MPQster, which is a special kind of string name,

12:25

then do a make clean first,

12:28

because otherwise you'll get weird errors.

12:32

And that's also true in Espressif.

12:34

if you make some changes to the ESP IDF settings,

12:38

then you'll need to do a make clean,

12:40

because otherwise it won't rebuild the ESP IDF part

12:44

of the base software, rebuild that.

12:47

- When you're updating the pins.c file

12:50

with the pin information, this is the file

12:53

where you want to match the silk screen

12:55

to what you put into the pins file, is that correct?

12:57

- Yes, there's a guide called,

13:00

how to add a new board to CircuitPython,

13:03

And that describes in detail about changing these,

13:07

copying these files and changing them.

13:08

It's not in the main building sort of Python guide,

13:11

but it's in the sidebar of that guide.

13:15

So that describes how to change all these.

13:16

And it describes also kind of the naming conventions

13:20

for the pins.

13:21

Like you do want to make them match up with the silk.

13:24

If they're just numbers, they can't be that.

13:26

So it says like put a D or a GP or an IO in front,

13:30

depending on the board family.

13:32

Look at an existing board and in that board family, there's like a sort of a typical nomenclature.

13:39

There are often canonical names for things. So try to copy those names if you can. The best reason

13:46

for copying names is that it means that any particular piece of software can run on more

13:52

than one board without changes or with easy changes. Oh, that makes sense. I hadn't thought

13:56

about that. One of the things you mentioned in passing earlier was that you need to have a vendor

14:02

ID and a product ID for the USB device. When and how does someone get a VID and a PID to add to their device?

14:10

Yeah, that can be a sticking point. So USB vendor IDs and product IDs are both 16-bit numbers. So a vendor ID comes from the USB organization. Maybe it's a foundation, I can't remember. But it's at usb.org. And in order to get an

14:32

one, you have to pay thousands of dollars. All right? So Adafruit got one a long time

14:41

ago and most manufacturers of some size got them. But that's a lot of money if you're

14:47

just building a hobby board or something like that. So how do you get around that problem?

14:52

Well, you could just invent or reuse USB, VID, and PID, but we're not going to add

15:00

that board to the list of CircuitPython boards if you invent one or just make one up because

15:05

it's unofficial and it's sort of like not, it's easy to get in trouble that way, kind

15:11

of.

15:12

Sure.

15:13

It's true that many manufacturers, small manufacturers, steal the IDs and PDs or just make them up,

15:20

but don't do that.

15:21

So there are a few USB vendor IDs that are retired and some people have taken over those

15:31

vendor IDs and have been issuing product IDs under those vendor IDs.

15:36

There's a website called pid.codes which you can go to and get one for free.

15:43

It involves submitting a pull request to a GitHub repo and Scott is one of the people

15:49

who can assign vendor IDs through that repo. If you're making a, an expressive board or

15:58

a Raspberry Pi RP2 something board, then you can apply to those manufacturers for a product

16:08

ID and they will assign you one. Usually only takes a week or two. There's a mechanism for,

16:14

both of those to do that. You use their vendor ID and they are allowed to give away product IDs

16:22

under that vendor ID. So both of those things will work.

16:27

>> So that's almost something you want to be doing in parallel while you're

16:30

building CircuitPython for the first time since it takes a week or two to get one.

16:33

>> If you are interested in submitting a board, yes. If you just want to build CircuitPython,

16:38

you don't have to do this at all. Or if you just want to experiment and build your own board,

16:43

Nobody cares what the product ID, you know, you're not distributing it. So it doesn't matter.

16:49

So for those who are distributing it, we've got CircuitPython running on our new board with a VID

16:53

and PID. You want to add it to CircuitPython.org so it gets built every time when a new version

17:00

of CircuitPython is released. How does that process work?

17:03

Okay, so it gets built whether or not it's on CircuitPython.org. CircuitPython.org doesn't

17:09

determine what's built. What determines what's built is what's in the CircuitPython source tree.

17:14

But for it to show up as something that you can download, when you submit a pull request to

17:22

CircuitPython data board, we ask that you submit a parallel pull request to CircuitPython.org.

17:30

And that's also explained in the how to add a new board to CircuitPython. So there's sort of a

17:39

There's a fixed set of features that you can say it does or doesn't have. And we want you to take

17:45

pictures of it, clear pictures, and supply three different pictures in different resolutions. And

17:52

that's all explained in the "How to Add a New Board to CircuitPython." When this happens, you

17:57

know, when you start submitting a pull request, like it's going to go through, go ahead and submit

18:02

a pull request to circuitpython.org, or we'll remind you. Because we're not going to finalize

18:07

the whole thing until both of those things are ready. That makes sense. Thinking back through

18:13

this process, are there any things that come to mind where people get stuck or challenges that

18:18

they seem to run into more often than not? I would say make sure that you install the

18:23

correct version of GCC. A lot of people just say, "Oh, I'm just going to install the one that comes

18:28

from Ubuntu." The compiler that we use for the ARM chips is called ARM-NUN-EABI-GCC. But if you just

18:37

the version that comes in the Ubuntu or Debian distribution, it's the wrong one. So don't do that.

18:45

Another thing is we haven't mentioned, but is that we use pre-commit, which is the thing that reviews

18:53

your changes before you make a commit, and it checks formatting and other things like that in

18:58

advance. And so it's explained in the build guide about how to set up pre-commit. That will save you

19:05

a lot of round trip time because otherwise you'll be making simple, say formatting mistakes.

19:13

And when you submit the pull request, you'll have to wait for the bill to complete and

19:17

then it will take a long time.

19:18

So pre-commit will check for that stuff in advance because we run pre-commit when you

19:23

submit a pull request also.

19:24

So it's, you got to pass that one way or the other.

19:27

That makes sense.

19:28

Yeah.

19:29

Getting, getting the expressive field right is, is a lot of trouble.

19:33

So we sometimes have to guide people through that.

19:36

And dealing with the Python virtual environments

19:40

is tricky because a lot of people

19:42

haven't used that in the past.

19:43

And also, when in doubt, do a clean build in case

19:46

you're getting odd build errors because you may obtain

19:49

something in which you need to start from a clean build.

19:56

And if you're building on Mac OS,

19:58

getting the right Python version is very difficult.

20:02

you know there's an XKCD cartoon about how much trouble it is to set up Python properly.

20:08

And how many different versions of Python there can be available on macOS. So that's

20:15

a problem.

20:17

>> I'm on a Mac running homebrew and I run into that all the time. So that is definitely

20:20

something that people should be looking out for.

20:22

>> Yeah. Yeah. And there's so many versions of macOS and things change abruptly. You know,

20:30

keep the same Python version for a while, and then they jump up several versions. And it's just really confusing. And there's just a lot to learn here. If you haven't used Git before, you got to learn Git and GitHub. There's just a lot going on here. And so, you know, we try to make a recipe. But it's important that you try to spend some time and do some studying about things that you don't know about so that when something goes wrong, which invariably will, that you can

21:00

have some understanding of like, well, what is really going on here? Why is this error happening?

21:08

But we're happy to help you along. That's definitely good advice. And if people get stuck,

21:12

again, come to the CircuitPython dev channel on the Adafruit Discord, and you and the other core

21:17

developers can sometimes help them out. Yeah, yeah, very much. Well, this was all good advice.

21:22

Dan, thanks so much for being on the show. You're very welcome.

21:27

Thank you to Dan for sharing his knowledge of building CircuitPython. For show notes and

21:31

transcripts, visit www.circuitpythonshow.com. Until next time, stay positive!