A retro emulation system on a <=2mm thick business card, using ideas borrowed from other projects and a sprinkling of insanity...

Public Chat
Similar projects worth following
This project aims to implement a complete retro emulation system featuring support for external gamepads, audio, and video via a HDMI connection, in a thin (sub-2mm) business card form factor without breaking the bank.

It will run a modified version of Retro-Go, supporting a handful of emulators (and DOOM) on an ESP32-S3 microcontroller, with support for DVI video via an RP2040 co-processor using the PicoDVI library.

Unorthodox connector solutions inspired by other projects are employed to provide the required connectivity in such a thin form factor, avoiding bulky off-the-shelf sockets, resulting in a device that is substantially thinner than the connectors that it plugs into.

This is an ESP32-S3 based business card running a modified version of retro-go to play emulators. An RP2040 outputs video to HDMI displays thanks to the PicoDVI library, while USB peripherals (so far only keyboards) can be used as controllers through the ESP32-S3s USB Host stack. The hardware design files for version 1 can be found here on GitHub.

All connectors are made using flat PCB structures, resulting in an overall thickness of a bit over 1.7mm (0.8mm PCB + 0.9mm QFN ICs) when nothing is plugged in. 

The RP2040 serving as a video adapter for the ESP32-S3 has no flash or crystal of its own, so is entirely dependent on the ESP32-S3 to provide a clock signal and upload firmware into its RAM on startup over a bit-banged SWD interface.

The original intent of the design was “wafer thin DOOM” - how thin can a fully featured console running DOOM be made? However, due to several issues encountered during development, the first iteration of RetroMedleyCard has had to be significantly cut back. Most prominently, the ESP32-S3 chip used only features 2MB of PSRAM, which is about enough to run Gameboy emulation, but anything requiring much more memory results in a system panic, which unfortunately means DOOM is out of the question for the time being.

Additionally, audio output is currently disabled, due to lack of memory to allocate audio sample buffers, and the display is limited to 52fps when drawing to the full 320x240 pixel display, since it has not been possible to get DMA based frame-buffer transfers working in time on the RP2040.

Future iterations will address this by using an ESP32-S3 chip with more PSRAM available, which should hopefully allow more emulators (and DOOM) to run while also making audio output possible.


Schematic exported to .PDF

Adobe Portable Document Format - 651.59 kB - 06/30/2024 at 22:21


  • 1 × ESP32-S3FH4R2 2x LX7 MCU @ 240MHZ, 4MB Flash, 2MB PSRAM, WiFi+Bluetooth
  • 1 × RP2040 2x Cortex M0+ MCU @133MHz(+overclock)
  • 2 × AP22653 Current-limited power switch, reverse current blocking/limiting
  • 1 × PAM8908 Single supply stereo headphone audio amplifier
  • 1 × TLV62585 Synchronous Buck Converter

  • The 2024 Business Card Contest is almost over - what’s next?

    Eontronics07/01/2024 at 19:19 0 comments

    With less than 24 hours until the contest closes (assuming I’m getting my timezones right), I’m still surprised that I’ve been able to go from a half-baked idea to a nearly functional device in the span of about two months. That said, there’s still plenty more work to be done to get RetroMedleyCard to the lofty heights of “wafer-thin DOOM”, which then raises the question - what happens next?

    Well first of all, I intend to take some time off to focus on getting some other (much simpler) projects across the finish line, and maybe even documented and shared if I’m happy with how they turn out. I’m also considering tidying up and releasing the simple_swd component I wrote for this project as a library, since it could be useful in other projects needing an easy way to access the SWD port of another MCU. Since the last two months have been especially stressful, getting RetroMedleyCard to where it is now, a change of pace and focus is in order…

    When I do return to this project, the first port of call would be to address the glaring issues identified in the current RetroMedleyCard iteration, namely a lack of available RAM on the ESP32-S3, fiddly and unreliable PCB connectors, and any silly errors in the PCB layout.

    Fortunately, the memory situation should be an easy fix, since Espressif offers the ESP32-S3-PICO-1-N8R8, with a whole 8MB of flash AND PSRAM. Since the current PCB doesn’t use the octal-SPI pins reserved for larger PSRAM devices, it should hopefully be a simple drop-in replacement for the current ESP32-S3FH4R2. I will need to read though the datasheet in detail, but it may be possible to reflow rework the existing PCBs for use as an initial test platform.

    Fixing the PCB layout and connectors will necessitate a new PCB iteration, though I will probably want to get the more capable ESP32 SoCs soldered by the fab house anyway, so updating the PCB at the same time shouldn’t be an issue, I could even add actual contact details to the silkscreen and QR code!

    The USB-C connectors will likely remain the same for iteration 2, as I still have a full batch worth of USB-C socket PCBs leftover. The 3.5mm TRRS audio socket should hopefully be relatively easy to fix, requiring a separate, dedicated PCB prong for the tip, due to its smaller diameter. The SD card socket can be improved by adding taller components as “pads” to contact the SD card, and relocating some of the pull-up resistors to act as physical barriers which prevent the SD card from being inserted too far. However, the current “pads” (0603 capacitors) are already theoretically the same thickness as the base PCB, so switching to taller components will increase the overall height of the card, which would be pushing the <=2.0mm target.

    With the extra PSRAM available, it should be possible to get a much more complete firmware working on the second iteration, using knowledge gained trying to bodge retro-go onto iteration 1. Firmware modifications should be much neater, better targeted to achieve the desired functionality, and with helpful comments explaining what the changes do, so that it can be released alongside the revised hardware design files. This would aim to include functionality which was omitted from the first iteration, such as gamepad support, proper audio output, and the ability to run a larger range of emulators (including DOOM, fingers crossed!).

    As for now, this concludes my work towards the 2024 Business Card Challenge, and I wish the best of luck to everyone participating!

  • It just about works, but can’t run DOOM…

    Eontronics06/30/2024 at 02:00 0 comments

    So the last few weeks of trying to patch together some working firmware before the competition ends have been… eventful.

    On the plus side, I did finally manage to get the card running an emulator, controlled over USB and displaying to a monitor via a HDMI port!

    Robert Doman’s Space Crawler demo for Gameboy running in an emulator on the business card
    (Messy) Test setup with PCB connected to USB-C power, a keyboard via a USB-C dongle, a HDMI cable for display output, and full size SD card

    However, there were a large number of difficulties along the way, and as a result I’ve had to make some pretty significant compromises (for this version of the board at least). As an overview of what works and what the limitations are (will be explained in detail later on):

    1. Display - the DVI output itself works great, the PCB edge connector seems reliable and my monitor recognises the signal flawlessly. However, the speed of the QPSI bus has been limited to 16MT/s, for 64Mbps throughput, or 52fps at 320x240 resolution in RGB565.
    2. USB - The card is controlled entirely via the USB Host interface of the ESP32-S3, supporting only HID keyboards at present. The RP2040’s USB interface is not configured, and the data wires are the wrong way around on the PCB anyway! Additionally the PCB USB edge connectors are quite temperamental and requires some fiddling to get a reliable data connection.
    3. Retro-Go launcher - about the only thing that works flawlessly is the launcher application built into Retro-Go - probably because I didn’t need to modify it!
    4. Emulators - currently I’ve only been able to get gameboy emulation working under Retro-Go (though there are many emulators I haven’t tested yet). Other emulators crash immediately on startup, which I suspect is due to a lack of memory on the ESP32-S3
    5. DOOM - crashes immediately on startup, which again I suspect is due to limited system memory
    6. Audio output - Retro-Go appears to use the audio stream to govern the emulator speed, relying on the rate the DMA transfers samples to the I2S peripheral. I haven’t been able to get this to run without crashing, and naive attempts to drive the sigma-delta peripheral in software resulted in inconsistent game speeds and horrific sounding audio. So, audio is disabled for the time being :(
    7. “Sockets” -  the audio and SD card “sockets” sort of work. Only certain SD cards actually make contact with the capacitor pads (presumably due to dimensional tolerances), and I misinterpreted a dimension drawing of the 3.5mm TRRS plug, so the tip fails to make contact in the “socket”. 

    So all-in-all, it mostly meets my requirements as a minimum viable demonstrator, but there is obviously a long way to go to reach what I originally envisaged when starting the project, and getting to this point at all required overcoming a bunch of hurdles in the development process, which at times felt like complete show-stoppers.

    Getting a working display output

    Going chronologically, the first major challenge was getting the RP2040 up and running as a video coprocessor, using the ESP32-S3 to program it on-the-fly.

    I chose to keep the RP2040 firmware within the flash on the ESP32-S3, rather than on the SD card, as otherwise there would be no-way of seeing errors if the SD card wasn’t connected. UF2 format was used for this as it seemed to give the smallest firmware file (compared to the .bin and .elf files) while also being easy to read data from. 

    Difficulties started when trying to connect to the RP2040 over SWD. As mentioned in a previous log, the RP2040 uses a multi-drop SWD interface, which many examples of the SWD interface do not implement. I had been using ataradov’s embedded-swd library, with some modifications to try and generate the initialisation sequence needed for the RP2040’s debug interface. Unfortunately I never had any luck getting a response from the RP2040, and didn’t understand the code well enough...

    Read more »

  • Hardware is here!

    Eontronics06/12/2024 at 01:51 0 comments

    First set of boards are finally here, so soon I should be able to start testing software!

    Assembled board front view

    Assembled board rear view

    The boards were ordered with PCBA for most of the surface mount components, largely due to the use of DFN/QFN packages which would be difficult to solder without reflow. The flexible connector “prongs” had to be separated from the edge of the PCB (shown below) and soldered onto the front of the card, forming the contacts for the SD card and 3.5mm Audio Jack. Additionally, a handful of passive components forming the crystal oscillator and RF filter still needed to be assembled, as the specific component values required additional fees for SMT assembly. (Shoutout to my dad for helping assemble these while I’ve been trying to write firmware!)

    Board as shipped. Note the prong structures attached to the bottom of the board which are removed and soldered to the front of the PCB to act as flexible contacts.

    The unusual connector designs actually appear to work better than I expected, though I’m not entirely convinced the SD card and 3.5mm jack are making good contact. Nevertheless, It looks good for a first version and should be bodge-able if they prove problematic. Due to the small profile, I chose to omit the cutouts in the sides of the USB-C plate, which would normally provide a latching action, so that they would be easier to mill. Fortunately there still seems to be enough friction to provide a decent retaining force, and the (H)DMI connector also stays seated without too much fuss.

    Assembled board demonstrating the use of the many silly connectors it incorporates. Much to my surprise, the PCB prongs seem to hold up quite well to being flexed when inserting/removing the SD card and Audio plug.

    In the meantime, I’ve been focusing on trying to get an initial firmware to a state where it can be uploaded to test that the board is actually functional. In particular I’ve been trying to understand how the Serial Wire Debug (SWD) interface of the RP2040 works such that I can upload a program into RAM from the ESP32. 

    As it turns out, the SWD interface is actually quite simple, while the documentation (in my opinion) makes trying to understand it seem like a chore. Eventually, I stumbled across this application note by Silabs, which gives a fairly concise explanation. To keep things brief, each transaction essentially consists of an 8-bit request followed by an acknowledgment and 32-bits of data read/write. The request can read or write to one of four registers on the debug port to control it, such as to select an access port to the system’s resources. The access port is then controlled using the same request format to manipulate registers to access system memory, etc. 

    Aside from a few nuances (inserting an extra clock cycle to change data direction, clocking an extra 8 bits after the last transaction  to ensure it is fully cooked through the debug port) this forms 99% of transactions over SWD. Initialisation of the debug port seems to be an exception, which requires specific sequences of bytes to be transferred to reset and enable the interface.

    The RP2040 specifically implements a multi-drop bus, allowing multiple targets to be connected, This seems to be a feature of “SWDv2”, which also implements some additional registers that were reserved in v1. This also requires a different initialisation sequence compared to v1, so documentation that does not refer specifically to multi-drop/SWDv2 is likely for the older v1 interface, and probably won’t work the the RP2040! 

    What would be nice now would be an easy-to-use, high level library to bit-bang either version of the SWD protocol, to make using the RP2040 as a flash-less coprocessor easier, for applications acting as an IO expander, to provide additional interfaces, or even to allow other architectures to use the RP2040 PIOs? This could also support more...

    Read more »

  • Software scope

    Eontronics05/30/2024 at 20:41 0 comments

    With the board out for manufacture, I now have some time to start thinking about how I'm going to get code written for it. Given the range of potential features available on the board (WiFi, Bluetooth, 2x Usb Hosts, DVI video, "analogue" audio), and the short time span of the competition, I don't want to be stuck-in over my head rushing to get the code working in time. Instead, I would like to create a minimum viable demonstrator for the competition, illustrating the core functionality of the project, then fleshing out all the extra features at a later date.

    Features that i consider to be part of the "core" functionality, against nice-to-haves are tabulated below:

    Required featuresNice-to-have features
    Support for a single external gamepadSupport for multiple external game pads over a range of interfaces
    Unbuffered video output through DVI in RGB565Fully buffered or syncronised video output to prevent tearing with up to 24-bit colours
    Analogue audio output over 3.5mm JackAudio output over a range of interfaces
    Playable emulatorRange of playable emulators with launcher(s)

    The core functionality revolves around the minimum requirements to reach the point where *an* emulator is playable on the card, while nice-to-have features expand on capabilities to support emulation of multiple devices, using a range of input devices and flexible audio output selection depending on user preference.

    These nice-to-have features result in a more complete device, but adds multiple cases will need to be handled by the software and be debugged, which could considerably increase development time.

    As previously mentioned, I would like to port Retro-Go to this card which should handle launching and running various emulators, so I would otherwise mainly need to focus on adding support for the various interfaces: a gamepad driver using Bluetooth OR USB host on the ESP32, DVI video through the RP2040 coprocessor,  and audio output using the ESP32's sigma-delta modulator.

    Once these features are working well, I can evaluate whether to throw in some of the nice-to-haves, or move straight onto documentation and tidying things up, depending on how much time remains in the competition (if any!)

  • Retroactive log 3: Hardware design and features

    Eontronics05/30/2024 at 20:07 0 comments

    With an overarching plan established to set the direction of the design, it's time to actually produce a PCB layout and determine all the little ancillary components to support the main processors. 

    So, following a hectic bank holiday weekend stuck in front of KiCAD and countless datasheets, I eventually managed to cram everything onto this board:

    To give a quick overview of the specs:

    • ESP32-S3 application processor with 4 and 2 MB of on-package flash and PSRAM, respectively
    • RP2040 video adapter, connected to the ESP32 via QSPI at up to 320Mb/s, and a second full duplex SPI side-channel at up 80Mb/s (in theory)
    • PAM8908 stereo headphone amplifier, chosen for being able to operate on a single supply rail without needing a bulky output capacitor
    • Dual USB 2.0 hosts over USB-C (connected to the ESP32 and RP2040, respectively), using AP22653's as power switches with ~750mA current limit
    • Full size SD card slot over 1-bit SDMMC interface on ESP32
    • TLV62585 synchronous buck converter to power it all.

    The board itself has a number of "interesting" design choices baked in to keep profile and cost to a minimum:

    • Card edge connector on top-left adapted from peterburk's picoDVIEdge should fit into a HDMI connector without using a chunky socket
    • Direct soldered 0.6mm thick USB-C 2.0 socket boards using 8-pin, 2.0mm pitch through hole interfaces
    • "Novel" SD card and 3.5mm sockets using flexible PCB prongs (seen at the bottom of the board) which will be sawn off and soldered directly to matching headers on the card.
      • For the 3.5mm socket, a cutout in the board slightly smaller than the 3.5mm jack is used to keep it in place. The prongs are laid perpendicular to the jack, and press down on it to make direct contact with the rings while providing some retaining force
      • The SD card prongs are aligned with the contacts on the card, and each uses 0.8mm tall capacitors as pads to (hopefully) interface with the recessed contacts of the SD card. Cutouts for the capacitors allow the prongs to remain flat on the board when no card is inserted.
    • 2-layer PCB coil for the buck converter - adds no thickness to the design, is free, and looks cool! (Though an SMD chip inductor would probably be far more practical...)
    • Entire board uses only 2-copper layers, to take advantage of discount pricing offered by several PCB fabricators
      • Where traces have needed to be routed through the ground layer, I've tried to avoid routing underneath high speed traces (particularly the 40MHz QSPI and 80MHz SPI interconnects). These are then fenced with vias to a top layer ground pour, to try and bridge the ground plane over them. Hopefully this will ensure ground return paths are fairly uninterrupted.
    • "Analogue" audio produced by the ESP32's sigma-delta modulator, passed through a first order RC low pass filter. This will probably sound "not great", but with only 2 passive components per channel it's also very cheap and compact.
    • CC detection and power control on USB-C downstream facing ports to be handled in software on the RP2040. This allows common power switch ICs to be used, which were cheaper than any USB-C DFP controllers I could find. A mosfet on each CC line protects the RP2040 GPIOs from current injection when unpowered and another host is connected, or if connected to a host that pulls the CC line to +5V.

    Putting all this together results in a board which should have no components taller than the 0.9mm-ish tall QFN packages, resulting in a total thickness of only 1.7mm!

    With all the questionable features implemented, it's just a case of sprucing up the silkscreen and sending it off to be manufactured (no points for guessing where though!)

    As it turns out, PCB art is hard, and not yet in my acquired skill set, so I instead resorted to using this cool font "AmazDooM" uploaded by Amazingmax. Thanks!

  • Retroactive log 2: Inspiration and The Plan(tm)

    Eontronics05/30/2024 at 00:33 0 comments

    This project wouldn't be a medley if it didn't draw inspiration from a number of other projects to solve niche problems raised only due to self-imposed restrictions, so here I "briefly" present a plan which forms the backbone of the design, and try to credit those sources of inspiration that make this project possible/plausible(?).

    As mentioned previously, I would like to be able to run a number of emulators with support for external gamepads on a host microcontroller. I have chosen to use the ESP32-S3FH4R2, as it provides common connectivity options for gamepads (USB host, bluetooth), comes with flash and PSRAM on package, saving the difficulty of trying to fit these on a small PCB, and is proven to have sufficient performance to run several emulators such as via Retro-Go,  which I would like to port onto this board to save the effort of writing firmware from scratch. To keep the form-factor as thin as possible, system-on-modules such as the ESP32-S3-WROOM are out of the question, so I will have to figure out how to integrate the WiFi antenna directly onto the board.

    The RP2040 video adaptor will work using the PicoDVI library to bit-bang a DVI interface, which many projects and products have demonstrated before. The specific application of the RP2040 as a video adaptor for a host processor can be seen in Pimoroni's PicoVision development board (referring to the humble RP2040 as the 'GPU', heh), which appears to program the 'GPU' from a host Pi Pico using 2 GPIOs to emulate an SWD interface. I intend for my ESP32 host to do much the same, so seeing how the PicoVision firmware handles this should make things much easier.

    While the PicoVision switches between two external banks of PSRAM as framebuffers, this sounds pricey and requires extra board space. Instead I aim to use the ESP32-S3's QSPI interface to shuffle data to the RP2040 as quickly as possible. Using a 4-bit bus in double data rate mode @40MHz gives a throughput of 320Mb/s, which should be more than enough to transfer a 320x240 framebuffer @60Hz (assuming the PIO on the RP2040 can handle it)?

    To keep the form factor thin, I sought out some 'alternative' connector solutions that other have tried, and the findings are fairly hopeful!

    USB-C 'ports' have been implemented a few times as PCB edge connectors, seen in Chris' CRAPi2040 (0.6mm thick PCB) and Dmitry Grinberg's Linux Business Card (0.8mm thick PCB), while picoDVIEdge by peterburk (0.8mm thick PCB) does the same to a 'DMI (the H is silent)' socket

    While the 'DMI' connector appears to work well on a 0.8mm board, comments online seem to suggest 0.6mm would be more suitable for USB-C, so I plan to use a 0.8mm thick PCB as the 'base' of the card (as the 0.8mm option is cheaper), with small 0.6mm thick USB-C adapter boards soldered on.

    A final big source of inspiration came from Dennis Kaandorp's PCB business card, which uses flexible prongs in a 0.8mm thick PCB to create a 2032 coin cell holder. With some creativity, I think this could be adapted create sockets for a 3.5mm TRRS connector and some form of external memory card (SD card or MMC)

    Since the ESP32-S3 is quite power hungry and the RP2040 will need to be overclocked, a 5V-3.3V buck converter seems more appropriate than a linear regulator, especially in low profile packages which tend to have poorer thermal conductivity. This does mean finding a sufficiently low-profile inductor (e.g. chip inductors), or I could try designing the inductor coil directly in the PCB traces... for fun of course :) .

    So summing this all up, the plan boils down to:

    • use an ESP32-S3 chip (not a complete module!) as the application processor
    • connect to the RP2040 video adapter through the QSPI bus, program from ESP32 via bit-banged SWD
    • use a 0.8mm base PCB as it is economical and appears to fit into a HDMI connector
    • use smaller, directly soldered 0.6mm PCBs to create 'sockets' for USB-C connections
    • figure out ways that flexible PCB prongs...
    Read more »

  • Retroactive log 1: Ideas and kickoff

    Eontronics05/29/2024 at 23:12 0 comments

    With the 2024 business card contest kicking off, I've finally found an excuse to try a silly project idea I came up with a while ago - making a big-screen compatible retro games emulator by using an RP2040 as a low-cost display adaptor through the PicoDVI library by Wren6991, coupled with a host micro-controller to actually run some emulators, using firmware such as ducalex's Retro-Go.

    To keep costs, part-count and board space down, the RP2040 would have the bare minimum of components required to operate - no external flash/RAM, and clocked directly from the host processor. As the RP2040 lacks on-chip flash to store user programs, the host processor will need to upload firmware directly to the RP2040's RAM on startup.

    Since this is expected to be plugged into a monitor, having the controller built-in to the PCB wouldn't be particularly practical, so external gamepad support is a must, and we'd need audio too, of course.

    To meet the competition requirements, this will need to fit on a small business-card sized PCB, and with a bonus category to make the product as thin and business-card like as possible, I get to try out some unusual workarounds to avoid using bulky components like connectors.

    So in the two months the competition runs for:

    - The PCB will need to be designed, manufactured and assembled

    - Software will need to be written/adapted and *debugged* for both the host MCU and the RP2040

    - Everything needs to be written up in a somewhat-orderly fashion

    ...which sounds an awful lot for such a short timescale...

View all 7 project logs

Enjoy this project?



The-Devil-Itself wrote 06/04/2024 at 15:06 point

plus point for the doom font

  Are you sure? yes | no

Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates