A Christmas Ornament That Runs Doom

A detailed build log of a miniature IBM PC-shaped Christmas ornament powered by an ESP32-C3 microcontroller that plays Doom with sound and wireless BLE controller support.

Doom Christmas ornament

New Year and Christmas are approaching, which means trees and everything that goes with them: garlands, decorations, and of course, ornaments. The holiday is too cheerful, and I decided it needed a gloomy game.

I built a small Christmas tree ornament modeled after an IBM PC, containing a TFT display, processor, and battery. The device shows a Doom demo mode with audio and music. Users can connect BLE keyboards or joysticks to play interactively.

Hardware

Main Components

The project uses an ESP32-C3 microcontroller:

  • RISC-V based processor at 160 MHz
  • 400 KB SRAM
  • Support for 8 MiB flash memory mapping
  • WiFi and BLE capabilities

Previous Doom Ports

Before diving into the build, it's worth mentioning prior work porting Doom to ESP32 using external PSRAM. A GitHub user named "doomhack" created a full Doom port for Game Boy Advance based on PrBoom, optimizing resource usage by pre-processing WAD files to reduce RAM requirements from typical specifications to approximately 300 KB. This great work served as the foundation for my project.

Circuit Design

Circuit schematic

The schematic includes:

  • Display: 0.96-inch TFT color LCD screen
  • Audio: Tiny speaker connected directly to GPIO pins
  • Power: Lithium-ion cell with charging logic
  • Voltage regulation: HT7833 LDO regulator providing 3.3V
  • Protection: Diode/FET circuit preventing simultaneous charging and discharging
Power management circuit

Flash Memory Upgrade

A distinctive feature of the ESP32-C3-Wrover-02 modules is that they only have 4 MiB of flash memory. This wasn't enough for the Doom WAD files, so I desoldered the metal cap and replaced the flash chip with an 8 MiB component to accommodate Doom's WAD files.

PCB photograph

Software

Doom Engine Implementation

The foundation uses doomhack's GBADoom port. Modifications included removing GBA-specific display and input bindings, implementing custom display drivers for the TFT screen, and creating a new input handling system.

Audio System

The original GBA version used tracker-based chiptune compositions. I converted the system to OPL (AdLib/Sound Blaster) emulation. The conversion process involved:

  1. Extracting MUS files and soundfont data from WAD using wadext
  2. Converting to IMF format using imf-creator
  3. Using the DOSBox OPL emulator for playback
  4. Configuring the I2S peripheral in PDM mode for direct speaker connection

To increase the amplitude, I configured one GPIO to output the PDM signal, and the second one to output its inverse, so that the speaker could be connected directly between them for double the volume.

Wireless Input System

The project implements BLE HID (Human Interface Device) support using the NimBLE stack. I wanted to use the lightweight Bluetooth LE stack called NimBLE because the alternatives would take up too much memory.

Key features:

  • Pairing mode allows automatic connection to BLE keyboards, mice, or joysticks
  • Custom HID implementation borrowed from FreeBSD's libusbhid
  • Supports any BLE device with HID capabilities

Case Design

3D Model Selection

The ornament's body mimics an IBM XT computer form factor. I sourced an existing model from Thingiverse designed for multi-color FDM printing.

3D model overview

Model Modifications

Using OpenSCAD, I:

  • Merged case and monitor components
  • Carved interior cavities for electronics
  • Optimized screen placement
3D model cross-section

Compartment Layout

The internal structure includes:

  • Main section: Electronics and battery (largest compartment)
  • Display section: 0.96-inch TFT screen
  • Output: Only the upper portion of the display is visible through the monitor window

Through the monitor window, only the upper part of the display is visible, so a rotated and downscaled Doom framebuffer of 80x60 pixels is drawn into it.

Manufacturing

I initially planned to use an FDM printer, but that machine failed. The files were sent to JLC for SLA (resin) printing. Since resin printing cannot produce multiple colors:

  • White base resin was used for primary surfaces
  • Spray paint was applied for gray and black accents
  • The power button and USB connector were fitted into dedicated slots
  • The bottom cover was glued for additional structural support
Painted ornament case

Assembly and Integration

Component Installation

Soldered to the PCB:

  • Tiny speaker (attached to speaker grille)
  • Power button
  • Micro-USB connector (charging and programming)
  • TFT display

As mentioned above, the screen is much larger than the plastic model and occupies almost the entire height of the case.

Internal component assembly

Power Management

The battery and PCB are arranged in a sandwich configuration in the main cavity. The display is positioned in the upper cavity. The speaker is glued to the speaker grille opening.

The thin bottom cover proved too flexible, requiring adhesive rather than snap-fit closure.

Assembled ornament interior

Final Result

Finished ornament on tree

The project successfully combines:

  • Miniaturized computing hardware (ESP32-C3)
  • Classic game software (Doom via GBADoom port)
  • Novel input methods (BLE wireless control)
  • Decorative enclosure (IBM XT-inspired 3D print)

As usual, the entire project — schematics, PCB design, case design, and firmware — has been published as open source on GitHub at: https://github.com/Spritetm/esp32c3-doom-bauble

Happy New Year and Merry Christmas!