Sir Box-a-Lot is a handheld, hackable 8-bit Sokoban clone implemented from scratch for the retro-modern AVR Dx series microcontroller. The hardware costs around $50 to assemble. The implementation features:
A selection of 300 levels with progressively increasing difficulty, suitable for novices and experienced players alike,
A polished, portable form factor when assembled on an inexpensive mail-order PCB,
Smooth animations, retro sounds, and full-color graphics rendered on a modern OLED screen,
Multi-user support with a range of per-level achievements,
Generous undo and other convenience features for streamlined, frustration-free gameplay,
Relatively low power consumption for at least 40 hours of gameplay on a single set of batteries.
The assembled circuit looks like this:
Note that you don't have to use a custom PCB; plans are provided for assembly on a generic perfboard (image). You also don't need to stick to Sokoban: you can use the circuit to develop any other game that's playable with a joystick and two auxiliary buttons.
Click on the button below to download an offline archive containing detailed schematics, source code, parts list, assembly instructions, and Gerber files for PCB manufacturing. If you're on Windows, you will need a tool like 7-Zip to extract the contents.
The archive contains the following files:
000-README.txt: parts list, assembly instructions, troubleshooting tips,
sir-box-a-lot2.c: richly-commented program source code,
levels-inline.h: Sokoban community levels (by Laura Wheeler, David W. Skinner, and Aymeric du Peloux),
font-inline.h: author's custom 6x6 font for OLED displays,
sprites-inline.h: original game sprites,
gerber-files.zip: PCB files needed to order a PCB from a fabricator,
schematics.jpg: circuit schematics for perfboard assembly or troubleshooting,
binaries/*.elf: precompiled AVR firmware binaries for convenience,
avr128db28/*: an alternative build for the AVR128DB28 or AVR128DA28 MCU.
The most expedient approach is to build the circuit by hand on a 7x8 cm perfboard based on the supplied schematics:
For a more professional look, you can send gerber-files.zip (see above) to a PCB vendor such as JLCPCB, OSH Park, or Digi-Key Red. The result should look something like this:
In the latter case, expect to pay $20-$40 for the boards and to wait 1-2 weeks for the order to arrive. Since there's usually a 3-5 board minimum and given that shipping costs are essentially fixed, it's best to split the order with some friends.
If taking the custom PCB route, default manufacturing settings are fine. You can choose a different board solder mask color or thickness. I recommend paying for lead-free HASL or ENIG finish, as the board will be handled extensively.
In addition to a standard soldering workshop, the following parts and supplies are necessary to assemble the circuit:
OLED display: Newhaven Display NHD-1.69-160128UGC3
Microcontroller: Microchip AVR128DB48 or AVR128DA48 in TQFP-48 (AVR128DB28 or AVR128DA28 can also be used; see below)
EEPROM: STMicroelectronics M95256-RMN6TP, M95256-DFMN6TP, M95320-RMN6TP, or M95320-DFMN6TP in SOIC-8 (see below)
Speaker: CUI CMS-151135-078L100 or similar (15x11 mm, wire leads)
Undo switch: E-Switch 320E11YEL, 320E11RED, 320E11WHT, or 320E11GRN (12.5x12.5 mm, see below)
Menu switch: NKK JB15HFP, JB15FP, or other 10x10 mm through-hole tactile button
Power switch: NKK GW12LCP or similar (around 7x3 mm, see below)
Capacitor #1: Kemet A759KS337M1CAAE015 or other through-hole capacitor rated for ~330 uF, at least 10 V, 8 mm in diameter
Capacitor #2: Kemet A750BK107M1AAAE024 or other through-hole capacitor rated for ~100 uF, at least 10 V, 5 mm in diameter
Capacitor #3: TDK FG18X5R1H105KRT06 or other through-hole MLCC rated for ~1 uF and at least 16 V
UPDI plug (optional): Adam Tech SMC-1-03-1-GT0, Preci-Dip 310-87-103-41-001101, or other generic female 3-pin header with 2.54 mm spacing
Battery clip: Keystone 2469, Hammond BH2AAAW, or any other regular 2xAAA holder with wire leads (25x53 mm)
Joystick: Adafruit 504 or a similar 6-pin through-hole navigation switch (10x10 mm)
Joystick cap: generic "Xbox One replacement thumbstick", pick your favorite color (example on Amazon)
Other stuff: 2x10 male PCB header for the OLED module; four short PCB standoffs with screws (M2x5 or M2x6); cyanoacrylate glue; hot melt glue / silicone caulk; optional conformal coating.
The UPDI connector is optional: for one-time programming, you can simply jam some breadboard jumper wires into the plated holes on the PCB.
If building on a perfboard, you will probably need a TQFP-48 / QFP-48 breakout board for the MCU (example); and a SOIC-8 one for EEPROM (example).
All electronic components should be nominally available from Mouser and Digi-Key; your total for the order should be around $50. That said, especially given the ongoing supply chain issues, here are some suggestions for substitutes:
Microcontroller: as of this writing (March 2023), the availability of AVR Dx MCUs is intermittent; Digi-Key had some AVR128DB48 chips last week, then AVR128DA48 earlier this week. Look around, place some backorders. Any of the following product codes should work: AVR128DA48-I/PT, AVR128DA48-E/PT, AVR128DB48-I/PT, AVR128DB48-E/PT, AVR128DA48T-I/PT, AVR128DA48T-E/PT, AVR128DB48T-I/PT, and AVR128DB48T-E/PT.
If you find a different product code, please double-check that the chip is in the TQFP-48 form factor, not VQFN-48. The pads on the PCB are too far apart for VQFN-48, and the package is more difficult to solder.
Note: the package now contains an alternative PCB design for the more readily available AVR128DB28 chip. These devices are currently in stock in a couple of places. The alternative circuit can be built on a perfboard using through-hole SPDIP ICs (I/SP or E/SP part suffixes); or on a mail-order PCB using SSOP-28 chips (part suffixes I/SS and E/SS).
EEPROM: although my original design calls for M95256-RMN6TP (256 kbit), you can save about $0.40 with M95320-RMN6TP (32 kbit). There are multiple other SPI EEPROMs on the market; as long as it can operate between 1.8 V and 3 V, has a maximum speed of at least 20 MHz, stores 32 kbits or more, and is pin-compatible with M95256, it should work. STM products aside, you should also be able to use Rohm BR25G320-3, Onsemi CAT25320VI, etc.
Tactile switches: any dimensionally-compatible switches should work on the PCB, but note that the "undo" switch (320E11YEL) has unusual pinout, so you are probably limited to other color variants of the same 320E11 series. The remaining switches are fairly standard.
Joystick: the joystick is currently on backorder at Mouser, but both Adafruit and Arrow have a good number in stock (link, link). For perfboard builds, you can also substitute the joystick for discrete direction switches.
Power switch: a small PCB slide switch, such as C&K JS202011CQN, is an acceptable substitute; you will need to clip one of the middle legs for it to fit. Other options similar to the original lever switch include Nidec CF-LD-1DC-AR2W and E-Switch 400UDP1L1BLKM2RE.
Power supply: the circuit works fine at supply voltages between 2.2 and 3.0 V. This is essentially the service range of alkaline and NiMH batteries, so I did not incorporate any regulation. If you wish to power the circuit from a different voltage - e.g., Li-poly or USB power - OLED supply must be limited to 3.3 V; the remaining stuff is OK to 5.5 V. A simple regulator - such as VXO7803-500 - should do the trick.
A "commercial" version of this circuit would probably feature a couple of changes. First, to reduce costs, the OLED module could be replaced with a $15 version without a bezel or a breakout board (link); in this case, an additional chip - maybe AP3032KTR - would be needed to generate 14 V for the LEDs. Another modification would be reverse polarity protection - perhaps an n-channel MOSFET such as DMG2302UK on the GND side.
Please be realistic about your soldering skills and seek help if needed. The project isn't particularly complex, but it requires soldering a single TQFP-48 chip with 0.5 mm lead spacing. If you have no experience with fine-pitch surface mount chips, you will mess up your first attempt:
With this disclaimer out of the way, here's the recommended sequence of assembly steps:
Solder both SMD chips, noting their orientation. The MCU has a recessed circle near pin 1. EEPROM has a chamfered long edge on the side with pin 1. Etched text on the package is not indicative of mounting direction.
Solder 2x10 pin header onto the back of the OLED module. Don't solder it to the main PCB yet, and don't remove the protective film until you're done with all the remaining assembly steps.
Trim, strip, and tin battery holder wires to allow attachment to nearby pads on the back of the PCB. You can allow some slack, just keep the wires short enough so that they don't snag.
Use hot melt glue or silicone caulk to attach battery holder to the rectangular region marked in the rear of the PCB. Allow glue to set.
Grab the speaker with tweezers, with the recessed side pointing up, then carefully apply cyanoacrylate ("instant") glue only to the bezel. Keep the glue off the membrane. Place the speaker in the marked position on the front of the PCB, membrane facing down and wires pointing toward the capacitors. Press gently and allow the glue to set.
Route speaker wires through nearby mechanical holes on the board, trim and strip the leads to allow attachment to pads on the back. Again, some slack is OK, just keep them short enough to avoid snags.
Neatly solder battery wires and speaker wires to pads.
Mount and solder switches, joystick, UPDI connector, and capacitors. Trim leads with flush cutters when done. Observe the polarity for large caps. Longer lead is positive; printed marking on top or on the side is on the negative side.
(If you want no pointy protrusions on the back of the PCB, the trick is to trim all leads flush with the board before soldering. With good soldering technique, this should leave the board silk smooth.)
Optionally clean up soldering flux residues with isopropyl alcohol and an unwanted toothbrush, then apply conformal coating to the exposed solder joints.
Install the OLED module using four short PCB standoffs. If you don't have any suitable spacers, you can use a gob of hot melt glue underneath for support. Either way, make sure that the header is sticking through.
Solder the OLED header to the board.
Fit the joystick cap. You will need to gently shave the sides of the joystick with a sharp knife or a small file. Press the cap into place; if it's not snug, apply a touch of cyanoacrylate glue, but make sure that the glue doesn't drip down the shaft. It's safer to hold the board upside down for this.
Here's a clip showing most of the assembly steps for the AVR128DB28 variant:
AVR toolchain is required to build the source code; this can be the Microchip Studio IDE on Windows, or avr-gcc on Linux or MacOS X.
If you're on Windows, download the latest Microchip Studio, then go to File > Open > Project / Solution and select sir-box-a-lot2.cproj from this package. Click on the Debug drop-down in the toolbar and select Release. If you're using the AVR128DB48 MCU, you can then hit F7 to compile. If you're using AVR128DA48, press Alt-F7, go to the Device tab, and click Change Device... first.
On Linux or MacOS X, please download the latest avr-gcc / gcc-avr and avr-libc packages for your system, as the chips are relatively new. The command to compile the source code is:
avr-gcc -O3 -mmcu=avr128db48 sir-box-a-lot2.c -o sir-box-a-lot2.elf
Substitute avr128db48 with avr128da48 if using the DA series chip.
If you get an error about a missing device-specs/specs-avr128db48 file, you can download and unzip this device pack from Microchip (despite the extension, it's just a regular zip file). After that, find the device-specs/ directory on your system (probably somewhere in /usr) and copy the following files from the archive you just downloaded:
./gcc/dev/avr128db48/device-specs/specs-avr128db64
./gcc/dev/avr128da48/device-specs/specs-avr128da64
Next, find a directory on your system containing libatxmega64d4.a (again, likely in /usr); and copy the following files from the DFP to that location:
./gcc/dev/avr128db48/avrxmega4/crtavr128db48.o
./gcc/dev/avr128da48/avrxmega4/crtavr128da48.o
./gcc/dev/avr128db48/avrxmega4/libavr128db48.a
./gcc/dev/avr128da48/avrxmega4/libavr128da48.a
Finally, find a directory on your system containing iox64d4.h (possible location as before); and copy the following files to there:
./include/avr/ioavr64db48.h
./include/avr/ioavr64da48.h
If you did this correctly, you should now be able to compile the source code.
If you have no experience or no luck with the AVR toolchain, you can also use prebuilt binaries included with this archive (binaries/*.elf) and skip directly to the programming step.
An UPDI-capable programmer is required to send code to the chip. The canonical option is ATMEL-ICE, but it is moderately pricey (~$150, link). Cheaper options include PICkit 4 or MPLAB SNAP (see below); as well as cheap third-party clones such as this.
The programmer can be operated via Microchip Studio on Windows, or via tools such as avrdude or pymcuprog on Linux and MacOS X. If you have Microchip Studio installed and if you're using ATMEL-ICE, you can just open cmd.exe, go to the directory containing sir-box-a-lot2.elf, and paste this command:
"C:\Program Files (x86)\Atmel\studio\7.0\atbackend\atprogram.exe" -t atmelice -i updi -d avr128db48 program -f sir-box-a-lot2.elf
Again, substitute avr128db48 for avr128da48 if using the DA series chip.
Alternatively, you can access the programming UI from Microchip Studio via Ctrl+Shift+P, select AVR128DB48 or AVR128DA48 as the MCU, and go to the Memories tab to select an ELF binary.
If using avrdude on Linux, the usual command line for ATMEL-ICE is:
avrdude -p avr128db48 -c atmelice_updi -U flash:w:sir-box-a-lot2.elf
If you get an error along the lines of "avrdude was compiled without USB or HIDAPI support", you should get angry at the maintainers of your Linux distro, uninstall the package, and build the tool by hand.
In regard to PICkit and SNAP programmers, I have no first-hand experience, but Rafael Martins notes:
"You can use a PicKit4 or SNAP AVR mode to send code to AVRs these days. They are cheaper than ATMEL-ICE [...] To enable AVR mode: plug the device, open MPLab IPE / IDE / Microchip Studio and try to run any operation in an AVR device (something like reading signature is enough). just doing that will change the tool to AVR mode, and now [...] either avrdude or pymcuprog will work just fine."
During programming, you might want to optionally configure the brown-out detector (BOD) fuse on the MCU. BOD can be set to 1.9V. Without BOD turned on, the display may appear glitchy when the battery is dead. BOD makes shutdown more graceful.
Here's a quick checklist for common circuit issues:
Device completely dead, can't program:
Make sure the circuit is powered and switched on.
Check battery polarity and condition.
Check UPDI connector polarity (GND should be toward the MCU).
Make sure you're using UPDI programming mode - not SPI, SWD, or JTAG,
Confirm device selection in the toolchain (AVR128DB64 or AVR128DA64, depending on the chip used),
Look for bridges or bad soldering across all EEPROM and MCU pins.
Inspect solder joints across 330 uF and 1 uF capacitors.
Inspect solder joints on both sides of the OLED header.
Inspect solder joints on the UPDI connector.
Double-check chip orientation for EEPROM and MCU.
Programming successful but circuit doesn't do anything:
Confirm device selection in the toolchain,
Upgrade to the latest version of the toolchain,
If open-source options fail, try Microchip Studio on Windows.
Sound but no display:
Check for soldering issues on MCU pins in the bottom left quadrant.
Check for bridges and bad joints on both sides of the OLED header.
Perfboard only: check the order of all OLED wires.
Display but no sound:
Check for soldering issues on MCU pins in the upper right quadrant.
Check soldering on the 100 uF cap and speaker pads.
Some buttons or joystick directions not working as expected:
Check for soldering issues on MCU pins in the bottom right quadrant.
Check button solder joints.
Perfboard only: check the order of switch wires.
High scores or player names not saving or not loading properly:
Check for soldering issues on MCU pins in the upper right quadrant.
Inspect all EEPROM pins.
Check EEPROM chip orientation.
Perfboard only: check the order of EEPROM data wires.
Here's some useful advice for players:
Push boxes to win.
To personalize player names, select name and then hold the "undo" button for about one second.
Hold buttons / joystick for rapid menu scrolling or map travel.
On the level selection screen, hold the joystick sideways to move in the increments of 10.
If you want to skip the boot animation, hold the joystick tilted left while flipping the power switch.
If you mess up, press the yellow button. There are 200 undo steps available and no penalty for using this function.
The blue button exits the game and allows you to choose another level. Press it twice to switch players.
When you switch players, level selection starts with the first level this player hasn't solved yet - but it's possible to skip ahead.
Reprogramming doesn't delete achievements due to the use of an external EEPROM; if you want to reset scores, simultaneously hold "menu", "undo", and tilt joystick to the left while turning on the device. Hold the keys until you hear a confirmation beep.
This article discusses some of the software challenges involved in designing an earlier prototype of Sir Box-a-Lot.
If you'd like to learn more about the SPI EEPROM interface, it is very similar to the SRAM interface discussed in this introductory article.
For more information about the OLED interface and the custom font used by Sir Box-a-Lot, follow this link.
If you're interested in an introduction to custom PCB design, click here.
Finally, some of my earlier 8-bit games can be found here. You might also want to check out my later project, Bob the Cat.
If you have any questions, suggestions, or feedback, contact me at lcamtuf@coredump.cx. For other projects, you can also follow me on Mastodon or Twitter, or subscribe on Substack. And if you end up building the circuit, please send me a photo!
Your lucky number is: 24215484