Skip to content

Module Firmware

Alex Van de Putte edited this page Jul 16, 2026 · 6 revisions

Module Firmware

Every split-flap module runs the SplitFlap Universal Firmware — one binary, flashed once to each module. Identity, calibration and the flap set are stored in the chip's EEPROM and assigned after flashing, so there is nothing to change per module before you upload.

Repo: github.com/avandeputte/SplitFlapUniversalFirmware · target: ATtiny1616 · toolchain: PlatformIO · programmer: SerialUPDI

Three stages take a bare module to a working cell: flash → provision → calibrate. Everything below rides the RS-485 wire protocol — every command, reply and result code is specified in Bus Protocol.


1. Flash

You need VS Code, the PlatformIO extension, and a SerialUPDI programmer — a cheap USB-to-serial adapter (CP2102, CH340, FT232 …) wired for UPDI: a single 470 Ω – 1 kΩ resistor between the adapter's TX and RX forms the UPDI data line, which connects to the chip's UPDI pin. The adapter does not power the board — power the module from its own supply.

  1. Install VS Code, then the PlatformIO IDE extension (it downloads the ATtiny toolchain on first build).
  2. Get the code and open the folder that directly contains platformio.ini (the highest-numbered version folder).
  3. Wire the programmer with the module powered off: UPDI data line → UPDI pin, adapter GND → module GND. Then power the module and plug in USB.
  4. Set upload_port in platformio.ini to your adapter's port (/dev/cu.usbserial-…, COM5, /dev/ttyUSB0).
  5. Build (the ✓ button, or pio run).
  6. Write fuses once per chip: pio run -t fuses. This sets the EESAVE fuse so the module's EEPROM (its ID, calibration and flap set) survives future reflashes. Skipping this means every upload wipes the module's identity.
  7. Upload (the → button, or pio run -t upload).
  8. Verify over the bus: sending m<ID>v returns the firmware version, ID and serial.

Every module gets the identical binary. platformio.ini is preconfigured (10 MHz internal clock, eesave on, SerialUPDI at 57600 baud).


2. Provisioning

(The short version — the full process, gateway and bare-metal alike, is Module provisioning.)

A freshly flashed module has no ID (it reports 255) and doesn't answer numeric commands. Instead it advertises its serial number on the bus every 10–15 seconds. You assign it a bus ID from the Gateway's Provision tab, from splitflap-os's own UI (provisioning is built into the product) if that is what drives your wall, or with the included provision.py terminal tool on any serial host — all three do the same thing.

The flow, either way:

  1. Discover — the tool/UI lists modules advertising their serials.
  2. Identify (optional) — home one module by serial so its reel spins; you can see which physical tile it is.
  3. Assign — give it a bus ID (0, 1, 2, …). The module writes the ID to EEPROM, acknowledges, and stops advertising.

Repeat for each cell, left to right, top to bottom, to match how you want the wall addressed. To start over, de-provision a module (or all) and it returns to advertising.

Because identity is assigned here — not compiled in — you flash the same binary to every module and never touch the IDE again after the first flash.


3. Calibration

(The short version — the full walkthrough is Module calibration.)

Calibration teaches each module where "home" is and how far a full reel turn is, so the right flap lands dead center. Again this is easiest from the Gateway's Calibration tab (it has a guided wizard), but the underlying steps are:

  • Count steps per revolution — the module measures a full turn automatically.
  • Set the home offset — nudge so the blank flap sits centered at home.
  • (Optional) per-flap fine-tuning — for any flap that lands slightly off, drive to it and lock a corrected position into the map.
  • (Optional) custom flap set — if your reel isn't the default 64-flap set, tell the module its character string so text maps to the right flaps.

Once calibrated, the values live in EEPROM and survive reboots (and reflashes, thanks to the EESAVE fuse).


Diagnostics

The firmware has built-in self-tests, surfaced on the gateway's Modules tab (or over the bus). Run them in order — each depends on the one before:

  1. Snapshot — reset cause, boot count, supply voltage, EEPROM OK, current flap. No movement.
  2. Hall sensor test — one revolution; reports OK / stuck / dead / noisy / inverted.
  3. Mechanical test — several revolutions; reports OK / inconsistent / no motion.

The flap set

The default 64-flap reel is:

 (blank) A–Z  0–9  ! @ # $ & ( ) - + = ; : % ' . , / ? *  r o y g b p w

The seven lowercase letters at the end are the colour flaps (red, orange, yellow, green, blue, purple, white).

Both the flap count and the character set are configurable per module and stored in EEPROM (v31+) — so you can print a reel with É, Ö or Ñ on it, or a shorter reel with no punctuation, and text still lands on the right flap. This is one of the Universal Firmware's biggest departures from the original, and it's what makes the companion's translated apps show up as words rather than blanks.

Flaps & character sets — how to set it, the 64-flap budget, and starter sets per locale.


Next: Gateway →

Clone this wiki locally