diff options
| author | Gabriel Schneider <[email protected]> | 2026-08-26 12:40:24 -0300 |
|---|---|---|
| committer | Gabriel Schneider <[email protected]> | 2026-08-26 12:40:24 -0300 |
| commit | 38bb891dd6bd0074894cbfedbf9185e303cc549e (patch) | |
| tree | 3362ea366be103c26ae78cee7467766fa697cae7 /src/pardes | |
| parent | 85cf1a7dd912db4a5fc3ac2cb9d8550050ffbdb0 (diff) | |
| download | esp32p4-38bb891dd6bd0074894cbfedbf9185e303cc549e.tar.gz esp32p4-38bb891dd6bd0074894cbfedbf9185e303cc549e.zip | |
Offer the editor the board's pads, and check one flips on the die
## The board half of Gpio
`pardes_p4_init` gained a `GpioFn` and the ABI version went to 2, which is what turns a mixed
pair of builds into a refusal to boot rather than five arguments read as six.
`gpioToggle` is four lines over `hal.gpio`: configure the pad as a readable output, read the level
it is driving, drive the other one, read it again. It is deliberately here and not in the editor.
A toggle is not a write to GPIO_OUT - `configureOutput` sets the IO MUX function, the GPIO matrix
route, the drive strength, the input buffer and the pulls, then the output enable, indexed by a
per-pin table - and that code is already in this repo, already the call `src/main.zig` blinks with,
and already checked against ESP-IDF's headers by `zig build diff`. The editor object gets a
function pointer instead of a second copy nobody tests.
`getDrivenLevel`, not `getLevel`: the answer is the level the board is driving, which is defined
for every pin. The pad's own level is what the outside world says, and on an unconnected header pin
that is noise. The input buffer is enabled anyway so `Peek` of GPIO_IN_REG can be compared to it.
## A fifth hardware check
`p4-bench --check` runs `Gpio 33` three times and requires 0->1, 1->0, 0->1.
The alternation is the oracle, not either answer. `0->1` alone is what a firmware printing a
hardcoded string would also say; two runs that disagree can only come from a level that was stored
and read again. Three, so the third rules out an ordering coincidence. GPIO33 because
`src/oracle/ledc_cases.zig` already documents it as a free pin on this board's JP1 header - pin 21
on the diagram the editor now draws. GPIO20 is the blink demo's pin and may have a wire on it.
This is the only check here that crosses the whole seam: editor word, C ABI, HAL, pad, and the
level back out through the message row. Nothing smaller exercises the ABI at all.
## -Dtheme-animation forwarded
Same path as the geometry, for the same reason: baked into the object, wanted from here.
All five checks pass on the die; host tests green; the board is flashed with md5 932898f34ca1dc31.
Diffstat (limited to 'src/pardes')
| -rw-r--r-- | src/pardes/app.zig | 34 |
1 files changed, 32 insertions, 2 deletions
diff --git a/src/pardes/app.zig b/src/pardes/app.zig index 8b43791..17bef83 100644 --- a/src/pardes/app.zig +++ b/src/pardes/app.zig @@ -64,6 +64,10 @@ const uart = @import("uart.zig"); /// How the editor emits bytes. Called with finished runs of ANSI, many times per frame. const WriteFn = *const fn (ctx: ?*anyopaque, ptr: [*]const u8, len: usize) callconv(.c) void; +/// The board's pads, offered to the editor. Optional on the wire so a firmware with nothing to +/// toggle passes null and the `Gpio` word reports that rather than the object guessing. +const GpioFn = *const fn (ctx: ?*anyopaque, pin: u16, was: *u8, now: *u8) callconv(.c) bool; + /// This board's allocator, handed across as plain function pointers. `log2_align` is a log2 value, /// which is exactly how `std.mem.Alignment` represents itself, so neither side needs a conversion /// table. @@ -81,7 +85,7 @@ const Allocator = extern struct { /// The one number both sides must agree on. Linkers do not type-check C symbols, so a signature /// that drifts on one side of this seam links cleanly and then corrupts the stack; checking this /// before calling anything else turns that into a refusal to boot. -const abi_version: u32 = 1; +const abi_version: u32 = 2; extern fn pardes_p4_abi_version() callconv(.c) u32; /// Hand over the allocator and the output sink, and state the initial window size. Returns 0, or a @@ -89,6 +93,7 @@ extern fn pardes_p4_abi_version() callconv(.c) u32; extern fn pardes_p4_init( alloc: *const Allocator, write: WriteFn, + gpio: ?GpioFn, ctx: ?*anyopaque, cols: u16, rows: u16, @@ -124,6 +129,31 @@ fn writeOut(_: ?*anyopaque, ptr: [*]const u8, len: usize) callconv(.c) void { uart.write(ptr[0..len]); } +/// Flip one pad and report the level before and after. The editor's `Gpio` word calls this; the +/// editor has no register of its own for it, deliberately. +/// +/// THIS IS WHY THE SEAM IS HERE. A toggle is not a write to GPIO_OUT: `configureOutput` points the +/// pad's IO MUX at the GPIO function, routes the GPIO matrix's output to it, sets the drive strength +/// and input buffer and clears the pulls, and only then enables the driver - four register files, +/// indexed by a per-pin table. That code already exists in `hal/gpio.zig`, it is the same call +/// `src/main.zig` blinks with, and its register numbers are checked against ESP-IDF's own headers by +/// `zig build diff`. A second copy inside the editor object would be a second copy under no test. +/// +/// `getDrivenLevel` rather than `getLevel`: the answer is the level this board is DRIVING, which is +/// defined for every pin. The pad's own level is what the outside world says, and on an unconnected +/// header pin that is noise. The input buffer is enabled anyway, so `Peek` of GPIO_IN_REG shows the +/// pad for anyone who wants to compare the two. +fn gpioToggle(_: ?*anyopaque, pin: u16, was: *u8, now: *u8) callconv(.c) bool { + if (pin > hal.gpio.max_pin) return false; + const p: u8 = @intCast(pin); + hal.gpio.configureOutput(p, .{ .readback = true }); + const before = hal.gpio.getDrivenLevel(p); + if (before == 1) hal.gpio.setLow(p) else hal.gpio.setHigh(p); + was.* = before; + now.* = hal.gpio.getDrivenLevel(p); + return true; +} + // ------------------------------------------------------------------------------------- the heap /// The span the linker script hands over, from `l2high`'s ORIGIN and LENGTH. @@ -221,7 +251,7 @@ export fn zig_main() noreturn { // Ask for more than any grid this board will ever render, so the SHELL's own ceiling is what // governs - it clamps to `-Dp4-cols`/`-Dp4-rows` and reports the result. Naming 80x24 here made // the firmware a second opinion about the geometry, which is one opinion too many. - const rc = pardes_p4_init(&editor_allocator, writeOut, null, 255, 255); + const rc = pardes_p4_init(&editor_allocator, writeOut, gpioToggle, null, 255, 255); if (rc != 0) { soc.rom.print("MARK PARDES_INIT_FAIL rc=%u\r\n", .{rc}); |
