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.
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!
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
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…
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
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
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
/dev/ttyACM1
- this
is trivially fixableavrdude
is in a loop so that I can dispatch the command and then reset the
microcontroller to flashclean
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.make flash_pal
for e.g. pal.hex