I remember a time when we used to make things. Duvac in Pasadena used to carry wire wrap supplies and integrated circuits. Fry’s used to have a wide selection of products for making circuits that weren’t contained in packaging that yellowed with age. You could buy Nixie displays from Radio Shack.
Perhaps it was a matter of economics: if you wanted a home computer on the cheap you needed to make it yourself. Perhaps it was a matter of tinkering: back then, you had to build your own stuff, while today “tinkering” involves playing with PHP and building your own web site. Or perhaps it’s simply just a matter of a culture which wants things faster, better, cheaper–and when you can buy a really cool computer or GPS gizmo with full color display for under a couple of hundred bucks, who wants to spend a thousand to get a small box with a handful of LEDs that flash?
But no-one seems to make things anymore. Which is a shame.
So in my spare time I decided to build a Simon-like game clone–because I can.
Here’s the circuit diagram: game circuit diagram, and here’s the source kit for SDCC for the software for the game: game source kit. The final ROM size is 1193 bytes, well under the 4K limit for the HC08QY4. (With some work it probably could be made to fit in less than 1K, suitable for the HC08QY1, which in quantity is around $1/unit.)
Update: There is a typo in the diagram. The CPU used is the MC68HC908QY4, not the QT4. The QY4 is the 16-pin version, and what is shown is the 16-pin DIP version of the circuit. The QT4 is the 8-pin version of the same processor.
Here are some pictures, including the box I made to hold the game:
And here’s a video of the game in action.
The source files uses SDCC for compiling the source kit from C to assembly language. There were a few gotchas that occurred while making the game:
(1) While the SDCC documentation says if you use the __interrupt(N) keyword an appropriate interrupt entry will be entered into the interrupt table of the HC08 processor, I found that for some reason the entry wasn’t added after all. Thus, the interrupts.s file actually provides the correct entries into the interrupt table. If you add a new interrupt, you should then update the interrupts.s file to reflect the new interrupt.
(2) I use stack variables rather than globals; this is because the underlying architecture is interrupt driven. In events.c I use the timer interrupt (configured to interrupt every 1/100th of a second) to poll the keyboard and generate key up/key down events, as well as fire off an event. This architecture is perhaps a little overkill, but it does allow me to respond to very complex logic without worrying if the logic fits in a 1/100th of a second window. Further, this has the advantage that in my GetNextEvent() routine, if there are no events taking place, I can place the processor into a low-power WAIT state, which reduces considerably the amount of power drawn by the device.
The overall advantage of this is that the game runs just fine on a couple of AA batteries. And I expect that, during game play when no lights are turned on, the total draw of the circuit should be on the order of 1.1mA. By contrast, the biggest draw are the LEDs.
I love the interrupt-driven architecture, by the way: if the same architecture were to wait for key strokes using the keyboard interrupt architecture–for example, we were using this chip for a keypad for a combination lock–we could put the processor into STOP mode. Without any external circuits being powered, in STOP mode the QT4 draws 0.36µA of power–meaning it could run in this standby mode on a couple of AAs for nearly 22 months.
The stack-based variables, however, is so I can keep everything straight, since in theory any routine could be re-entrant.
But this means that many of the built-in run-time libraries for the HC08 on SDCC don’t seem to work right. My random number generator deals with the reality that in-line long integer multiply drops to a library call–so it doesn’t work right at all. However, a long-integer shift does work correctly, so I implement the GNU random() number generator algorithm using shifts and adds in C, which then generates the right (non-library calling) routine.
(3) There is no sound. That’s because I didn’t have access to a small speaker. I intend to fix this with a future version when I have some time. When I do this, I’ll probably use the same interrupt loop (slightly tweaked) to drive the speaker to seven different sounds: one for each position, and an “you fail” sound. (One possibility would be to tweak the interrupt timer duration and adjust all the timing of the rest of the game to match. Another would be to up the interrupt timer frequency, and maintain two additional counts: one which indicates if I pull up or down the speaker line, and another which indicates if I should drop into my old 100Hz interrupt routine.)
(4) The animations are perhaps a little over the top. With sound I probably could simplify the startup sequence. I also wonder if I shouldn’t add a seventh ‘start’ button to start the game instead of using the “hit any button to start” method I’m using now.
(5) Why are the lights so strange, with D1 being the lower right LED? Because I got disoriented when I was hooking up the LEDs: my intention was to make D1 the top light, with other lights working clockwise around. Instead, I wired up LED 6 as the lower light, with the other lights working counter-clockwise–meh. It was easier to rework the software than re-glue the lights. I worked the switches in the same order deliberately so I didn’t get confused.
Sure, it’s a silly little gizmo with a handful of lights. But I had fun!