# Typoena firmware Rust crate targeting `xtensa-esp32s3-espidf`. See the project root [`README.md`](../README.md) and [`docs/v0.1-mvp-technical.md`](../docs/v0.1-mvp-technical.md) for the wider context. ## Current state **Spike 1 — Blink.** Toggles GPIO 2 every 500 ms and logs `blink N` to the USB-serial console. This proves three things only: 1. The Espressif Rust toolchain (Xtensa) is installed and on PATH. 2. The crate links against `esp-idf-svc` and compiles for `xtensa-esp32s3-espidf`. 3. Basic GPIO output works on real silicon — verified 2026-07-04 on an ESP32-S3 (rev v0.2, 16 MB flash): `blink N` streams at 1 Hz over USB-serial (115200) and GPIO 2 + the on-board WS2812 toggle in lockstep. Everything past that — EPD, SD, USB host, partial refresh, Wi-Fi/TLS, gitoxide push — is its own follow-up spike per [`docs/v0.1-mvp-technical.md`](../docs/v0.1-mvp-technical.md#hardware-bring-up-order). ## Quick commands A [`justfile`](https://github.com/casey/just) wraps the common commands and sources the espup env itself — run `just` in this directory for the list (`build`, `flash`, `monitor`, `info`, `ports`). ## Build Once per shell session, source the espup env (sets `LIBCLANG_PATH` and adds the Xtensa GCC to `PATH`): ```sh . ~/export-esp.sh ``` Then from this directory: ```sh cargo build --release ``` The first build is slow (the esp-idf C sources are checked out and built under `.embuild/`). Subsequent builds are incremental. ## Flash (when hardware is on the bench) `cargo run --release` triggers `espflash flash --monitor` via the runner configured in `.cargo/config.toml`. With the ESP32-S3-DevKitC-1 connected over USB you should see: ``` […] blink 0 […] blink 1 […] blink 2 … ``` at 1 Hz on the serial monitor, and — if an LED is wired from GPIO 2 → 330 Ω → GND — the LED blinks in lockstep. ## Pin choice GPIO 2 is a safe general-purpose pin on the ESP32-S3-DevKitC-1: it's not tied to a strapping function at boot and not muxed to the USB or PSRAM peripherals. The blink loop also drives the on-board addressable LED — WS2812 on GPIO 48 (GPIO 38 on DevKitC-1 v1.1 boards) — via the RMT peripheral, so both a plain GPIO and the RMT path are exercised. ## Board pinout The bench board follows the **ESP32-S3-DevKitC-1 v1.0** pinout — an ESP32-S3-WROOM-1 **N16R8** module (16 MB flash, 8 MB octal PSRAM). The v1.0 revision wires the on-board WS2812 RGB LED to **GPIO 48**; v1.1 moved it to GPIO 38, so match assignments against this diagram, not the v1.1 one. ![ESP32-S3-DevKitC-1 v1.0 pinout](docs/esp32-s3-devkitc-1-v1.0-pinout.jpg) Source: [Espressif ESP32-S3-DevKitC-1 v1.0 user guide][devkitc-1-v1.0]. The octal PSRAM consumes **GPIO 26–37**, so those are unavailable for peripherals. [devkitc-1-v1.0]: https://docs.espressif.com/projects/esp-dev-kits/en/latest/esp32s3/esp32-s3-devkitc-1/user_guide_v1.0.html ## Editor / rust-analyzer The repo-level `.zed/settings.json` configures `rust-analyzer` for this crate: - `cargo.target` is pinned to `xtensa-esp32s3-espidf` with `allTargets = false`, so RA doesn't try to also check the crate for the host target (which can't build `esp-idf-sys`). - `binary.path` is pinned to the **rustup-managed** rust-analyzer (`stable` toolchain), not Zed's bundled one. Reason: recent Zed builds ship a rust-analyzer that calls `cargo metadata --lockfile-path`, which is still gated behind `-Z unstable-options` in cargo 1.95 and fails on both the `stable` and `esp` toolchains. The rustup-managed RA is version-locked to the cargo it ships with and avoids the flag. If a contributor on a different machine has issues, regenerate the path: ```sh rustup component add rust-analyzer --toolchain stable rustup which rust-analyzer --toolchain stable # put the printed path into .zed/settings.json under lsp.rust-analyzer.binary.path ``` Two things rust-analyzer still needs from the **environment Zed was launched in**: - `LIBCLANG_PATH` — required by `bindgen` inside `esp-idf-sys`. - The Xtensa GCC on `PATH` — required by `embuild` during `cargo check`. Both are set by `~/export-esp.sh`. The pragmatic workflow: ```sh . ~/export-esp.sh zed /Users/julien/jclab/typewriter # or: open from this shell ``` If Zed is launched from Finder/Dock instead, rust-analyzer will report `bindgen` errors on the first `esp-idf-sys` check. Close Zed, source the env in a terminal, and relaunch from there. ## Toolchain pins `rust-toolchain.toml` pins the channel to `esp` (installed by `espup install`). Cargo.toml currently includes git `[patch.crates-io]` overrides for `esp-idf-sys` / `esp-idf-hal` / `esp-idf-svc` (template default). These follow master and may need pinning to released versions if a master commit breaks the build.