No. 72 / project of 147 on the ladder

AtomVM chip-visible I/O NIF demo

introduces — AtomVM platform NIFs; Erlang-driven chip UART writes; Erlang framebuffer marker writes; frame-ready bridge from AtomVM

harden statelast run2026-05-05
signoff
  • DRCNOT RUN
  • LVSNOT RUN
  • antennaNOT RUN

P71 proved AtomVM could run a bundled-stdlib concurrent workload on the chip. P72 changes the question: can Erlang code reach out of the VM and cause chip-visible behavior?

Headline: AtomVM now resolves local platform NIFs and Erlang uses them to write UART bytes, read mtime, write RGB565 framebuffer markers, and pulse the host frame-dump bridge.

AtomVM on P72 (chip-visible I/O NIF demo)
Starting AtomVM revision 0.8.0-dev+git.fd574b8
Found startup beam: chip_io.beam
P72 AtomVM chip I/O starting
chip mtime ms: 336
$ chip:uart_putc/1 says hello from Erlang
chip fb base: 15728640
[harness] frame 1 dumped (24576 bytes)
[harness] frame 2 dumped (24576 bytes)
[harness] frame 3 dumped (24576 bytes)
frame worker pulses: 3
chip mtime delta ms: 243
P72 AtomVM chip I/O PASS
Return value: ok
AtomVM exited result=0

What changed

The RTL stays on the P70/P71 base. The important change is in the AtomVM platform shim: platform_nifs_get_nif() now resolves a small chip module surface.

NIFeffect
chip:uart_putc/1writes one byte to the chip UART MMIO data register
chip:mtime_ms/0reads the monotonic chip timer in milliseconds
chip:fb_base/0returns the demo framebuffer scratch base
chip:write16/2writes one RGB565 halfword inside the scratch framebuffer window
chip:frame_ready/1pulses the existing MMIO_FRAME_READY bridge

erlang/chip_io.erl calls those NIFs from a spawned worker process, draws three tiny 16x16 colored blocks, pulses frame-ready after each block, and reports the count back to the parent.

Verification

cd projects/72_atomvm_chip_io/test
make all
make verilator-run-fb

Harness result:

[harness] halted=1, halt_code=0x00000001

The frame dumps are in projects/72_atomvm_chip_io/test/captured/frames/. This is not yet “real graphics”; it is a marker that proves the whole path is wired: Erlang -> AtomVM platform NIF -> chip memory/MMIO -> Verilator host dump.

What is not proven

F/D architectural compliance was NOT RUN. LibreLane hardening was NOT RUN. The framebuffer window is a P72 scratch convention at 0x00f00000, chosen to avoid the AtomVM lib.avm and main.avm slots. A future graphics rung should make that memory map explicit.

What just happened?

AtomVM stopped being a sealed runtime. Erlang can now call into a tiny chip platform API and create observable hardware-side effects. That is the bridge we need before doing AtomVM-driven graphics to the host.