A while ago now I bought an ItsyBitsy M4 Express, and two of their NeoPixel Jewel LED boards from AdaFruit to create eyes for a plastic skull halloween decoration. Until this last weekend, I haven’t had time to play with it much though. Beyond soldering the headers on the board (the two sides, not the end one), and adding some patch wiring to the NeoPixel boards too so I could build up the electronics part on a breadboard to experiment with.
Looking on the AdaFruit site I discovered two things about this board that are going to make the project easier:
- The board runs CircuitPython out of the box (although an older version the I needed to upgrade)
- There is a CircuitPython for Jupyter Notebooks, which is a very powerful way of prototyping Python code straight from a browser.
Did I mention I bought this kit a while ago? Well, turns out the version of CircuitPython on the board was not only old, but old enough to not work with the Jupyter kernel, so I needed to upgrade. On most embedded boards that involves finding a way to hook up a serial console and copying the new firmware to the board using that. Not so with the ItsyBitsy…
Step 1 – The Bootloader Upgrade
First up, it suggested updating the bootloader as the version I had contained a known issue. Connecting the board via its USB to my Mac, and double pressing the reset button on the board made it appear as a USB drive with the name ITSYM4BOOT, Then it was a simple matter of copying the new bootloader image to the drive. As soon as the copy finished, the board rebooted and installed the new bootloader. Perhaps the most painless bootloader upgrade I’ve ever done (and earlier in my career I did a lot of firmware updates on all kinds of boards).
Detailed instructions here.
Step 2 – CircuitPython Upgrade
After the bootloader upgrade, it booted back into the bootloader, so to upgrade the CircuitPython version, simply download the new software image from circuitpython.org, (in my case adafruit-circuitpython-itsybitsy_m4_express-en_US-5.3.1.uf2 since that matches my ItsyBitsy M4 Express board), copy it to the ITSYM4BOOT drive again, and, as before, it will reboot when done. Only this time, it boots back to CircuitPython mode.
Jupyter Notebooks Setup
I’ve used Jupyter Notebooks with Python for data analysis work, and other Python prototyping, so I was intrigued to see how it would work for prototyping embedded code.
I started off following the instructions, opting for the pip command line installation most of the time. I already had jupyter installed, so the first part was very smooth (basically, I didn’t need to do anything). When it came to installing the CircuitPython kernel though, the instructions were not quite as good. I followed the git clone & python setup.py path only to have the build phase bomb out with streams of errors (I’ve never been a fan of distributing software in source form to be compiled on each person’s machine).
After spending a little time trying to find a solution, I tried something “obvious:”
pip3 install circuitpython_kernel python3 -m circuitpython_kernel.install
That just worked and I was able to confirm that the kernel was available. Much simpler than dealing with compilation errors & sandbox violations.
With the board plugged it, I was able to create a notebook using this kernel, and from there run simple code on the board. Controlling the NeoPixels though required one more step.
The NeoPixel products (essentially WS2812B individually addressable LEDs) have a library that AdaFruit supply which can be used to access them easily from Python. The trick though is that the libraries need to be copied onto the board.
While the page about CircuitPython on ItsyBitsy talks about these, the Jupyter Notebook one did not mention it. Simply make a directory called “lib” on the USB drive that the device presents (CIRCUITPYTHON) and copy the required library files into it. For NeoPixel support, neopixel.mpy.
With the library installed on the device itself, I was able to run Python code like this from my browser to control the lights (in this case, turn the middle one on in red):
import board import neopixel pixels = neopixel.NeoPixel(board.A1, 7) pixels = (255, 0, 0)
The board.A1 reference tells the library which GPIO pin the data line for the LEDs is connected to, the 7 tells it how many pixels are in the chain. To set the color of any pixel, just assign an RGB tuple to the LED by index number.
The only negative I’ve found so far with the Jupyter Notebook approach is that where in a more traditional Python environment re-running a block is an easy way to make a change and try something new, some of the calls here did not work when executed a second time.
Not a big problem, and mainly affected the setup calls (like creating the neopixel object). If really needed, a restart of the kernel fixed it.