chore(firmware): scaffold Spike 1 Blink crate

Generated from esp-rs/esp-idf-template for the ESP32-S3 std target.
src/main.rs toggles GPIO 2 every 500 ms and logs `blink N` over USB-
serial — the minimum bring-up surface called out in
docs/v0.1-mvp-technical.md (Spike 1: confirm toolchain, flash, and basic
GPIO). edition=2024 with rust-version=1.85.

No editor/render/git/usb/fs modules yet; those land per the spike
methodology when later spikes need them.
This commit is contained in:
Julien Calixte
2026-05-23 14:36:51 +02:00
parent 4bdcdd09ba
commit 55ba0db0f6
8 changed files with 209 additions and 0 deletions

111
firmware/README.md Normal file
View File

@@ -0,0 +1,111 @@
# 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 post-flash, once the
board is on the bench).
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).
## 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. If you want to drive the on-board addressable LED instead,
that's WS2812 on GPIO 48 and needs a different driver — out of scope for
Spike 1.
## 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.