Avra Kedabra

Table of Contents

Deep arcana

I am, for one reason or another, attempting to build a PAL output serial terminal. Let's just assume that's a reasonable thing to do because my writing style doesn't really sustain getting bogged down in explaining myself.

Having learned over the years that diving straight in the deepend doesn't always produce results, I've decided that for my first pass I should probably do this with more modern technology, and have opted to use the microcontroller that is ubiquitous in my life, a knockoff Arduino Pro Micro. This board sports an Atmel ATmega32u4 which is most common in hobbyist USB keyboards which is why I have them just kicking around everywhere.

Saucery

I'm not great with electronics outside of some real basics of digital electronics and this is a truly analogue project where voltages matter, so I'd be pretty lost without this amazing page where the author builds PAL games out of PIC microcontrollers. They step through all the theory beautifully and then the practicalities of getting the full range of voltage outputs necessary for character output on 2 IO pins. Perfect for me, so I'm not going to paraphrase - if you want to understand just read it!

Avra Kadabra

The article says that timings are incredibly important, and I can only assume that's true because my attempts at producing PAL output in C didn't appear to do the trick as far as a TV was concerned, and looking at it under a logic analyzer I also have my suspicions. Timing sensitive C is not my forte, so I started to take a stab at AVR asm.

For whomever comes after me, I'm leaving these words together so that modern search engines (as fucking unhelpful as they are) can still point you to the right place: atmega32u4 avra assembly

The assembler

You're looking for avra which is available under a few distros - in Arch it's in the AUR and builds and installs with no problem.

The invocation is:

avra -I ./include -o main.hex main.asm

… which will produce a flashable hexfile (if you're converting your makefile from C to ASM don't leave avr-objcopy in or you'll spend hours flashing garbage to your controller). The equivalent Makefile is below:

AS=avra
ASFLAGS=-I ./include

%.hex: %.asm
  $(AS) $(ASFLAGS) -o $@ $<

Notice I'm using a local include/ directory…

The chip

avra does not ship with the definitions required for the ATmega32U4. It ships with the definitions for the ATmega32 which, if you compare with the datasheet, does not put the registers at the same memory locations.

I'll save you some effort here:

mkdir include
cd include
wget https://raw.githubusercontent.com/DarkSector/AVR/master/asm/include/m32U4def.inc

For some reason or other the chips need to be hardcoded into avra too, and it only has definitions for the ATmega32, and will complain about the .DEVICE directive in the include pointing to a microcontroller it doesn't know.

You need to change the .DEVICE definition to ATmega32 and it will work just fine (at least for simple IO use cases). You can double check what your version of avra supports by doing avra --devices

Do the include

With the avra flags set as above and the modified file in your local include directory, all you need to do then is:

.include "m32U4def.inc"

And you can refer to the port definitions by their friendly names :)

In my case I'm actually liable just to cherry-pick the bits I need out once I've got my PoC, as PAL is actually super simple and I only really need the definitions for DDRD and PORTD

Flashing

It would be pretty unfair of me to not share a working solution, so here's my entire Makefile

.ONESHELL:
SHELL=/bin/bash
TARGETS=pal.hex
DEFAULT:$(TARGETS)
CC=avr-gcc
AS=avra
ASFLAGS=-I ./include

%.hex: %.asm
        $(AS) $(ASFLAGS) -o $@ $<

flash_%: %.hex
        while ! avrdude -p m32u4 -c avr109 -U flash:w:$<:i -F -P /dev/ttyACM1; do sleep 1; done

clean:
        rm -f *.bin *.hex

Notables:

  • I've been lazy and hardcoded in the port for flashing /dev/ttyACM1 - this is trivially fixable
  • avrdude is in a loop so that I can dispatch the command and then reset the microcontroller to flash
  • clean doesn't have all the targets yet, but now is the time for writing, not for fixing. avra dumps a bunch of stuff out to disk.
  • In this format the invocation is make flash_pal for e.g. pal.hex

Validate