$ /buzzqrd/blog/


Using CircuitPython on Linux

Sep. 24, 2023


Recently, I got a neat little device from the electronics website Adafruit. The device is called a Proximity Trinkey and is a little USB key with a 48MHz 32-bit processor, 32KB of memory and 256KB of flash. Additionally, the board comes equiped with 2 RGB LED's and a color sensor that can also be used for close-range proximity. All of this for less than $10 in a small, beautiful form!

Now, one of the most intersting parts of this device is how it can be programmed so easily. Now, I am not big on using Python for any kinds of serious applications, but this Trinkey is mostly just for fun, art projects, education, or other similar uses. And, since it is such a fun device, it is also really nice that it is so portable and can be programmed on any computer!

The Trinkey comes pre-loaded with CircuitPython, which is Adafruit's own software used for programming the microcontroller devices that they sell. If you take any of their development boards or little devices like the Trinkey, and plug it into your computer over USB, it will show up as a USB storage device, much like a flash drive. Here, you can find a file called code.py in the root folder of the USB storage drive. This is the source file for the code running on your CircuitPython device!

Plug one of these devices into any computer with a text editor and you can edit the code, save it, and it will be running right on your Trinkey or other CircuitPython device!

Now, when I first got this device, I thought that it would be very easy to use with linux, but it took a little bit to get it working and there were no guides specially for linux. Normally, Adafruit tells you to use the Mu Python Editor to program their devices. I used it once long ago and it was terribly slow and buggy. Also, you would have to install it onto a device first. With this method, you can program your device on any computer. So, I am writing here about the steps that I took to get it working. It is pretty straightforward, once you learn what to do.

Programming the CircuitPython Device

When you first get the device, before plugging it in, open a termial and run the command lsblk, which should give an output similar to this:


NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
sda 259:0 0 478.5G 0 disk
|-sda1 259:1 0 1G 0 part /boot
|-sda2 259:2 0 16G 0 part [SWAP]
`-sda3 259:3 0 488.5G 0 part /


Now, your's won't look exactly the same, but you should see a list of all of your drives, partitions, sizes, and where they are mounted. You should probably be familiar with mounting and unmounting drives in linux. If not, please read up on it and then come back.

Now, plug in your CircuitPython device via USB and run lsblk again. You should now see a new drive that wasn't on the provious list. This is your CircuitPython device.


NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
sdb 8:16 1 64.5K 0 disk
`-sdb1 8:17 1 64K 0 part
sda 259:0 0 478.5G 0 disk
|-sda1 259:1 0 1G 0 part /boot
|-sda2 259:2 0 16G 0 part [SWAP]
`-sda3 259:3 0 488.5G 0 part /


Here, the new sdb drive shows up with only 64K of storage.

If this drive does not show up, you need to keep it plugged in and quickly double-press the reset/boot button on the Trinkey or other device. This should bring up the TRINKEYBOOT drive (or named after whatever other device you have). Mount the drive that apprears and then download the appropriate UF2 bootloader file from Adafruit. You should be able to find an up-to-date .uf2 bootloader for your device from this list of CircuitPython supported devices. Then copy that UF2 file onto the mountpoint for that drive. Once you have done that, the drive should change and restart, becoming a new drive that can be used for the rest of this tutorial.

Now, this drive can be mounted to a directory with a command similar to this:


mount /dev/sdb1 /mnt/mydrive


After mounting the drive, you should be able to see the code.py file inside of the /mnt/mydrive directory (or whatever directory you mounted to). You can edit this with vim, emacs, or whatever you use to edit basic text files. Note that you may need to be root or use sudo to modify the code.py file.


Getting I/O From Your Device

When you program your CircuitPython device, you can use print and input functions to print out and take in text from the user. But where do we get this from?

The answer is with the GNU screen command! It comes pre-installed on some linux distros, but not on some like Arch. To install on arch, just run:


sudo pacman -S screen


Now we can use screen command to connect our USB tty terminal to your current shell.
What we need to do is find the name of the tty, which should be near the bottom of dmesg after you plug in the device.


sudo dmesg


Running this should show a line that says something like this:


usb 1-2: new full-speed USB device number 8 using xhci_hcd
usb 1-2: New USB device found, idVendor=239a,
idProduct=8104, bcdDevice= 1.00
usb 1-2: New USB device strings: Mfr=1, Product=2,
SerialNumber=3
usb 1-2: Product: ProxLight Trinkey M0
usb 1-2: Manufacturer: Adafruit Industries LLC
usb 1-2: SerialNumber: XXXXXXXXXXXXXXXXXXXXXXXXX
cdc_acm 1-2:1.0: ttyACM0: USB ACM device


Here, we can see the USB terminal can be connected to at /dev/ttyACM0. We can use the screen command to connect now:


sudo screen /dev/ttyACM0


We should start seeing things printed out! Unfortunately, this is a bit hard to do if things are only printed once when the device is plugged in.

When you are done, you can exit screen with ctrl+a d.

One issue with screen is that if your device does I/O right at boot, the user won't have enough time to respond to the message. For that we can use tio. Tio can be used in a very similar way to screen, but if you reset the device (via unplugging and replugging or with a reset button), it will automatically reconnect to the tty terminal quick enough to receive the data coming from the device!

I hope that you found this guide useful. If there is something else you think I should add (or if you found a typo), send me an email. Thanks!

buzzqrd