Neil's assignment for this week:
individual assignment:
    browse through the data sheet for your microcontroller
    program a microcontroller development board
      to interact (with local input &/or output) and communicate (remotely)
    extra credit: use different languages &/or development environments
group assignment:
  compare the performance and development workflows for other architectures
    

Group Work

Group work for the week is documented here. Probably the biggest thing I got out of the group work personally was a chance to look at the Seeed Xiao modules, which I hadn't used before. Impressive specs, and the ability to solder them directly onto a PCB really opens up some possibilities!

Introduction

I have quite a bit of experience with embedded system programming on the Arduino platform, so I'm going to challenge myself to try some new methods and techniques. I also know that my final project might involve some fairly intensive floating-point computation, so I need to learn to use a modern high-end processor. My final project will also use some advanced mathematics, for which Python libraries already exist, so I'll see if I can use these libraries on the microcontroller rather than reinventing the wheel. My initial goals for the week are listed below, marked with ✓ if I succeeded, ✖ if I had problems, and → if I deferred the task or went in another direction.

Espressif ESP32C3 Datasheet

As a first step, I browsed through the ESP32-C3 Datasheet, which will be my focus for this week. Major features of the ESP32-C3 processor:

Seeed Studio XIAO-ESP32 Features

I'll be using a microcontroller chip built into a tiny Seeed Studio Xiao microcontroller board. This board can be either plugged into a breadboard for prototyping, or soldered onto a PCB for a finished design. I read through the Getting Started with Seeed Studio XIAO ESP32C3 guide to learn about the features that make it a big step up from the "bare chip" ESP32:
Xiao ESP32C Pinout
Pinout for Seeed Studios Xiao ESP32C

Comparing Development Workflows

Since I'm going to be teaching this class in the future, I decided it was worthwile to compare several development systems, to find out what's best to recommend to my students. Here's a summary table of the processors and development environments I worked with, with links to my methodology and a brief statement of problems I encountered.
Arduino Uno Rev3Seeed Studio XIAO-ESP32Seeed Studio XIAO-SAMD21C
Arduino IDE Success (group work) Success Success
CircuitPython Incompatible Failed Success

Basic Arduino development for the ESP32C

To set up the Xiao ESP32C for use with Arduino, I followed the Seeed Studios Getting Started with XIAO ESP32C3. Specifically I did the following: When I first tried this, I had trouble with port selection and uploading. Turns out I had a bad USB-C cable: replacing it fixed the problem.
circuit diagram for blink sketch
Circuit diagram for the blink sketch (from Seeed Studio documentation

Basic CircuitPython development for the ESP32C (Failed)

I tried to set up the Xiao ESP32C for use with CircuitPython, and had trouble. (I'm giving a brief summary here rather than a detailed procedure, because my steps won't help anyone.) I followed these instructions for installing CircuitPython onto the ESP32C. It was fairly complicated, but in theory it only has to be done once.

Next I installed the tools we need to start writing code for the board. I downloaded, installed, and launch the mu editor. Then I switched into CircuitPython mode in mu. Here's where things went wrong: mu failed to recognize the Xiao as an ESP32 device.Apparently the C3 version of the ESP32 doesn't have native USB support, which is something CircuitPython more or less relies on. I also tried MicroPython but that didn't work either. Looks like if I want to use an ESP32, I have to use either Arduino or Espressif's own development toolchain.

Basic Arduino development for the SAMD21C

Since I really want to try out CircuitPython, I switched to the Xiao Seeeduino SAMD21C, which is based on the ATSAMD21G18A-MU processor. To set up this board for use with Arduino, I followed the directions on Seeed's site:
resetting seeeduino xiao
Resetting the Seeed Xiao SAMD21. Image from Seeed Studios.
Here's where I had trouble: during upload, the Arduino IDE got stuck on "Uploading..." forever, or sometimes eventually said "No device found on COM4" and wouldn't upload. Following Seeed's advice on resetting the board didn't help.

But what did fix the problem was this advice, which says that many of these chips can be forced to listen to the PC by double-tapping the reset button. The orange light should start glowing solidly. This is contrary to Seeed's advice, which is to do a single-tap. There's also the problem that the Xiao board doesn't actually have a reset button: instead it has two metal pads that you short together with a piece of wire (see image at right).

With a double-tap reset, the Seeeduino resets into "Direct Firmware Uploader" (DFU) mode: it reconnects to the PC and looks like a flash drive. It also will actually listen to programming requests from Arduino over the COM port. Two annoyances: Windows asks me what to do with this "new disk drive" every time I upload, and bizarrely, programming the Arduino briefly disconnects my USB headset, which I don't understand but doesn't do any harm. From here Arduino programming works normally, as described above.

Basic CircuitPython development for the SAMD21C

And now let's try out CircuitPython. Seeed has detailed instructions on setting this up, which is always a good sign.
Installing CircuitPython firmware
Installing CircuitPython firmware. Just drag-and-drop!

Using the Mu editor with CircuitPython

While you can program a CircuitPython board just by saving a file created in any editor, the "Mu" editor has some handy special features that let you talk to the Xiao in real time. To set it up:

Joystick Julia

I wanted to create something that satisfies the homework requirements for this week (program a microcontroller development board to interact (with local input &/or output) and communicate (remotely)) that would give me some insight about floating-point math on current-generation microcontrollers. So I wrote some code to generate Julia set fractals based on joystick input and print them out over the serial port.

How do you do computer graphics over a serial port? I used a simple text-based system, where " ", ".", "o" and "O" represent increasing "brightness".

I used "spiral design" to build this. First I just created a Julia set generator with no electronic inputs, just serial port output, and tested this in both CircuitPython and Arduino. CircuitPython was too slow to be useful. Then I added the joystick and the code to interact with it, writing my final version for Arduino only.

About Julia Sets

Julia sets are a type of fractal closely related to the famous Mandelbrot set. They are generated using the following algorithm:
  1. Pick a number \(c\) in the complex plane.
  2. For all numbers \(z\) in the complex plane,
    1. Calculate a new \(z = z^2+c\)
    2. Repeat, iterating over and over.
    3. If \(z\) heads off to infinity, it is not a member of the Julia set. If it doesn't, it is.
  3. Plot the values of \(z\) that do or don't head off to infinity on the complex plane. Typically the number of iterations before each point "runs away" is shown with a color map.
There's only one Mandelbrot set, but there are an infinite number of Julia sets, one for each value of \(c\), whose shapes resemble anything from circles to snowflakes to dragons to butterflies. Examples are shown below!

Raw CircuitPython on SAMD21C

First, a CircuitPython version of the basic Julia generator with no joystick input. (source code is found in my repo). It doesn't use any special libraries, and has functions to do math on complex numbers. I didn't bother with classes, my complex numbers are just 2-element arrays.
Output of CircuitPy Julia Set code.
Here's the output from the CircuitPython version of the Julia set code for c = −0.8 + 0.156 i. Notice how slow it is: 21 seconds to calculate this!
Wikipedia Julia set image
This is what the Julia set looks like for c = −0.8 + 0.156 i when calculated using an actual computer.
Output of CircuitPy Julia Set code.
Another Julia set, this one for c = 0.28 + 0.008 i.
Karlsims.com Julia set image
What it looks like on an actual computer (this is for a sliiightly different c = 0.285 + 0.01 i.

Arduino on SAMD21C

Next, an Arduino version of the basic Julia generator with no joystick input. (source code in repo). This runs about 20 times faster than the CircuitPython version!
Output of Arduino Julia Set code.
Arduino version of the Julia set code for c = −0.8 + 0.156 i. Notice how fast it is: 1.04 seconds to calculate this!
Better Julia
Here's another Julia set for c = 0.37 + 0.37 i. I fine-tuned the iteration counts and ".oO" scheme to get better detail.

CircuitPython with ulab (Failed)

Python is, as expected, extremely slow. In desktop python, there's a "numpy" module which is designed to make math operations fast and easy. In CircuitPython, this is implemented using the "ulab library. I tried to get this working, but it looks like ulab is not installed in the SAMD21C version of CircuitPython. It's possible to recompile the CircuitPython firmware to include it, but that's more of a pain than I have time for right now.

This leaves us in an awkward position: for my final project, I need ulab and CircuitPython. CircuitPython won't run easily on the ESP32 processor, ulab is difficult to set up on the SAMD21C, and it looks like the SAMD21C might be too slow anyway. Conclusion: I think I need the RP2040 version of the Xiao!

Final version with joystick control

Finally, we add joystick input to allow the user to select a value of \(c\). This is, of course, a ridiculous input method: nobody would do this unless it was for an assignment that has to both "interact" and "communicate". But it ended up being pretty fun!

Here's the circuit diagram for the joystick and button. The joystick is just a pair of potentiometers in a convenient package. I used a separate button rather than relying on the "push to click" feature of the joystick, because pushing in on it always messes up my aim.

I also took the time to fine-tune the "brightness values", to get more detail with my ".oO"-based graphics system. See the video below!

Photo of Joystick Julia circuit
The completed Joystick Julia circuit.
Here's how it works. When you plug it in and start the serial monitor, the Xiao sends a constant stream of data showing the current value of \(c\). You adjust its real part with the X-axis of the joystick, its imaginary part with the Y-axis. When you press the button, a Julia set will be calculated and printed on the serial monitor. The Xiao then pauses and waits for you to click again, before starting the stream of \(c\)-values to pick another.

Screen capture of Joystick Julia in action. On the left is the output from the serial monitor, on the right is a Wikipedia image of the particular Julia set I'm trying to capture.

Of course this would be much better with an LCD touchscreen. Or just as a mobile phone app. Frankly, doing text-based graphics for a fractal image with joystick input is pretty ridiculous. But it satisfies the homework requirement, it taught me a lot about the tools I'll need for my final project, and I think it's pretty neat.

Design Files