DeMon — Debug + Monitor

AntOS host, system supervisor, hardware glue, and boot-UI display engine — pronounced "Demon".

DeMon is built around the ESP32-P4 (paired with an ESP32-C5 for wireless) and sits at the centre of everything: it boots the system, programs the FPGA, runs AntOS, watches over every other chip, drives the system display via its MIPI engine, and provides hardware debugging across the entire Ant64.

The choice to host AntOS on DeMon — rather than on the FireStorm Execution Engine inside the FPGA — has one important consequence: AntOS keeps running while the FPGA is being reconfigured. Loading a personality cartridge, flashing a development bitstream, or recovering from a fault all happen without disturbing the OS. The main display blanks only for as long as the FPGA takes to reconfigure — a fraction of a second for the native chipset on a normal boot, somewhat longer for a personality load — and AntOS keeps running on DeMon throughout.


Overview

Feature Detail
Main chip ESP32-P4 — single 400 MHz HP RISC-V core + 40 MHz LP RISC-V core
AI / DSP PIE extensions (Performance Instruction Extensions — RISC-V SIMD-like for AI and DSP)
PSRAM 32MB (embedded with the ESP32-P4)
Wireless chip ESP32-C5 (Wi-Fi 6, Bluetooth 5.3, Thread, Zigbee)
Flash 16MB
RTC Microchip MCP79410
RTC battery CR2450 — up to 20 years life
Storage Internal HS USB hub — DBFS master (D:), DBFS shadow (D!:), internal general drive (E:), external memory-stick port (B:) · external SD card slot (A:) — see Storage below and Filesystem & Drive Letters for the full scheme
USB (HID / debug) FS USB hub — internal keyboard · mouse · USB-Serial-JTAG of Pulse + ESP32-C5
OS AntOS runs here, on the 400 MHz HP core
Display feed 2-lane MIPI DSI TX → FireStorm FPGA — composes UI + sprite and tilemap layer descriptions; FireStorm renders them at scanout
Audio Triple SID engine (L/C/R) — 9 SID voices, PIE-accelerated · SAM speech synthesizer — formant TTS, PIE-accelerated · both streamed to FireStorm via MIPI

Why ESP32-P4?

The ESP32-P4 is Espressif's high-performance RISC-V SoC: a single 400 MHz HP RISC-V core for application code, a separate 40 MHz LP RISC-V core for low-power background tasks, integrated MIPI display TX, USB OTG, and 32MB embedded PSRAM. It also has PIE (Performance Instruction Extensions) — Espressif's RISC-V SIMD-like instructions for fast AI inference and DSP. See https://developer.espressif.com/blog/2024/12/pie-introduction/ for an overview of PIE.

PIE on DeMon's HP core gives AntOS access to small ML inference and DSP acceleration: speech recognition, ambient music analysis, font rendering acceleration, image scaling, etc. — all without a separate AI chip.

The integrated MIPI engine is the critical feature for DeMon's display role — it lets AntOS render its UI on the HP core and feed it into the FireStorm FPGA as one of two MIPI display sources. Once the FPGA bitstream is loaded, DeMon's MIPI feed becomes the AntOS UI layer in the chipset's display compositor.

The ESP32-C5 provides wireless connectivity (Wi-Fi 6 dual-band, Bluetooth 5.3, Thread, Zigbee, ESP-NOW) and frees the ESP32-P4 from RF responsibilities. They communicate over an internal SPI / UART link.

Pulse uses the same ESP32-P4 SoC, in a parallel but not symmetric role. DeMon hosts AntOS and feeds the system UI to FireStorm's MIPI RX #0; it carries the general-purpose load — the OS, Luau scripting, networking, storage, user-driven work — so its FireStorm feed is one duty among many. Pulse hosts the music sequencer and feeds its UI to MIPI RX #1; it runs a real-time RTOS with a fixed set of dedicated tasks and no user scripting, so it can act as a higher-throughput, lower-jitter data pump to FireStorm — its real-time RTOS and absence of OS scheduling, not a wider bus, are what free it for that role (both supervisors use a QSPI register window). They share the same SoC, toolchain, and recovery model, but differ in role, software model, peripheral wiring, PSRAM use, and delivery profile.

Real-Time Clock — MCP79410

  • 64 bytes battery-backed SRAM (a candidate store for the NFC DBFS-switch target — survives power-off on the coin cell)
  • 128 bytes EEPROM + 8 bytes protected EEPROM
  • Supports years 2001–2399
  • Costs less than £1

A standard MCP79410 — the machine ID no longer lives here (it moved to the ESP32-P4 eFuse, below), so the blank-EUI variant is not needed.


Machine ID — ESP32-P4 eFuse

The Ant64 machine ID (aid) lives in the ESP32-P4's on-chip eFuse: a 4096-bit one-time-programmable store (up to 1792 bits reserved for custom use) with configurable per-block write and read protection. This is genuine silicon OTP — once a bit is burned 0→1 it can never return to 0 — which is exactly the permanence the re-writable RTC protected EEPROM could not give. aid is the identifier used in NFC card registration / licensing.

Stored as a 64-bit aid64 — the 48-bit structured ID plus a 16-bit CRC:

aid64: 64 bits in ESP32-P4 eFuse (custom-use block)
  [63..16]  aid   48 bits   structured machine ID (timestamp ‖ batch ‖ serial)
  [15..0]   crc   16 bits   CRC-16/CCITT-FALSE over the 48-bit aid

aid (the 48-bit value — logical machine ID only, NOT a network MAC):
  [47..28]  timestamp  20 bits   hours since 2026-01-01 00:00 UTC (≈119 yrs), hour of first test
  [27..16]  batch      12 bits   0–4095
  [15..0]   serial     16 bits   per-batch monotonic, 0–65535
  • Uniqueness key = (batch, serial) — a manufacturing-process guarantee (the jig must never reissue a serial within a batch; monotonic counter, resets only on a deliberate new batch). The timestamp is provenance, not part of the key. Decodes to first-test hour + batch + unit-of-batch for support / warranty / recall scoping.
  • CRC-16 is a local integrity wrapper (and rounds the burned value to 64 bits). Recompute it over the 48-bit aid at end of first-test — to catch a bad burn before the unit ships — and at boot. Because eFuse is 0→1-only, the one available corruption / tamper mode is setting extra bits, and any such change breaks the CRC, so DeMon refuses a corrupted aid rather than licensing against a garbage ID. Detection, not correction (the eFuse's own hardware encoding schemes are the correction layer). Variant pinned: CRC-16/CCITT-FALSE — poly 0x1021, init 0xFFFF, no reflection, no final XOR — stated explicitly so the jig and firmware always agree. The CRC is part of the stored/burned value only; the URI parameter and licensing key on the 48-bit aid, never the 64-bit aid64.
  • Write-protected at first-test → hard primitive. After burning aid64, burn the block's write-protect bit (WR_DIS) so no further writes (even 0→1) are possible — confirmed available on the P4. That turns OTP into fully immutable: aid becomes a hard identity primitive, not the soft re-writable value the RTC EEPROM would have been. aid is write-protected, not read-protected — it must stay readable, because it is appended to URIs and hashed for transmission. See the burn plan below for the (irreversible!) ordering and granularity cautions.
  • Identity-grade, not a secret. Readable on-chip; if sent to a server, transmit a per-server salted hash (or the HMAC attestation below), never the raw value — don't broadcast the production calendar or allow cross-service correlation. Keep the raw structured value for local / support decode only.

Hardware attestation — read-protected secret + HMAC (design option)

For genuine machine-side anti-clone — the equivalent of the card's NTAG-424-DNA path — burn a separate secret key into a read-protected eFuse block: one DeMon's crypto hardware can use internally but can never read back out. Attestation is then a hardware-keyed HMAC — the server sends a nonce, DeMon returns HMAC(secret, nonce ‖ aid), and only a board holding that exact un-extractable key can produce it. Unlike a salted hash of aid (which only proves "someone who once saw this aid"), this cannot be cloned even with full bus access, because the key is unreadable by construction — the same mechanism ESP32 secure-boot / flash-encryption keys use. Not yet committed; documented as the path to a hard machine-side identity if commercial licensing needs it.

eFuse burn plan — handle with care (eFuse is irreversible)

Write-protection is confirmed available on the ESP32-P4 (the WR_DIS register — burning the relevant bit permanently disables further programming of its field). But every eFuse burn is one-way and unrecoverable — a wrong value, or a wrong order, means a permanently mis-IDed unit (scrap, not re-flash). Unlike the re-writable RTC EEPROM, there is no second chance. Three rules for the first-test jig:

  1. Granularity check (before burning anything). WR_DIS is not per-bit — one write-disable bit can govern a whole field or group. Confirm exactly which WR_DIS bit covers the custom block holding aid64, and that burning it does not collaterally write-protect anything we may need to write later. Pick a block whose write-protect bit is ours alone.

  2. Burn order: protection LAST, verify before the point of no return. Stage → burn aid64read back and re-check the CRC-16only then burn the WR_DIS bit. Never write-protect before the read-back verify (after WR_DIS, even a 0→1 fix is impossible). This mirrors IDF's own discipline — its tooling burns WR_DIS bits separately, after all other data, precisely so the burn's retry mechanism can recover from coding errors first.

  3. Plan the WHOLE eFuse layout up front. aid64, the optional HMAC secret (with its RD_DIS read-protection), and any future Secure Boot v2 / Flash Encryption keys all share the same WR_DIS/RD_DIS machinery — and protection bits have ordering conflicts (e.g. write-protecting RD_DIS for Secure Boot can foreclose read-protecting a Flash-Encryption key later). Decide the complete allocation and burn sequence for the unit's lifetime before burning the first one, because an ordering mistake is as unrecoverable as a wrong value.


Responsibilities

DeMon (ESP32-P4 — 400 MHz HP core + 40 MHz LP core)
 |
 ├── Runs AntOS on the HP core (persists across FPGA reload)
 ├── Programs FireStorm FPGA at boot via JTAG — also acts as a full-time JTAG
 │      host for FPGA reflash, fabric debug, and SPI flash updates (see JTAG Host below)
 ├── UPDI orchestrator for Sticky and Crank — DeMon supplies parsed firmware
 │      images and fuse settings; Pulse does the actual bit-bang (see UPDI Orchestration)
 ├── Drives AntOS UI as MIPI display layer → FireStorm MIPI RX #0
 ├── Composes sprite + tilemap layer descriptions (display list + tile-index map) — FireStorm renders them at scanout (see Composer)
 ├── Triple SID audio engine (L/C/R) — driven by AntOS, FireStorm, and Pulse
 ├── SAM speech synthesizer — text-to-speech for voice prompts / accessibility / dialogue
 ├── QSPI ↔ FireStorm — register window + FPGA→DeMon return data (data-ready IRQ on GPIO36)
 ├── Bidirectional SPI ↔ Pulse — peer command/data link (master + slave channels)
 ├── 5 Mbit/s asynchronous, GDMA-driven UART ↔ Pulse — additional peer link, complements the SPI channels
 ├── UPDI → Clicky (AVR128DB64) keyboard controller — program (io45)
 ├── HS USB host → hub → D: (DBFS), D!: (DBFS shadow), E: (general), B: (external stick)
 ├── PIE-accelerated AI/DSP for AntOS services + SID engine + layer composition
 ├── Streams debug output from each component (including FireStorm internal hard RISC-V coprocessor)
 ├── Remote reset of any component
 ├── FS USB host → hub → keyboard, mouse, ESP32-C5 JTAG, Pulse JTAG — see Storage
 ├── External SD card slot (general removable storage)
 ├── 32MB PSRAM available for AntOS, application data, OTA staging,
 │    layer descriptions / sprite display lists, SID engine audio buffers
 └── LP core (40 MHz) — RTC monitoring, low-power housekeeping, wake handling

DeMon (ESP32-C5)
 |
 ├── Wi-Fi 6 (2.4 + 5 GHz)
 ├── Bluetooth 5.3 LE + Mesh
 ├── Thread 1.3 mesh
 ├── Zigbee 3.0
 ├── ESP-NOW (no router needed)
 └── Optional LoRa via external SX1262

MIPI Display Feed to FireStorm

The ESP32-P4's integrated MIPI DSI transmitter is wired to MIPI RX #0 on the FireStorm FPGA (one of two 2-lane + clock D-PHY receivers — the other, MIPI RX #1, is fed by Pulse).

Specifications:

  • 2 data lanes + differential clock (D-PHY)
  • Up to 1.5 Gbps per lane = 3 Gbps total (~375 MB/s peak)
  • Enough bandwidth for 1280×720 at 60 Hz RGB UI overlay plus headroom for bulk data

FireStorm uses DeMon's MIPI feed as the AntOS UI display layer — the chipset composites it alongside whatever application is running on the FireStorm EE. Recovery menus, file browsers, system status, network state, and the AntOS shell all live here. The text and videotext content within this layer is composed by DeMon's text subsystem as a cell-grid description — grid, font selection, VT100/ANSI parsing, style attributes — and FireStorm renders the glyphs from its own font ROM at scanout; DeMon never produces finished text pixels in the production path. See AntOS Text Architecture for the subsystem's design and Composer for the compositing model.

The display description uses only a fraction of the link, so the spare bandwidth carries lower-priority traffic into FireStorm's DDR3 — network and storage data for the running application (packets, file/DBFS reads), asset uploads, OTA payloads, debug captures. The frame description always takes priority against the vblank deadline; this bulk fills the gaps beneath it and never delays a frame.

Return Path — FireStorm → DeMon

The reverse direction is QSPI, reusing DeMon's existing QSPI register window into the chipset (SPI2, CS FireStorm) rather than any MIPI or USB path. FireStorm raises a data-ready interrupt on DeMon's GPIO36; DeMon then clocks the payload out over QSPI as master — interrupt-driven and on-demand, separate from DeMon's outbound MIPI feed above. It carries chipset telemetry, audio buffers from the Tempest mixer (e.g. for OTA stream encoding via the ESP32-C5), compressed / reduced-resolution video readback (capture / streaming / recording), and bulk transfers from FireStorm DDR3 into AntOS memory. Throughput is QSPI-clock-bound (order of tens of MB/s), so raw full-resolution frame readback still compresses or downscales to fit. Routing the return over QSPI leaves DeMon's HS USB OTG free for the internal storage hub (see Storage). Pulse's return path differs — Pulse keeps a USB-HS device link to FireStorm (its HS USB isn't needed for storage); see Pulse and Memory.

MIPI is Dormant During FPGA Reconfig

DeMon's MIPI TX port has one destination — FireStorm (the return path above is a separate QSPI link). While the FPGA is being reprogrammed (personality cartridge load, bitstream update, recovery), FireStorm's MIPI RX isn't running, so DeMon's MIPI link is dormant for the duration; there is no system vsync either. During that window AntOS UI moves to the SPI-driven vertical touchscreen (see Keyboard Touchscreen), which is on its own bus and unaffected by FPGA state. Pulse's circular TFT (also SPI) does the same job on the music side. When the FPGA comes back, MIPI resumes and the next vsync triggers normal frame-locked operation.

Frame-Sync Cadence

DeMon's MIPI traffic is frame-locked, not continuous. FireStorm's system vsync output is wired to a DeMon GPIO, and DeMon waits for that pulse before pushing each frame. On vsync, DeMon bursts the next frame's layer descriptions (text cell grid, tile-index map, sprite display list) plus that frame's SID / SAM audio chunk over MIPI; the link is idle between pulses. The descriptions are tiny — a full 64×30 cell grid is ~7.5 KB, dirty-cell streaming a few hundred bytes most frames — a small fraction of the per-frame MIPI budget. FireStorm renders and scales the layers to the active output resolution at scanout via per-layer pixel replication, so DeMon never produces finished pixels and doesn't have to render at 4K or 1080p (see Composer).

Sprite and Tilemap Layer Capability

DeMon composes display layers as descriptions, not pixels: a text cell grid, a tilemap tile-index map, and a sprite display list, each streamed over MIPI to FireStorm, which renders and composites them at scanout. The P4's job is to maintain layer state — what sprite, where, which tile, which glyph — and FireStorm turns state into pixels. This is the production model and it deletes the per-frame palette-expand that used to dominate the bring-up path; see Composer for the full architecture and the benchmark that drove it. (The ESP32-P4's 2D Pixel Processing Accelerator is still on the die, but the supervisor display feed no longer goes through a P4-side pixel blit.)

Content kinds DeMon composes:

  • AntOS sprites — system icons, file-browser thumbnails, notification badges, animated cursors, status indicators (id + position + scale/flip/rotation + palette bank, emitted into the display list)
  • Sprite-based overlays for applications — AntOS-side widgets composited over the running game/demo without involving the FireStorm EE
  • Effects layer — particle bursts, screen transitions, accessibility overlays
  • Recovery / boot sprites — animated splash, progress indicators before the user-facing application even starts
  • AntOS tile-grid backgrounds — file-browser grids, icon-grid views, settings panels and themed surfaces, composed as a tile-index map over a tileset
  • Recovery / boot grids — a status grid populating tile-by-tile as services come up

These supervisor-composed layers are rendered by the same FireStorm tile and sprite hardware as its native layers (tilemap, sprites) — the only difference is the authoring path: DeMon streams a description, the running application writes chipset registers. The supervisor path is for UI-scale grids and overlays at modest update rates; full-screen game-style backgrounds at high update rates stay on FireStorm's native engines, driven by the application.

Pulse composes its own description streams the same way (MIPI RX #1). Between them the two supervisors deliver two independent description feeds into FireStorm — for example, AntOS overlay sprites and a file-browser tile grid on RX #0; music-performance sprites and a step-sequencer tile matrix on RX #1.

Display Behaviour: Native Boot vs Personality Load

On a normal power-on or reset, the FPGA auto-loads its native Ant64 chipset from its own attached flash chip. This takes only a fraction of a second — well under what the user perceives as a wait. Once loaded:

  • The native chipset is up
  • MIPI RX #0 (from DeMon) and MIPI RX #1 (from Pulse) start accepting feeds
  • The AntOS UI from DeMon and the sequencer UI from Pulse appear on the main display almost immediately
  • Resetting the system always returns the FPGA to this native state — the flash is the canonical source of truth

When the user (or AntOS) loads a personality cartridge — Amiga, Atari ST, C64, etc. — the FPGA temporarily takes on that personality's bitstream instead of the native chipset. This is a more substantial reconfiguration:

  • The personality bitstream is loaded into the FPGA's configuration logic (via JTAG from DeMon, or directly from the cartridge depending on the personality)
  • Main display is dark for the duration of this load — typically up to ~1 second
  • Once the personality is up, its own display pipeline drives the main display

A reset at any time returns the FPGA to its native chipset by re-reading the FPGA flash — discarding the temporary personality and bringing the AntOS UI back. The personality is, by design, an overlay onto the persistent state of the flash; it's never written to flash.

In all cases:

  • AntOS keeps running on DeMon, undisturbed
  • The keyboard touchscreen stays active, driven directly by DeMon, showing AntOS status, reload progress, recovery prompts, or any other useful information throughout the blackout
  • The circular display above the keyboard (driven by Pulse via SPI) also stays active independently
  • The blackout window is bounded by FPGA configuration time alone — fast for native, slightly longer for personality

This is intentionally different from the previous design where AntOS ran on the main processor: there's no OS to bring back up, no kernel re-init, no filesystem remount. And even within the blackout window the user has visible feedback via the touchscreen and the circular display.


Triple SID Audio Engine

DeMon runs a three-SID emulator in software on the ESP32-P4 — three instances of the MOS Technology 6581/8580 SID chip, panned Left / Centre / Right for a wide stereo image. Audio rendered by the SID engine is streamed to FireStorm over the MIPI bulk-data path (sharing the link with the AntOS UI feed) and joins the Tempest mixer as another voice source alongside Tempest, Pulse AMY, and FireStorm EE application audio.

The SID engine is a shared audio resource: although it lives in DeMon firmware, it can be driven by any of the three CPUs in the system — AntOS on DeMon, FireStorm in the FPGA, and Pulse over its direct SPI link to DeMon (see below). It's an audio engine that happens to be hosted on DeMon, not a private DeMon facility.

What It's For

  1. System sounds — alerts, notifications, navigation feedback, error tones, low-battery warnings, the kind of UI audio that should be available the moment AntOS is up, before the user has loaded an application or fired up the sequencer
  2. Sound effects for AntOS-side applications — file-browser audio cues, network event sounds, debug audio output, accessibility tones
  3. Game and demo sound effects — applications running on FireStorm can trigger SID voices for retro-flavoured sound effects (explosions, alerts, jumps, lasers) without burning Tempest voice slots; particularly useful when those voices are committed to music or sample playback
  4. Sequencer-driven SID voices — Pulse can route MIDI tracks to the SID engine for compositions that want authentic SID timbre in the mix
  5. SID file playback — the engine plays classic .sid files directly; AntOS doubles as a C64 music player out of the box
  6. AntOS Luau scripts — algorithmic / generative composition driving the SIDs as a programmable instrument

Why on DeMon?

DeMon is the right host for this because:

  • PIE-accelerated — the SID engine's filter math, oscillator mixing, and waveform generation benefit from the ESP32-P4's PIE SIMD extensions, fitting comfortably within available CPU budget
  • Independent of FPGA state — the SID engine keeps running even during FPGA reload; system audio is uninterrupted
  • MIPI bulk path is already there — no new bus is needed; the SID audio shares the MIPI link with the AntOS UI feed
  • Spare CPU on the supervisor — AntOS does not saturate the HP core; the SID engine fits in the headroom

How It's Triggered

The SID engine accepts events from three sources:

Trigger source Path Latency Use
AntOS on DeMon direct function call sub-µs OS sounds, scripts, SID file player, accessibility
Pulse SPI master → DeMon SPI slave (LPSPI) low µs Sequencer-driven SID voices, MIDI track routing
FireStorm EE chipset event mailbox + IRQ to DeMon low µs Game / demo / app sound effects

The FireStorm path uses a chipset register block as a mailbox: FireStorm writes SID note-on / note-off / parameter events into a small queue, then raises a dedicated IRQ to DeMon over a GPIO line. DeMon reads the queue via its QSPI window into the chipset and dispatches the events to the SID engine. This is the same general mechanism used elsewhere for FPGA-to-supervisor signalling — a few microseconds of latency, dominated by the IRQ-to-handler time on the ESP32-P4.

All three sources can drive the engine simultaneously; SID voices are dynamically allocated to whichever source is asking. Conflict policy (which source gets which SID chip when contended) is configurable in AntOS — typical defaults reserve one of the three SIDs for OS sounds and let games / sequencer share the other two.

Capability

  • 3× SID chips (MOS 6581 / 8580 selectable per instance — 6581 for the classic "muddy" sound, 8580 for the cleaner late-era variant)
  • 3 voices per SID — 9 total
  • Per-voice triangle / sawtooth / pulse / noise waveforms with ring modulation and oscillator sync
  • Per-SID multi-mode filter (low-pass, high-pass, band-pass, notch, with resonance)
  • L / C / R panning assigning each SID to a stereo position
  • CPU cost — roughly 5–10% of the HP core for all three SIDs at full polyphony, well within DeMon's available budget alongside AntOS itself
  • Compatibility — the engine can play SID files (the iconic .sid format), letting AntOS act as a C64 music player out of the box

Audio Path

AntOS scripts          Pulse (SPI master)         FireStorm EE
SID file player        sequencer events           game/demo FX
       │                       │                          │
       │              (SPI slave on DeMon)    (chipset mailbox + IRQ
       │                       │                read via QSPI)
       │                       │                          │
       └───────────────────────┴──────────────────────────┘
                               │
                               ▼
                  3× SID emulators (DeMon ESP32-P4, PIE-accelerated)
                               │
                               ▼
                  L / C / R mix to stereo buffer in PSRAM
                               │
                               ▼
                  stream over MIPI link → FireStorm
                               │
                               ▼
                  Tempest mixer (alongside Tempest voices, AMY, application audio)
                               │
                               ▼
                  WM8958 / WM8960 codec

Speech Synthesizer (SAM)

Alongside the Triple SID engine, DeMon runs a retro formant speech synthesizer in the tradition of S.A.M. (Software Automatic Mouth, 1982) — the iconic robotic voice of the Commodore 64, Atari 8-bit, and Apple II era. Like the SID engine it's hosted on DeMon but shared across all three CPUs, and like SID it streams its audio to FireStorm via the MIPI bulk-data path for mixing alongside everything else.

What It's For

  1. AntOS system voice prompts — boot messages, error alerts, low-battery warnings, network-event announcements; voice feedback that AntOS can produce the moment it's running, with no application involvement
  2. Accessibility — screen-reader mode for menu navigation, spoken descriptions of UI state, audio-first navigation when the main display is busy or unavailable
  3. System narration — patch names spoken aloud, file-browser audio cues, status-line readouts
  4. Musical use via Pulse — Pulse can send text or phoneme events to DeMon over the SPI link; the rendered speech enters the mixer as another voice source. SAM-style robotic vocals as a musical instrument — sequencer-driven phoneme streams, vocoder leads, "talking" basslines
  5. Game / demo dialogue from FireStorm — applications running on FireStorm can request SAM speech via the chipset mailbox; iconic robotic voice-acting at the cost of a few register writes
  6. AntOS Luau scripts — algorithmic narration, text-to-speech for arbitrary AntOS text

Why on DeMon?

  • AntOS owns voice prompts and accessibility — the OS is where text-to-speech requests originate; hosting the engine on the same chip makes the path direct
  • PIE-accelerated — formant synthesis (additive partials at three formants per phoneme) benefits from PIE SIMD
  • Available before applications — boot-time voice prompts work without any application running
  • Same dispatch model as SID — three trigger sources, MIPI audio out, mixer-side handling identical to SID

How It's Triggered

The same three-source pattern as the Triple SID engine:

Trigger source Path Latency Use
AntOS on DeMon direct function call sub-µs Voice prompts, accessibility, scripts
Pulse SPI master → DeMon SPI slave (LPSPI) low µs Musical use, vocoder leads, dialogue tracks
FireStorm EE chipset event mailbox + IRQ to DeMon low µs Game / demo dialogue, app speech

Pulse can send either complete text strings (DeMon's Reciter does the text-to-phoneme conversion) or pre-converted phoneme streams (for tighter musical timing).

How It Works

SAM converts text to speech in two stages:

Text input
    │
    ▼
Reciter (text-to-phoneme)
    Text → phoneme string using English pronunciation rules
    e.g. "HELLO" → /HH EH L OW/
    │
    ▼
Phoneme-to-speech (formant synthesis, PIE-accelerated)
    Each phoneme → three formant frequencies (F1, F2, F3)
                 → three formant amplitudes (A1, A2, A3)
                 → pitch contour
                 → voiced/unvoiced classification
    Combined via additive synthesis → audio samples
    │
    ▼
PCM audio buffer → streamed to FireStorm via MIPI link
                    → joins the Tempest mixer

The formant synthesis produces the characteristic 1980s robotic voice — not because the algorithm is simple, but because it deliberately computes speech with limited resolution (originally 8-bit samples, low sample rate). On the Ant64, running at full ESP32-P4 speed with the output going to the WM8958 codec via FireStorm's mixer, the algorithm is authentically SAM-like but with modern fidelity. The output sample rate is configurable; the engine can run at the original ~7 kHz for full retro flavour, or at 48 kHz for cleaner integration with the rest of the audio path.

Implementation

The open-source C port of SAM (s-macke/SAM, ~39 KB) runs as a bare-metal function on the ESP32-P4. No OS involvement is needed for the inner rendering loop — AntOS / Pulse / FireStorm submit requests, the SAM engine renders into a buffer in DeMon's PSRAM, and the buffer is streamed out over MIPI as part of DeMon's audio output to FireStorm.

Parameters (matching original SAM)

Parameter Range Effect
Speed 0–255 Talking rate (72 = normal SAM)
Pitch 0–255 Voice fundamental frequency (64 = normal)
Throat 0–255 Formant F1 shaping — voice quality (128 = normal)
Mouth 0–255 Formant F2 shaping — vowel colour (128 = normal)

Preset Voices (matching original SAM manual)

Voice Speed Pitch Throat Mouth
SAM (default) 72 64 128 128
Elf 72 64 110 160
Little Robot 92 60 190 190
Stuffy Guy 82 72 110 105
Little Old Lady 82 32 145 145
Extra-Terrestrial 100 64 150 200

Extensions Beyond SAM

The ESP32-P4 has far more processing power than the original 6502 host. The engine can be extended beyond the historical SAM algorithm:

  • Higher sample rate output (original SAM: ~7 kHz; DeMon can render at 48 kHz)
  • Smoother formant interpolation between phonemes
  • Additional phoneme sets (non-English languages)
  • Pitch envelope per phoneme (more natural intonation)
  • The Pi Zero 2W accelerator (when fitted) can assist with neural TTS for more natural speech, while DeMon retains the retro formant mode

Audio Path

AntOS scripts          Pulse (SPI master)         FireStorm EE
voice prompts          text / phoneme events      app dialogue events
accessibility          for musical use            via chipset mailbox + IRQ
       │                       │                          │
       └───────────────────────┴──────────────────────────┘
                               │
                               ▼
                  SAM Reciter (text → phonemes, when needed)
                               │
                               ▼
                  SAM formant synthesis (DeMon ESP32-P4, PIE-accelerated)
                               │
                               ▼
                  PCM buffer in DeMon PSRAM
                               │
                               ▼
                  stream over MIPI link → FireStorm
                               │
                               ▼
                  Tempest mixer (alongside SID, Tempest voices, AMY, application audio)
                               │
                               ▼
                  WM8958 / WM8960 codec

DeMon ↔ Pulse — Bidirectional SPI Link

DeMon and Pulse are connected by two SPI channels that form a full bidirectional command/data link between the two supervisors. Each chip has both a master and a slave SPI port wired to the other.

Direction DeMon side Pulse side Used for
DeMon → Pulse SPI master (SPI2) SPI slave (LPSPI) Boot config, firmware updates, supervisor commands, AntOS-side events to play through Pulse (UI sounds via AMY, sequencer transport control), file / sample / patch data
Pulse → DeMon SPI master (SPI2) SPI slave (LPSPI) MIDI events for AntOS to record or forward, SID and SAM trigger events, jog-dial state for AntOS UI, file-system / sample-library requests, status updates

This is not a hierarchical supervisor link any more — DeMon and Pulse are peers. Either side can initiate a transaction at any time; the slave side accepts whatever the master sends. AntOS arbitrates its end; Pulse firmware arbitrates the other. The same two ports also carry the firmware-update flow (for emergency recovery DeMon can reflash Pulse over its USB-Serial-JTAG via the FS HID hub, but day-to-day operation uses the SPI link).


JTAG Host — FireStorm Programming and Debug

DeMon is the system's JTAG host for the FireStorm FPGA. The JTAG link from DeMon to the GoWin GW5AST goes well beyond initial boot-time bitstream loading — it covers the full programming and debug lifecycle of the FPGA over the life of the machine.

What it does

  • Boot-time bitstream load — on power-on, DeMon programs the FPGA from the canonical bitstream in storage (native chipset by default, personality cartridge image when one is loaded)
  • FPGA reflash — bitstream updates pushed from AntOS, OTA payloads, or development workflows are written into the FPGA via JTAG with no separate programmer required
  • FPGA SPI flash programming — JTAG-to-SPI bridging through the FPGA lets DeMon write the on-board configuration flash that holds the native chipset bitstream. The flash is the canonical source on reset; updating it from DeMon updates the persistent state
  • Fabric debug — single-stepping, breakpointing, and register access for FireStorm soft cores (and the GW5AST-138's hard RISC-V core, which has its own debug path that JTAG can reach orthogonally)
  • Recovery and bring-up — when development bitstreams misbehave, DeMon's JTAG access is the recovery path that doesn't require a separate dongle

Toolchain compatibility

Two implementation routes are on the table, picking which is a roadmap decision:

  • Custom protocol over USB-Serial-JTAG / TCP. A small DeMon-side service, a small host-side tool. Minimum work, full control over performance and feature scope. Means new tooling rather than reusing the ecosystem.
  • openFPGALoader / urJTAG / OpenOCD compatibility via a well-known transport (FTDI FT2232 emulation, dirtyJtag, or XVC). Lets existing GoWin/RISC-V toolchains drive the FPGA without a separate adapter. More work upfront, big payoff in tooling reuse.

Either way, the JTAG signals themselves are bit-banged or driven via the ESP32-P4's GP-SPI peripheral configured as JTAG (TCK on SCLK, TDI on MOSI, TDO on MISO, TMS on a separate GPIO). The GP-SPI path gets useful clock rates for multi-megabyte bitstream loads; pure bit-bang would be painfully slow.


UPDI Orchestration — Sticky and Crank Firmware Updates

DeMon is the orchestrator for firmware updates to the two AVR128DB-family microcontrollers in the system — Sticky (joystick / paddle / 5V controller I/O) and Crank (jog dials). Neither AVR is directly wired to DeMon; both are reached through Pulse, which owns the physical UPDI lines and performs the bit-bang protocol on instruction from DeMon.

Split of responsibilities

Component Role
DeMon Holds the firmware images on storage, parses them (Intel HEX / ELF), extracts the program bytes and fuse settings, ships a clean payload over the bidirectional SPI link to Pulse, watches Pulse's progress / status reporting, surfaces results to AntOS
Pulse Receives the parsed payload, parks any active sequencer work, enters UPDI session mode against the requested target (Sticky or Crank), writes flash + fuses, reads back to verify, exits UPDI, reports pass/fail to DeMon

This split keeps the parser on the side that already has the firmware files and the toolchain to handle them, and keeps the timing-sensitive bit-bang on the side that is physically next to the target AVRs. Pulse doesn't need an Intel HEX implementation; DeMon doesn't need UPDI line drivers.

Scope

UPDI is used for firmware update and possible debug — not for runtime control. Both AVRs run autonomously between updates; routine joystick / jog-dial data flows over the SPI peer links from Sticky and Crank to Pulse and onward to AntOS. UPDI sessions are infrequent, explicitly invoked from AntOS (e.g. update sticky, update crank), and require the sequencer to be parked for the duration.

OCD-level debug (single-step, breakpoint, register inspection on the AVR cores via pyupdi-style tooling) is the natural extension if it's ever needed; the bit-bang transport supports it. Initial implementation is programming only.


Wireless — ESP32-C5 (Phreak)

The C5 is the core of Phreak, the Ant64's wireless subsystem — Wi-Fi/BLE here, plus the optional LoRa and GPS radios (see Communications).

Protocol Standard Notes
Wi-Fi 6 802.11 b/g/n/ax 2.4 GHz + 5 GHz
Thread 1.3 Mesh networking
Zigbee 3.0 IoT mesh
Bluetooth 5.3 LE + Mesh
ESP-NOW 2.4 GHz / 5 GHz No router needed — 1Mbps

The ESP32-P4 controls the C5 over the internal UART1 / SPI link (§ pinout). One option for that link is Espressif's ESP-AT firmware, which exposes Wi-Fi, TCP/IP, TLS, MQTT, HTTP, BLE, and BluFi as text AT commands — see the Phreak AT Command Reference for the full command set, transport, and flashing details.

Debug Connectivity

Channel Speed Notes
Wi-Fi Up to 54Mbps Router required
Bluetooth 2Mbps
ESP-NOW 1Mbps No router needed
SPI (to ESP32-P4) Up to 62.5Mbps Practical ~10Mbps

Optional: Waveshare Core1262 HF LoRa Module (SX1262) for LoRaWAN and/or Meshtastic use.

Anti-Brick

DeMon can be unbricked via an ICP cartridge even when the ESP32-P4's firmware is corrupted: its USB-Serial-JTAG D+/D- lines are brought out to the cartridge port, so a cartridge in the standard slot can reflash DeMon directly. The ESP32-C5 cannot unbrick DeMon — recovery goes through the cartridge port, not over the air.


Keyboard Touchscreen — Always-Available Display

In addition to the MIPI feed into the FPGA, DeMon owns a vertical touchscreen mounted next to the keyboard (a TFT panel with capacitive touch, SPI-connected). The screen is wired directly to the ESP32-P4 over its own SPI bus, independent of the MIPI link — it has its own controller, its own framebuffer in PSRAM, and its own touch input path. This independence is what makes it the fallback display whenever MIPI has no destination.

This matters because the touchscreen is visible at all times:

  • At power-on, the FPGA loads its native Ant64 chipset from its own flash in a fraction of a second — but during that brief moment, before MIPI RX is active, the touchscreen is already showing AntOS boot status, the current boot phase, or a splash logo. By the time the user is consciously waiting for the screen to come up, it is already up.
  • During FPGA reload (personality cartridge swap, bitstream update, recovery), the main display blanks while the FPGA reconfigures — typically up to ~1 second for a full personality bitstream, a fraction of a second for a native-chipset reset. The touchscreen continues to show AntOS status, progress, and any interactive prompts throughout.
  • During normal operation, the touchscreen is a secondary display surface — AntOS can render system status, the file browser, settings, debug info, soft keys, or jog-dial-style controls here.

Combined with Pulse's circular display above the keyboard (see Pulse), the Ant64 has two always-on auxiliary displays that survive any FPGA state — useful for diagnostics, recovery, and informational UI that needs to be visible even when the main display compositor isn't running.


Hidden Debug Display — SSD1363 OLED (optional)

DeMon optionally drives a small 256×128 16-greyscale OLED (SSD1363 controller, I2C at 0x3C) as a hidden diagnostic surface inside the case. The OLED is not fitted by default — it's a builder/developer option for units that need a permanently-on debug surface independent of the FPGA, MIPI, network, and keyboard touchscreen. Production Ant64s typically ship without it; debugging and development units, kits, and field-service builds may include it.

When fitted, the OLED is for the system to talk to itself — boot progress, subsystem state, scrolling event log, recovery information. It is read by whoever opens the case or knows where to look, not by users in normal operation. Unlike the keyboard touchscreen (which is user-facing and shows AntOS UI), the OLED is purely for introspection.

The OLED's value is its independence. It runs on plain I2C from DeMon and comes alive within milliseconds of power-on — before the FPGA loads, before MIPI is configured, before the network is up, before the user touchscreen has initialised. If any of those subsystems is itself the thing that's broken, the OLED still tells the story.

When not fitted, sys_oled detects no device on the bus and silently disables itself — all the diagnostic content that would have gone to the OLED still goes to the UART console and (once available) the network debug stream, so nothing is lost functionally. The OLED is purely additive.

Full layout, screen list, and refresh strategy are documented separately in Debug Display.


SPI1 — Device Select

DeMon's ESP32-P4 uses SPI1 with different CSn lines to control multiple devices:

Value Selected Device
0 Pulse Sequencer
1 ESP32-C5
2 Cartridge
3 Touch TFT

Smart Cart — Cartridge Port

A 30-pin edge connector connected to DeMon's ESP32-P4. The full pinout, the physical notes, and the catalogue of cartridge designs (ICP, chain cart, …) live in Cartridges.

  • If a cart is present at boot, it is used in preference to the SD card
  • Cart insertion/swap whilst powered on triggers an automatic reboot (can be disabled)
  • Cart can be safely removed whilst powered on — no reboot
  • Reinserting the same cart also does not reboot

Pins 13/M and 14/N lay the groundwork for a future redesign of the ICP cartridge: they expose DeMon's USB-Serial-JTAG — the same debug/programming interface that also reaches the USB-C port — so an ICP cartridge in the standard slot can debug and reflash DeMon directly, without needing a separate USB-C connection. The cartridge itself draws power from the cart 5V rail (pin 02/B); the board is powered from its main USB-C input and gated by the power button, so no dedicated board-power feed is needed on the cart port. (See Anti-Brick and What DeMon Can Reprogram.)

Built-In NFC Card Reader

The Ant64 has an on-board PN532 NFC reader — no cartridge required. Its antenna sits just behind the cartridge port, so a card placed at the cartridge slot is read directly: the same physical location accepts either a cartridge or a tapped NFC card.

The reader is on DeMon's I3C peripheral bus (I²C-legacy mode), with reset on io20 and IRQ on io21 (see the GPIO table below). The full card model — the "a card is a URL" scheme-dispatch mechanism, user/environment (DBFS) switching, and the game-manifest system — is documented in NFC — Cards, DBFS Switching & the Game Manifest System. A card carries only a short URI (a manifest URL or a dbfs:// target); game content is cached in the user's DBFS rather than on the card.


Neopixels — 8 Status LEDs

These eight WS2812 status LEDs are still controlled by DeMon, but physically driven by Clicky. DeMon sends a per-LED colour/state intent to Clicky over UART2 and Clicky drives the string; the buzzer works the same way — DeMon tells Clicky which tone to play and for how long, and Clicky handles the timing. DeMon never bit-bangs LED or buzzer timing itself.

No. Name Behaviour
0 Power Off → white (self test) → amber (booting) → green (ready)
1 External SD card Off / blue (detected) / green (R/W) / red (error)
2 Cartridge SD Off / blue (detected) / green (R/W) / red (error)
3 Main (fast) SD Off / blue (detected) / green (R/W) / red (error)
4 Network Off / blue (connected) / green (R/W) / red (error)
5 Wi-Fi Off / blue (connected) / green (R/W) / red (error)
6 Bluetooth Off / green (R/W) / red (error)
7 MIDI Off / green (R/W) / red (error)

During self-test all LEDs go white, then change individually: green = passed, red = failed. LED functions are documented and can be repurposed if needed.


Power and the power button

Power is supplied by USB-C. DeMon JTAG D+ and D- also go to the USB-C (and to the cart port, for ICP programming). DeMon will have power button feedback and control. Power in should be via a diode (1N5822 ?) so it's one way. The power button has an RGB LED driven via DeMon's MCP23017 I2C expander (PA2/PA3/PA4) — one digital line per channel, so it shows 8 fixed colours including off (no PWM dimming). The expander also carries the power-off output and the power-pushed input (PA0/PA1, with a pushed-input interrupt on PA INT), linked to a power controller. Pressing the button for approx 10 seconds will force a power down.

Pin USB-C Main board/DeMon connection
VOUT +V
OFF GPIO 23 OUT (needs pull up?)
PUSH GPIO 22 IN (needs pull up set)
BTN Physical button to GND
VIN +V
GND GND GND

Sparkfun open source soft power switch mk2


What DeMon Can Reprogram

  • FireStorm FPGA bitstream (via JTAG) — without interrupting AntOS
  • FireStorm FPGA flash (via JTAG chain)
  • Pulse (via USB-Serial-JTAG, through DeMon's FS hub)
  • Sticky (via UPDI through Pulse)
  • Crank (via UPDI through Pulse)
  • Clicky keyboard controller (via UPDI direct from DeMon — io45)
  • ESP32-C5 (via USB-Serial-JTAG, through DeMon's FS hub)

The ESP32-P4 itself can be reprogrammed over USB or via the cartridge ICP port. Because AntOS lives on DeMon, reprogramming DeMon is a deliberate, deeper-recovery operation — it reboots the OS. Recovery is layered: if DeMon is bricked, the ICP cart can reflash it; if everything is bricked, JTAG access from a PC can rebuild the system from scratch.

If anything goes wrong — Ant64 can heal itself.


Storage

The Ant64 has a layered storage topology, hosted off DeMon's USB controllers. Throughout this section, internal drives sit inside the case (not user-removable in normal use) and external ports are sockets mounted on the case, accessible from outside without opening the box.

Drive-letter assignment is port-based — each physical USB port maps to a fixed letter, independent of attach order or enumeration timing. The complete drive-letter scheme, DBFS shadowing rules, multi-user DBFS support, and boot/hot-plug behaviour are documented in Filesystem & Drive Letters.

USB topology — HS storage hub, FS HID hub

DeMon's two USB 2.0 OTG controllers are split by role:

  • HS USB OTG → storage hub. The High-Speed port drives a hub carrying up to four USB mass-storage devices, run at High-Speed for bulk throughput:
    • D: — DBFS master — primary storage for AntOS, applications, user data, the DBFS database
    • D!: — DBFS shadow — a continuous mirror of D: for redundancy; hidden from user-facing APIs; if the primary drive fails, no user data is lost — the shadow takes over
    • E: — Internal general drive — additional internal storage for things that don't belong in DBFS (large media libraries, downloaded asset caches, OTA staging)
    • B: — External memory-stick port — user-supplied USB memory stick for transient data, transfers, and backups
  • FS USB OTG → HID hub. A Full-Speed hub carries the human-interface and debug devices:
    • Keyboard and mouse
    • ESP32-C5 USB-Serial-JTAG — program / debug of the radio companion
    • Pulse USB-Serial-JTAG — so DeMon programs / debugs Pulse (Pulse's own OTG ports are committed: HS to FireStorm, FS to its MIDI port)

Drive-letter assignment is port-based on the storage hub (see Filesystem). The FPGA→DeMon return path is not USB — it's the QSPI link with a data-ready interrupt on GPIO36 (see Return Path) — which is exactly why both OTG controllers are free for storage and HID.

External SD card slot

An external SD card slot (mapped as A:) for user-supplied removable storage — used by the MOD player, sample import, Doom WAD libraries, save transfers, and as a generic file source for AntOS. It is not the primary system storage (DBFS holds that on D:); the slot is for removable media and bulk content.

Dual-host and single-speed hubs

Dual-host operation — hosting the HS storage hub and the FS HID hub at once — is enabled via peripheral_map = BIT0 | BIT1 in the USB host config and is tested working on the ESP32-P4. Keeping HS storage and FS HID/debug on separate hubs avoids the IDF host stack's TT-not-supported limitation — no mixed-speed traffic behind either hub.

Switched Hub Power — Software Power-Cycle

Each hub takes its +5 V supply through a software-controlled high-side switch, so AntOS can power-cycle a hub without anyone touching the hardware. The control lines exist on the MCP23017 expander: PB5 = HS storage-hub power and PB4 = FS HID-hub power. The drives are the recovery-critical case — the DBFS keepalive pulses PB5 to re-enumerate a wedged drive without disturbing HID on the other hub.

Why it's needed: ESP-IDF's external-hub driver can, on a bad hot-unplug, park a downstream port in a "device not working — wait for removal" state that a fresh insertion won't clear. The only reliable recovery is to remove the hub's VBUS and re-apply it, forcing a clean re-enumeration of the hub and everything behind it. With PB4/PB5 driving the hub power switches, AntOS does that itself — the DBFS keepalive detects the wedged drive and pulses PB5 (the storage hub), rather than asking the user to pull the hub's power lead.

High-side, not low-side. USB devices share their ground reference with the host (it's the return for D+/D−). Switch the +5 V rail and keep GND common; never switch the hub's ground, or the data lines lose their reference while the port is "off."

Why two transistors. A 3.3 V expander pin can't turn off a P-channel pass FET whose source sits at +5 V — it can't pull the gate all the way up to 5 V. So a small N-channel FET level-shifts: the expander pin drives the N-FET, and the N-FET pulls the P-FET gate down to pass +5 V through to the hub.

Recommended discrete switch (one per hub)

Ref Part Role
Q1 AO3401A — P-ch, −30 V, −4 A, ~50 mΩ, SOT-23 High-side pass FET: +5 V in → +5 V out to hub
Q2 2N7002 — N-ch, SOT-23 Gate driver / level shifter from the 3.3 V expander pin
R1 10 kΩ Q1 gate pull-up to +5 V — holds the hub off when Q2 is off
R2 1 kΩ Series gate resistor, expander pin → Q2 gate
R3 100 kΩ Q2 gate pull resistor — sets the boot default while the expander pin is high-Z. Tie to +3.3 V → default power-on (hub up before firmware runs, drives enumerate at boot); tie to GND → default power-off. The MCP23017 boots with all pins as high-Z inputs, so this one resistor decides the hub's state until AntOS drives the pin. +3.3 V is recommended for the storage hub.
C1 100 nF Q1 gate-to-source — soft-start; slows turn-on to tame inrush (recommended for the 4-port hub)
R4 1 kΩ In series Q2-drain → Q1-gate; sets the soft-start ramp with C1 (optional)
C2 10–47 µF ∥ 100 nF Bulk + decoupling on the switched +5 V at the hub

Wiring (HS hub on PB5 shown; the FS hub is identical on PB4):

   +5V ──┬───────────────[ R1 10k ]───────────┬── Q1.gate
         │                                     │
      Q1.source                           [ C1 100n ]      (soft-start to +5V)
         │
      Q1.drain ───────────────────────────────────► +5V to hub ──[ C2 10–47µF ∥ 100n ]── GND

   Q1.gate ──[ R4 1k ]── Q2.drain
                           Q2.source ── GND
   MCP PB5 ──[ R2 1k ]──┬─ Q2.gate
                        └─[ R3 100k ]── +3.3V

Polarity / default state. PB5 high (or high-Z at boot, via R3) → Q2 on → Q1 on → hub powered. PB5 low → Q1 off → hub unpowered. A power-cycle is therefore: drive PB5 low for ≥ 500 ms, then high.

Current. A fully-loaded four-port hub can draw ~2 A (4 × 500 mA plus the hub). The AO3401A handles the prototype's D: + D!: pair (~1 A) comfortably; for a fully-populated four-port hub use a higher-current P-FET (e.g. AON7407, −8 A) or the load-switch IC below.

Production recommendation — dedicated load switch. For a shipping board, prefer a high-side USB load-switch IC (e.g. SY6280AAC or AP22653, ~2–2.6 A, SOT-23-6) in place of Q1/Q2: active-high EN driven straight from PB4/PB5, built-in soft-start (no inrush network needed), current limit (a shorted stick can't drag the rail down), and a fault flag you can route back to a spare MCP23017 input. Same single control line, fewer failure modes than the discrete pair.

Firmware. AntOS drives PB5 high during bring-up and leaves it. On the hub-wedge condition — today this shows up as repeated D: keepalive FAILED (errno=2) with no re-attach — it issues one low → delay → high pulse on PB5 to power-cycle the HS hub: the in-software equivalent of pulling the hub's power lead, and the recovery path for a USB port that ESP-IDF's hub driver has left stuck.


Prototype

The prototype uses an Olimex ESP32-P4-DevKit board. This provides a network RJ45 connector and a MIPI-DSI-to-HDMI output for the display; io36 is pulled to 3v and io35 (boot) is pulled to 3v. (In production io36 = the FireStorm data-ready interrupt that drives the QSPI return path; on the devkit there's no FPGA, so it's simply tied high.)

DeMon's own USB-Serial-JTAG goes to the USB-C power port — providing power, console, and JTAG debug over a single cable.

The HS USB port drives the storage hub — D:/D!:/E:/B: (see Storage).

The FS USB port drives the HID hub described in Storage above — keyboard, mouse, and the ESP32-C5 and Pulse USB-Serial-JTAGs.

SDCard pinout on prototype (IO39-IO45)

Pin GPIO Original MMS Usage SPI/QSPI
1 IO41 DAT2 SPI3 HOLD/IO3
2 IO42 *CD/DAT3/CS SPI3 CS (QSPI)
3 IO44 *CMD/DI SPI3 MOSI/IO0 (Pulse to DeMon)
4 IO45 out power UPDI to Clicky
5 GND
6 IO43 *SCK SPI3 SCK
7 IO39 *DAT0/DO SPI3 MISO/IO1 (DeMon to Pulse)
8 IO40 DAT1 SPI3 WP/IO2
CD IO3 NC

SPI2 has multiple select lines and can be SPI or QSPI

SPI3 is QSPI slave to pulse

MCP23017 I2C IO expansion

Pin Behaviour Pin Behaviour
PA0 Power off output PB0 Firestorm Config
PA1 Power pushed input PB1 Firestorm Ready
PA2 Power R LED PB2 Firestorm Done
PA3 Power G LED PB3 Pulse EN
PA4 Power B LED PB4 FS HID-hub power
PA5 NFC Reset PB5 HS storage-hub power
PA6 ESP32-C5 BOOT (IO28) PB6 Touch reset
PA7 ESP32-C5 EN PB7 HyperRAM reset
PA INT Power pushed input interrupt PB INT Firestorm done/Firestorm Ready

(ESP32-C5 pin27 should be wired to 1)

**** = spare for now

PB4 / PB5 (FS HID-hub / HS storage-hub power) drive the high-side hub power switches described in Switched Hub Power under Storage — software can power-cycle either hub (drive the line low → wait → high) to recover a wedged USB port without physical intervention; the DBFS keepalive uses PB5 for a wedged drive.

PB6 resets the vertical TFT touch screen's I²C touch controller (the touch keypad set into the keyboard). The OLED debug display's former cycle button and reset line are gone — diagnostics now move to the ICP cartridge, which reads the byte-form data straight off the I²C ports and renders it however it likes; PB INT accordingly carries only FireStorm done/ready.

PB7 drives the FPGA HyperRAM reset line. Because DeMon controls it independently of the FPGA, AntOS can load ROM / cartridge / disk images into the HyperRAM, then hold it out of reset across an FPGA reprogram — so the HyperRAM keeps its contents while FireStorm (or a guest personality image) reloads, and comes back with memory already populated for the incoming FPGA image. (There is no longer a software screen on/off line — the screen stays powered.)

UEXT Name Behaviour
1 3.3v
2 GND
3 io37 UART0_TX to Pulse
4 io38 UART0_RX from Pulse
5 io23 NC
6 io22 NC
7 io54 NC (gpio54 carries Clicky UART2 RX — not connected here)
8 io53 NC (gpio53 carries Clicky UART2 TX — not connected here)
9 io4 nc
10 io5 nc
EXT1 Name Behaviour
1 3.3v
2 GND
3 io2 UART1_TX to ESP32-C5
4 io3 UART1_RX from ESP32-C5
5 io4 ESP32-C5 HANDSHAKE
6 io5 SPI2 CS SDCARD (SPI)
7 io6 SPI2 CLK
8 io7 SPI2 MOSI/IO0 (controller to SD)
9 io8 SPI2 MISO/IO1 (SD to controller)
10 io9 SPI2 CS SCREEN (SPI)
11 io10 SPI2 CS CARTRIDGE (SPI)
12 io11 SPI2 CS ESP C5 WIFI (QSPI)
15 io14 SPI2 CS Pulse (QSPI)
16 io15 SPI2 CS FireStorm (QSPI)
17 io16 JTAG TDI
18 io17 JTAG TMS
19 io18 JTAG TCK
20 io19 JTAG TDO
EXT2 Name Behaviour
1 5v
2 GND
3 io54 UART2 RX (from Clicky)
4 io53 UART2 TX (to Clicky)
5 io48 SPI2 HOLD/IO3
6 io47 SPI2 WP/IO2
7 io46 MCP23017 INT-A
8 io33 I3C master SDA
9 io32 I3C master SCL
10 io23 pulled to 3v VBLANK from FireStorm
11 io22 pulled to 3v SCREEN CMD/DATA
12 io21 NFC Interrupt
13 io20 MCP23017 INT-B
14 ESP_EN
15 GND
16 io27 USB1P1_1P Full USB
17 io26 USB1P1_1N 12Mbps
18 GND
19 DP USB_DP Fast USB
20 DN USB_DN 480Mbps

Prototype 2 GPIO assignments

GPIO Role GPIO Role
0 UART1 CTS (to ESP32-C5) 28 RMII CRS DV
1 UART1 RTS (to ESP32-C5) 29 RMII RXD0
2 UART1 TX to ESP32-C5 30 RMII RXD1
3 UART1 RX from ESP32-C5 31 MDC (SMI CLK)
4 ESP32-C5 HANDSHAKE 32 I3C SCL
5 SPI2 CS SDCARD (SPI) 33 I3C SDA
6 SPI2 CLK 34 RMII TXD0
7 SPI2 MOSI/IO0 (controller to SD) 35 RMII TXD1
8 SPI2 MISO/IO1 (SD to controller) 36 ****
9 SPI2 CS SCREEN (SPI) 37 UART0 TX to Pulse
10 SPI2 CS CARTRIDGE (SPI) 38 UART0 RX from Pulse
11 SPI2 CS ESP C5 WIFI (QSPI) 39 SPI3 MISO/IO1 (DeMon to Pulse)
12 UART0 CTS (to Pulse) 40 SPI3 WP/IO2*
13 UART0 RTS (to Pulse) 41 SPI3 HOLD/IO3
14 SPI2 CS Pulse (QSPI) 42 SPI3 CS (QSPI)
15 SPI2 CS FireStorm (QSPI) 43 SPI3 SCK
16 JTAG TDI 44 SPI3 MOSI/IO0 (Pulse to DeMon)
17 JTAG TMS 45 UPDI to Clicky
18 JTAG TCK 46 MCP23017 INT-A
19 JTAG TDO 47 SPI2 WP/IO2
20 MCP23017 INT-B 48 SPI2 HOLD/IO3
21 NFC interrupt 49 RMII TX EN
22 SCREEN CMD/DATA 50 RMII REF CLK
23 VBLANK from FireStorm 51 PHY reset
24 JTAG USB P1 0P 52 MDIO (SMI DATA)
25 JTAG USB P1 0N 53 UART2 TX (to Clicky)
26 USB1P1_1P 54 UART2 RX (from Clicky)
27 USB1P1_N

**** = spare for now

A Note on the Previous Architecture

In earlier prototypes, DeMon acted only as a low-level supervisor, with AntOS hosted on a separate application SoC. Consolidating AntOS onto DeMon's ESP32-P4 (paired with an ESP32-C5 for connectivity) brings several benefits:

  • AntOS persistence across FPGA reload — bitstream changes no longer require an OS reboot, only a brief screen blackout (a fraction of a second for the native chipset; up to ~1 second for a personality)
  • One coherent OS processor — AntOS runs entirely on DeMon's ESP32-P4 rather than being split across a separate application SoC
  • 32MB PSRAM — enough for AntOS, application data, and OTA staging
  • Native MIPI display engine — DeMon drives its UI directly into the FPGA as a composited layer
  • PIE extensions — small AI / DSP acceleration available in the OS without a separate accelerator chip
  • Native Wi-Fi 6 + BT 5.3 + Thread + Zigbee via the ESP32-C5
  • Simpler power tree — both ESPs are 3.3 V parts with well-characterised power management

The trade-off is that FireStorm in the FPGA is no longer an OS host — it runs user applications, games, demos, and real-time chipset interaction code, while AntOS-level services (filesystem, network, scheduler, UI, debug server) live on DeMon. The two communicate via the QSPI register window and the MIPI link.


Reference Links

Important: The Ant64 family of home computers are at early design/prototype stage, everything you see here is subject to change.