dcreager.net

PyBadge notes

I want to install the Uxn emulator for the Adafruit PyBadge. The default instructions have you install the graphical IDE. I'd rather do things through the command line.

PyBadge Uxn emulator

Arduino IDE instructions

Initial setup

The Arduino CLI is available in Pacman.

$ sudo pacman -S arduino-cli

Per the IDE instructions, we have to make sure to add the Adafruit URL as an additional board manager URL.

$ arduino-cli config init
[edit ~/.arduino15/arduino-cli.yaml]
$ head -n 2 ~/.arduino15/arduino-cli.yaml
board_manager:
  additional_urls: ["https://adafruit.github.io/arduino-board-index/package_adafruit_index.json"]

Install the PyBadge board and Arcada libraries.

$ arduino-cli core download arduino:samd
$ arduino-cli core install adafruit:samd
$ arduino-cli board attach -b adafruit:samd:adafruit_pybadge_m4

Plug in the PyBadge and update its bootloader. (Follow the recommendation to double-check which cable you're using, to make sure it's not power only!)

Updating the PyBadge bootloader

[double-press reset button]
$ sudo mount /dev/sda /mnt
$ sudo cp ~/Downloads/update-bootloader-arcade_pybadge-v3.15.0.uf2 /mnt
[wait for bootloader to update and PyBadge to restart]
$ sudo umount /mnt

Compile the Uxn emulator.

$ arduino-cli compile uxn-pybadge.ino

Upload the emulator.

$ arduino-cli upload -p /dev/ttyACM0 uxn-pybadge.ino

It's not currently working! The filesystem doesn't exist, and so I can't follow the emulator README's instructions for uploading a Uxn ROM.

To debug and see the serial console output:

$ arduino-cli monitor -p /dev/ttyACM0

[Note that I think you have to time things carefully so that /dev/ttyACM0 exists for the command to succeed. But that device file doesn't exist until you plug in the PyBadge. So if you time things poorly you might miss the first couple of serial port output lines.]

Flash filesystem

I was able to get the flash filesystem to work in the Arduino IDE. It required adding the Adafruit TinyUSB and Adafruit SPIFlash libraries in the sketch. (This just adds the relevant include directives to the sketch's .ino file — it seems that the compile step uses the include directives to determine which libraries to compile and link into the final executable.)

#include <Adafruit_TinyUSB.h>

#include <Adafruit_FlashCache.h>
#include <Adafruit_SPIFlash.h>
#include <Adafruit_SPIFlashBase.h>
#include <Adafruit_FlashTransport.h>
#include <flash_devices.h>

I also had to choose “Tools › USB Stack › TinyUSB” to activate the TinyUSB implementation.

Next step is to figure out how to reproduce all of the above with arduino-cli. The library inclusion step should be persistent, since that updated the actual .ino file.

Having read through the source of the Adafruit libraries, my hunch is that the TinyUSB menu option just adds -DUSE_TINYUSB to the compilation flags. I was eventually able to find this description of how those custom menu options work:

Custom board options

To confirm, I found the following lines in the Adafruit boards.txt file:

$ less ~/.arduino15/packages/adafruit/hardware/samd/1.7.13
[snip]
# Menu: USB Stack
adafruit_pybadge_m4.menu.usbstack.arduino=Arduino
adafruit_pybadge_m4.menu.usbstack.tinyusb=TinyUSB
adafruit_pybadge_m4.menu.usbstack.tinyusb.build.flags.usbstack=-DUSE_TINYUSB

The documentation says that we can for the CLI, we can add the option value to the fqbn while compiling:

$ arduino-cli board attach -b adafruit:samd:adafruit_pybadge_m4:usbstack=tinyusb
$ arduino-cli compile uxn-pybadge.ino

And this worked! I can now upload the (fixed) emulator to the PyBadge.

$ arduino-cli upload -p /dev/ttyACM0 uxn-pybadge.ino

If you hold down the ‹start› button while the PyBadge starts up, the emulator will start in MSD (mass storage device) mode. The PyBadge will appear as a new block device (/dev/sda etc). Mount that and copy a Uxn rom as start.rom. The emulator will run that ROM when it boots.

sudo mount /dev/sda /mnt
sudo cp ~/roms/catclock.rom /mnt/start.rom
sudo umount /mnt

Fixing the interpreter loop

This “worked”, in the sense that the emulator would start and load the rom, but most of the roms I tried wouldn't actually work as they do in uxnemu on the desktop. The serial console shows a lot of “uxn halt” messages. I added some additional debug messages to print out the PC and the instruction byte for every instruction that is executed, both in the PyBadge interpreter and in uxnemu. At some point, some of the traces would start to diverge. This suggested to me that the interpreter loop in the PyBadge emulator isn't correct, though I didn't take the time to figure out precisely how. Instead, I just copied the interpreter loop from uxnemu over to the Arduino project.

[PATCH] Use latest uxnemu emulation loop

And with this patch, roms started to actually work!

Snake game running on the PyBadge

...except that the apple in that snake game always shows up in the upper left corner.

...and none of the clocks show anything.

Fixing the ‘datetime’ device

Turns out that there's a recent patch to use an attached RTC board to provide “real” data when accessing the datetime device. And snake uses the current hour and minute as a poor man's random number generator. So the last change was to partially revert the RTC patch. If it's available, go ahead and use it. If not, fall back on the previous datetime implementation that assumes that the PyBadge was turned on at 2022-02-19 00:00:00, and counts up from there.

RTC board for PyBadge

[PATCH] Use millis datetime device when RTC isn't present