Debug Display — SSD1363 OLED (optional)

A hidden diagnostic surface inside the case. The system uses it to talk to itself — to show what it's doing, what's gone wrong, and what's been happening — to anyone who knows it's there.

Direction (planned). The primary diagnostic surface is moving to the ICP cartridge — it runs its own CPU from the cart 5 V rail, boots independently of the host, and renders whichever supervisor's diagnostic feed (DeMon, Pulse, or the ESP32-C5) is selected from its menu over the cart I2C/I3C bus, as fast as any local screen. Once that path lands, this in-case OLED becomes an optional always-present mirror of the same feed rather than the independent last-resort surface described below — handy on a unit with nothing in the cart slot, but no longer the keystone. Its screen-cycling button and reset (DeMon MCP23017 PB6/PB7) are transitional and will free up.


Purpose

The Ant64 can contain a small OLED display tucked inside the case, not visible from the outside in normal operation. It is not fitted by default — it's a builder/developer option for units that want a permanently-on diagnostic surface independent of every other subsystem. Production Ant64s typically ship without it. Debugging boards, field-service builds, kits, and developer units may include it.

When fitted, it exists for one purpose: to give the system a way to show what it's doing without depending on the main display, FireStorm, the FPGA, the keyboard, the network, or any other subsystem that might itself be the thing that's broken.

The main display path is rich and useful — but it depends on a lot:

  • FPGA bitstream loaded
  • FireStorm running and compositing
  • HDMI link healthy
  • HDMI/DP/VGA output stage configured
  • A working TV or monitor on the other end

When any of those fail — and especially during the seconds before they come up — there's nothing to look at. The hidden OLED solves that for builders who fitted it. It runs on plain I2C from DeMon (the CM5), comes alive within milliseconds of power-on, and depends on essentially nothing else. If the rest of the machine has hung, glitched, or refused to boot, the OLED still tells the story.

It is deliberately not user-facing. The user-facing display is the HDMI output, the keyboard touchscreen, and the network terminals. The OLED is for the machine to introspect — diagnostics, traces, the kind of information that would clutter the user UI but is invaluable when something needs investigating.

When not fitted

sys_oled probes the I2C bus at boot. If no display ACKs at the expected address, the module silently disables itself and logs a single line noting "no OLED detected — diagnostic display disabled." All diagnostic content that would have gone to the OLED continues to flow to:

  • The UART console (always available via the USB-Serial-JTAG)
  • The network debug stream (once networking is up)
  • The event log ring buffer in RAM (queryable via shell commands and GDB)

So no functional information is lost — the OLED is purely an additional convenience for builders who want a permanently-visible status surface without needing a console connection. A production Ant64 with no OLED has identical functionality; it just has no visible heartbeat when the user opens the case.


Hardware

A 2.7" 256×128 monochrome OLED driven by the Solomon Systech SSD1363 controller, mounted inside the case on a small daughter board. Connects to DeMon over standard I2C on sys_i2c (port 0) at address 0x3C.

Key specifications:

Property Value
Controller SSD1363
Resolution 256 × 128
Greyscale 16 levels (4 bpp)
Active area ~61 × 31 mm
Pixel pitch 0.24 mm
Interface I2C (also supports SPI, parallel)
I2C address 0x3C (SA0 strapped low)
Frame buffer size 16 KB
Power Self-illuminating, no backlight
Operating temp -40°C to +85°C
Lifetime Standard OLED — fine for diagnostic use

I2C runs at 100 kHz on this bus (shared with the RTCC, EEPROM, and NFC chip). At that rate, a full-frame transfer takes ~1.5 seconds — but the OLED is never refreshed full-frame in normal operation. Updates are partial-region writes of typically a few hundred bytes, taking tens of milliseconds. The system spends >99% of its time not talking to the OLED.

Earlier Ant64 prototypes used a smaller SSD1315 128×64 monochrome OLED in this role. The SSD1363 replaces it entirely; SSD1315 support has been removed from the codebase.


The Overview Screen

The default screen on power-up. Stays up unless the button is pressed. Shows everything the user is likely to want to glance at without interaction:

┌──────────────────────────────────────────┐
│ AntOS v0.4   uptime 00:12:34   ●cpu 18% │  ← header (bright)
│ tasks: 14 ready, 2 blocked              │
│ heap:  free 3.4GB / 4.0GB (85%)         │
│ ──────────────────────────────────────── │  ← divider (dim)
│ HDMI: 1280x720@60 locked H=0x4651       │
│ USB:  D=0x0781:5591 E=0x090c:1000       │
│ I2C0: RTC EEPROM OLED NFC PN532         │
│ NET:  wifi up 192.168.1.42  ssid=home   │
│ ──────────────────────────────────────── │
│ DBFS: D:/DBFS/sys.db   shadow ON        │
│ ──────────────────────────────────────── │
│ [15:42:01] sys_storage: detach D:       │  ← event log (fades)
│ [15:42:03] sys_storage: attach D:       │
│ [15:42:03] db: reopened sys.db          │
│ [15:42:08] hdmi: HPD edge               │
│ ──────────────────────────────────────── │
│ ▌Screen 0/8 — Overview                  │  ← screen indicator
└──────────────────────────────────────────┘

Layout regions:

Region Rows Update rate Content
Header 1 1 Hz OS version, uptime, CPU%
System summary 2 0.5 Hz Task count, heap
Subsystems 4 0.5 Hz HDMI, USB, I2C, network state
DBFS 1 event-driven Master path, shadow state
Event log 4-5 event-driven Most recent system events
Footer 1 static Current screen indicator

The event log is a ring buffer of N lines (probably 32) — the bottom 4-5 are shown on-screen, the rest are visible on the dedicated event-log screen (see below).


Additional Screens (via Button)

A momentary tactile switch beside the OLED cycles through additional screens for deep-dive diagnostics. Each one fills the full 256×128 with detail on one subsystem.

# Screen Purpose
0 Overview Default screen described above
1 Tasks All OS tasks: name, state, stack high-water, CPU%
2 Heap All heap regions with free/used, fragmentation, biggest blocks
3 USB Topology Tree view: root hub → ports → connected devices
4 Display / HDMI HDMI link status, lock state, framebuffer info
5 DBFS Master + shadow status, pair markers, last write, schema version
6 Network Interfaces, routes, listening services, recent traffic
7 Event Log (full) Entire ring buffer, paginated; scroll with extra button presses

Pressing the button when on the last screen wraps back to Screen 0. The current screen number persists across button presses but resets to 0 on long-press or reboot.


Button Semantics

A single momentary tact switch handles all interaction:

Action Effect
Short press (<300 ms) Next screen
Long press (>1 s) Return to Screen 0 (overview)
Double press Freeze updates on current screen — useful for reading without it changing, or photographing the state
Triple press Toggle invert (light-on-dark ↔ dark-on-light)
Hold during boot Enter recovery mode — show only the boot log, no other screens accessible until reset

Software debouncing handles contact bounce. The button uses a single GPIO with an internal pull-up; pressed = ground.


Refresh Strategy

The OLED is updated by region, not full-frame. Each region has its own update cadence based on how often its content actually changes:

Region Update rate Reasoning
Header (uptime, CPU%) 1 Hz User expects "now-ish"
Subsystem status 0.5 Hz Changes are rare; 2 s lag is invisible
Heap / memory 0.2 Hz Slowly drifting; nobody watches second-by-second
Network state 0.5 Hz Rarely changes once up
Event log event-driven Push when something happens, otherwise idle
DBFS status event-driven Changes only on attach/detach/promote

This means the I2C bus is nearly always idle from the OLED's perspective. A 1 Hz tick that updates only what changed is typically ~500 bytes of traffic per second — ~0.4% of bus capacity at 100 kHz. Effectively invisible.

The full 16 KB redraw only happens at boot, screen change (button press), or invert toggle. Those are user-visible events where a ~1.5 s redraw is acceptable.


Visual Design

The SSD1363's 16-level greyscale is used deliberately to create a visual hierarchy. Without it the screen would just be a dense wall of identical-weight text; with it the eye can skim for what matters.

Brightness Used for
100% (full white) Header, errors, warnings, freshly-changed values, current cursor
75% Static labels, fresh log entries
50% Default body text, idle/normal status values
25-30% Dividers, frames, screen indicator
12% Aged log entries (older than ~10 seconds)
0% (off) Pixel-off, log entries that have scrolled out of the visible window

The event log uses fade-on-scroll: a new entry appears at the bottom at 75%, fading by one level each subsequent tick until it reaches the floor of 12% and then scrolls off the top. This gives a strong sense of "what just happened" without the user having to actively read every line — recent events draw the eye, old ones recede.

Greyscale also enables simple visual meters without dedicated chrome: a heap bar can be 50%-filled with full-bright pixels for the used portion and 12% for the empty, giving an immediate sense of fullness without bar borders or labels.


Implementation Notes

sys_oled module structure

sys_oled.c        — public API (write_line, fill_region, set_screen, etc.)
sys_oled_ssd1363.c — chip driver (init sequence, partial-region writes)
sys_oled_overview.c — Screen 0 layout renderer
sys_oled_tasks.c   — Screen 1 layout renderer
sys_oled_heap.c    — Screen 2 layout renderer
...
sys_oled_button.c  — button state machine
sys_oled_log.c     — event log ring buffer

Each screen renderer is responsible for its own region updates. The dispatcher knows which screen is current and only ticks the corresponding renderer.

Event log ring buffer

A small in-RAM circular buffer (probably 32 entries × 48 bytes each = 1.5 KB) holds the most recent system events. Any subsystem can call sys_oled_log_event(tag, fmt, ...) and the line lands in the buffer regardless of which screen is current. Both Screen 0 (bottom 4-5 lines) and Screen 7 (full buffer paginated) read from the same buffer.

The buffer also survives subsystem failures — it's a plain RAM allocation that doesn't depend on DBFS, the filesystem, or any other subsystem that might itself be the thing producing the log entries.

Recovery-mode boot

If the button is held during reset, sys_oled enters a special mode where:

  • Only the boot log scrolls across the entire screen (no overview layout)
  • All button presses except "release" do nothing
  • The screen state is independent of normal operation — even if sys_storage or other subsystems fail, the boot log still scrolls

This is the diagnostic-of-last-resort surface: when the system can't boot far enough to show anything meaningful on the main display, the OLED can still scroll the boot log at the user.


Implementation Status

This document describes the target architecture for SSD1363-fitted units. Current status (v0.4):

  • Active: previous-generation SSD1315 driver (128×64 monochrome, single-line status) — being retired in favour of SSD1363
  • Pending: SSD1363 part on order
  • Pending: SSD1363 driver back-end (sys_oled_ssd1363.c)
  • Pending: sys_oled probe-and-disable logic for the no-OLED-fitted case
  • Pending: screen renderers (overview, tasks, heap, USB, DBFS, etc.)
  • Pending: event log ring buffer
  • Pending: button hardware + state machine

The sys_oled public API stays stable across "no OLED" and "OLED fitted" states — calling code that uses sys_oled_write_line() etc. keeps working regardless. Only the internal driver behaviour changes.


Related Documents

  • DeMon — the Raspberry Pi CM5 supervisor that hosts the I2C bus the OLED lives on
  • AntOS — the operating system whose state the OLED displays
  • Filesystem & Drive Letters — DBFS state shown on Screen 5
  • AntOS Text Architecture — the main display's text system (separate from this debug surface)

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