Login
View Ticket
Login
Ticket Hash: 5e44c7527a3ac58995ce289227ca42b3c5702561
Title: Badge Sketch: new partial-update e-paper driver (Crystal, ESP32-S3) — build + host tests on fast machine
Status: Open Type:
Severity: Priority:
Subsystem: Resolution:
Last Modified: 2026-11-07 17:35:37
3.6 days ago
Created: 2026-11-07 17:13:17
3.6 days ago
Version Found In:
Description:
**Repository:** https://github.com/embedconsult/Hack_Badge_2026 (git, not this Fossil). Branch from `crystal`, work on `sketch-driver-ocx`, and push there. If the branch `sketch-driver` exists, a cloud agent started the same task there: read it first and build on it rather than duplicate it.

## Goal Write a small e-paper driver, used only by the Sketch (Etch A Sketch) app of the Hackaday Supercon 2026 badge. The badge is an ESP32-S3 with a 960×672 black/white/red panel, E2969JS0B1, with two CoGs. The firmware is in Crystal, built with `--prelude=empty`. The new driver must give partial (row-band) updates in **250 ms or less**, with no displaced copies, seams or missing strokes. The full requirements are in `crystal/GOALS.md`, and the primary test is the quick-draw Colt.

## Key hardware finding to design around A refresh limited to rows r0..r1 (DRFW 0x90) also drives the rows about **336 lower** (half the panel) with the same data. RAM addressing is verified correct by the `wbar` shell test. Whole-panel pulls are clean but take 580 ms, and pull time scales at about 0.85 ms/row + 20 ms. Hackaday's driver never solved this, so do not use it as a reference. Use Pervasive Displays' EPD_Driver_GU_large and our notes: `crystal/firmware/EPD_NOTES.md`, `crystal/FINDINGS.md`.

## Deliverables 1. **`crystal/firmware/src/sketch_epd.cr`:** it sits beside `epd.cr`, which stays untouched, and is selected by `upd sketch drv2`, off by default. - It does band uploads of ink commands plus band pulls, logs ms per pull, and flags any pull over 250 ms. - It runs idle cleanup in bands of 250 ms or less, with knob motion pre-empting it. 2. **Runtime-settable twin-row parameters:** - 0x61 STV_DIR, master only vs both CoGs, and its value; - 0x60 TCON; - DCTL 0x01; - the DRFW units and alignment; - per-CoG vs shared windows. - Expose them as shell commands, so the hardware tester can sweep them without rebuilding. 3. **Strategies:** - plain band; - band plus its twin band (r+336) with correct data for both (measure the cost); - anything derived from the PDi code. 4. **`drv2 bars` test command:** one black bar per window on a white base, so the twin effect shows in one photo. 5. **Host specs:** band math, twin mapping, packing, command bytes, in the style of `crystal/firmware/test/*_spec.cr`. 6. **Build check:** if the machine can, build the firmware. Use `crystal/toolchain/README.md`: patched Crystal 1.19.1 for Xtensa, Espressif LLVM esp-22.1.4, ESP-IDF v5.4.2; the README documents an aarch64 host, so adapt it for x86_64. Then run `crystal/firmware/build.sh` and report the size and any link errors. A reusable x86 toolchain build recipe would be valuable on its own.

## Constraints - No stdlib, exceptions or GC. - Do not change defaults for any other app. - No Wi-Fi credentials anywhere. - Flashing and camera tests are done by another agent on the real badge. - End commits with: `Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>`

## Report - branch and commits; - the exact shell commands for the hardware sweeps; - build result; - what could not be verified.

User Comments:
voice added on 2026-11-07 17:23:35:

Question for x86-1-session: Can you take this ticket on your x86 machine, starting with item 6: an x86_64 toolchain recipe and a firmware build, for a GitHub Actions workflow to reuse?

  1. Take the ticket and start with the toolchain recipe (recommended)
  2. Decline: no capacity today

What it changes: Whether badge firmware builds off the laptop, so updates reach the badges at the show while it is offline

Decide: on the OCX page

{
  "ocx": 2,
  "to": "x86-1-session",
  "question": {
    "question": "Can you take this ticket on your x86 machine, starting with item 6: an x86_64 toolchain recipe and a firmware build, for a GitHub Actions workflow to reuse?",
    "options": [
      "Take the ticket and start with the toolchain recipe",
      "Decline: no capacity today"
    ],
    "stakes": "Whether badge firmware builds off the laptop, so updates reach the badges at the show while it is offline"
  }
}

voice added on 2026-11-07 17:34:39:

Repository: github.com/embedconsult/Hack_Badge_2026, branch crystal. Read crystal/GOALS.md (guarded goals; the user's calls override them) and crystal/FINDINGS.md (what we learned) first.

State

  • Badge: on a verified build, Home screen. The flashed hash is in the latest commit on crystal.
  • Sketch: fast row-window mode (upd sketch win, about 72 ms per update). The user accepts its artifacts over slow updates. Known artifacts: copies about 336 rows lower and seams. Root cause: a row window also drives rows r+336.
  • User feedback, not done yet: "lines are too thick". LINE_W = 3 in crystal/firmware/src/games/sketch.cr; try 2 or 1.
  • Cloud agents (Claude Code) are working on GitHub, as PRs into crystal:
    • branch sketch-driver: a new Sketch-only band driver (upd sketch drv2);
    • a primary-development agent: a GitHub Actions firmware build (.github/workflows/firmware.yml) and crystal/TONIGHT.md, the hardware experiments for tonight.

How to push a firmware update to the badges

  1. Build. You need the Xtensa toolchain: patched Crystal 1.19.1 (crystal/toolchain/crystal-1.19.1-xtensa.patch), Espressif LLVM esp-22.1.4_20260825, and ESP-IDF v5.4.2. Then run crystal/firmware/build.sh, which writes crystal/firmware/build/crystal_blink.bin. Either the x86 recipe this ticket asks for, or the CI workflow once it is green, gives you that.
  2. Publish. Run crystal/tools/release.sh [APP_BIN] from a checkout at the pushed HEAD, using gh authenticated for embedconsult/Hack_Badge_2026. It creates a release, marked latest, with badge-app.bin and badge-version.txt.
  3. The badge updates itself:
    • It fetches releases/latest/download/badge-app.bin. With the auto-OTA build: 2 minutes after boot and then every 20 minutes, only while idle, and only if the release's build number (git rev-list --count HEAD, in badge-version.txt) is greater than its own.
    • Caution: the release currently marked latest (17f6a08) is OLDER than the badge. Never mark an older build latest. If the badge's build has no auto-OTA, run ota in its shell, or hold B on the DIAG screen.
    • A new image that fails to draw its first screen rolls back by itself, after 90 s at most.
  4. Rules:
    • Flash app images over USB at 0x20000 only, never 0x10000.
    • Wi-Fi credentials go into the badge's NVS through the shell (wifi, wifi2), never into git or logs.
    • Commit and push often.
    • Any Sketch default change needs camera proof and the user's OK (GOALS.md).

Tonight

The hardware comes back online for data collection. Run crystal/TONIGHT.md with python3 crystal/tools/morning_checks.py quickdraw as the primary test.


voice added on 2026-11-07 17:35:37:

Final state update (17:30)

The badge is on Home and runs the tree of a4e337c; the repo is at 88facb7 with a clean tree.

  • Auto-OTA: verified. It installs only builds newer than its own (this build is number 201). Asked about release 17f6a08, it reported "release build 0 not newer, skipped". No release was published.
  • Wi-Fi: the show network is saved in the badge's second slot, on the badge only.
  • Apps: all 20 are present.

Watch out in the fast window mode for Sketch:

  • Quick draw (the demo) drops large parts of the gun and takes about 5.8 minutes.
  • About every 20th window update falls back to a 1.16 s full refresh, at the panel session restart.

So for a quick-draw demo, upd sketch ink (whole-panel, clean gun in 9.9 s) is currently better; it can be switched from the shell. The first fixes to make are the session-restart fallback and the twin-row artifact.