Craft
Craft is a demo running on its own minimalistic demo
platform. The demo platform is based on an ATmega88 microcontroller.
Having successfully built a soundchip out
of a microcontroller together with my friends in kryo, I wanted to tackle the greater challenge
of generating a realtime video signal along with the sound. This is the
result:
Download
- lft_craft (Original video clip, Xvid, 89.4 MB)
- lft_craft_src (Schematics, firmware binaries and source code, 70.5 KB)
Scene reaction
Craft won the Console / Real Wild compo at Breakpoint 2008. I will never
forget the overwhelming reaction from the audience!
Here's the Pouët
page for Craft.
How does it work?
Just like your average 80's home computer, the entire design is centered
around the timing of the video signal.
A typical VGA-based, low-resolution CRT monitor will redraw the screen 60
times per second using an electron beam, which is sweeping across the screen
one line at a time. TFT monitors work differently, but the VGA signal is still
based on the idea of an electron beam. Timing is crucial: One display line
takes 24 μs, and is followed by a 7.75 μs break called the
horizontal blanking period. After 480 such lines, there's a longer break
(1428.75 μs, equal to 45 full display lines) before it all starts over.
Two digital signals are used to synchronize the sender (graphics card, custom
demo hardware etc.) and the receiver (monitor). They are called the horizontal
sync and the vertical sync signals. It's OK to deviate a bit from the standard timing
values as long as you keep the sync signals steady.
The microcontroller is clocked at 20 MHz. If we convert the figures
above into clock cycles, we get 480 cycles of visible pixels, 155 cycles of
horizontal blanking and 45 full display lines worth of vertical blanking
— but during those lines you need to keep generating the horizontal sync
pulses. Due to rouding errors, we get a frame rate of 59.99 Hz, but that
is well within the tolerance range of a computer monitor.
Music
Sound is generated during the horizontal blanking periods. That gives a
sample rate of 31496 kHz. Of course, only the really timing critical part
(waveform generation) is performed during the horizontal blanking. Melody,
rhythm, amplitude envelopes, arpeggios etc. are handled by a playroutine which gets called
once for every video frame, during vertical blanking.
There are four sound channels in total, each with its own fixed waveform.
The waveforms are 4-bit triangle, 50% pulse, 75% pulse and white noise. The
noise is generated by means of a 15-bit shift register. The volume of each
channel can be individually controlled, except for the triangle channel, which
is always playing at full volume. This minimalistic softsynth was of course
inspired by the NES sound chip.
Video
Apart from the sync signals mentioned above, a VGA signal contains three
analog voltage lines — red, green and blue — that vary between
ground and 0.7 V during the visible parts of the video frame. As you can
see in the schematic below, I perform a two-bit digital-to-analog conversion
for each of these signals, using R-2R resistor ladders. That way,
the software can change the current colour in a single clock cycle using the
out PORTC,register instruction.
In addition to this,
I've hooked up a couple of diodes and a PNP transistor in such a way, that when
the MOSI pin is low while the OC2B pin is high, the three color signals will
be pulled to a high voltage, corresponding to white. This is used to generate
high resolution scroll text: The MOSI pin is connected to a shift register
internally in the AVR (it is typically used for serial data transmission), and this
shift register can be programmed to emit a sequence of 8 bits with a single instruction, thus offloading
the CPU. Smooth scrolling is then implemented by inserting variable delays
before and after each display line, but that alone is not enough, because characters
would appear and disappear suddenly at the edges of the screen. So additionally, the
output comparator connected to timer 2 in the chip is set up to create a
visibility window using the OC2B pin.
Schematics
This is how it all fits together, hardware-wise. If you are interested in
the physical layout used on the breadboard, you can find it along with firmware
and source code near the top of the page.
The variable 1K resistor can be used to adjust the brightness of the scroll texts.
.---[ 1K ]-+------- E (PNP) C -------------------+---+---.
| /|\ | B _|_ _|_ _|_
| `----' | \ / \ / \ /
| | --- --- ---
| .---__---. | | | |
(to programmer) --- RESET | | PC5 ----[ 442 ]-----------+---+---|---|--- Red
| | | | .-[ 220 ]-' | |
(n.c.) PD0 | | PC4 ----[ 442 ]-+-[ 442 ]--- GND | |
| | | | | |
.----------+-[ 2K ]----- PD1 | | PC3 ----[ 442 ]-----------+-------+---|--- Green
| .-[ 1K ]-' | | | | .-[ 220 ]-' |
| `--+-------[ 2K ]----- PD2 | | PC2 ----[ 442 ]-+-[ 442 ]--- GND |
| `-[ 2K ]-- GND | | | | |
| `- OC2B | | PC1 ----[ 442 ]-----------+-----------+--- Blue
`---[ 1K ]-. | | | .-[ 220 ]-'
.--------+-[ 2K ]----- PD4 | | PC0 ----[ 442 ]-+-[ 442 ]--- GND
| | | |
| VCC | | GND `-[ 1K ]-.
| | | |
| GND | | AREF (n.c.) |
| 22pF | | |
| GND -||--+- XTAL1 | | AVCC (n.c.) |
| 20 MHz [ ] | | |
| GND -||--+- XTAL2 | | SCK -------------- (to programmer)
`-[ 1K ]-. 22pF | | |
.--------+-[ 2K ]----- PD5 | | MISO ------------- (to programmer)
`-[ 1K ]-. | | |
.--------+-[ 2K ]----- PD6 | | MOSI ---------+--- (to programmer)
+ `-[ 1K ]-. | |
----)|------------+-[ 2K ]----- PD7 | | OC1B ------------------------------------- HSync
Audio 10uF | |
--------- GND (n.c.) PB0 | | PB1 -------------------------------------- VSync
`--------'
If you want to learn more, I suggest you dive into the source code, starting
with boot.S, mainloop.S and asm.S. The most
interesting part is probably the cycle-accurate code in asm.S.