← Selected workP42024–25

Dual-Microcontroller DOOM Game Engine 

An embedded game engine split across two processors, with custom inter-processor communication that cut rendering latency by 60 % against a single-processor implementation.

Organisation
University of Leeds · ELEC 2645 Embedded Systems Project
Period
December 2024 – June 2025

Evidence

  • −60 %Render latencyvs single-processor
  • 97/100Project mark
  • 240 MHzESP32-S3
  • 40 MHzFramebuffer linkSPI
  • 921,600Sync linkbaud, UART
  • 240 × 320DisplayILI9341, 2.8 in

Case study

01

The problem

  • A raycaster on one microcontroller has to finish tracing the frame before it can start pushing pixels, and pushing pixels is slow.
  • The obvious fix — a faster part — was not available inside the module budget.
02

The design

  • Split the engine across two processors: an ESP32-S3 at 240 MHz alongside an STM32L476RG.
  • Two links rather than one bus. Framebuffers move over SPI at 40 MHz; the pair stays in step over UART at 921,600 baud.
  • Separating bulk from urgent traffic means a frame transfer never sits in front of a synchronisation message.
03

What I did

  • Wrote the engine and the inter-processor protocol.
  • Chose the link rates and the split, and defended both in the report.
  • Built and debugged the hardware, including the 2.8-inch ILI9341 interface.
04

How it was tested

  • Measured render latency against a single-processor implementation of the same engine on the same display.
  • Verified sync-link error budget across the temperature range without an external crystal at both ends.
05

Result

  • 60 % lower rendering latency than the single-processor build.
  • 97/100 on the project. Module overall 87.
The hardwarePhotographs and footage — Arnav’s own

The hardware

  • A 2.4-inch colour TFT panel on a breadboard displaying the DOOM title screen, wired to a microcontroller with jumper leads.Title screen
    The title screen on the panel it was written for — 240 × 320, driven over the framebuffer link.
  • AudioLevel theme
    The level theme, rebuilt from square waves and played back through the rig’s own speaker. There is no sample in the firmware — the tune is synthesised from the noise the hardware can already make.
  • On hardware
    The engine running on the board, frame timer along the top edge. The demo further up this page is a reimplementation of this renderer in the browser; this is the hardware it was written on.

    A clip of the DOOM engine running on the small TFT panel: a textured corridor, a sprite enemy, and a status bar showing health and ammunition, with a frame-rate counter along the top edge.

Two processors, one engine: an ESP32-S3 at 240 MHz alongside an STM32L476RG. Framebuffers move over SPI at 40 MHz and the pair stays in step over UART at 921,600 baud, on a 2.8-inch ILI9341 at its native 240 × 320.

Two links rather than one was the decision that took the most arguing. A single bus carries both bulk pixel data and time-critical synchronisation, and the frame transfer then sits in front of every sync message. Separating them means the wide, slow-to-drain path never blocks the narrow, urgent one.

Decisions

  1. 01

    Why two links instead of one bus?

    Bulk and urgent traffic have opposite requirements. A framebuffer wants width and does not care about latency; a sync message wants latency and is a few bytes wide. Sharing a bus means every sync waits behind a frame.

  2. 02

    Why 921,600 baud on the sync link?

    It is the highest standard rate both parts clock cleanly without a custom divisor, which keeps the error budget inside spec across the temperature range without an external crystal on both ends.

Block diagram: an STM32L476RG and an ESP32-S3 running at 240 megahertz, joined by a 40 megahertz SPI framebuffer link and a 921,600 baud UART synchronisation link. The pair renders 60 per cent faster than the single-processor implementation.STM32L476RG32-BIT MCUESP32-S3240 MHzSPI · 40 MHzUART · 921,600 BAUD−60% RENDER LATENCY vs SINGLE-PROCESSOR
Fig. P4 — Inter-processor architecture. Link rates as specified.