ADR 0006: A hardware enable path for both valve banks, with the hold policy left to the product¶
| Status | Accepted |
| Date | 2026-11-02 |
Context¶
Today "safe" means every valve is commanded to 0 over SPI. Nothing de-energises a bank independently of SPI: a
stalled transfer, a hung valve-bus mutex or a stuck control thread leaves every output as it was. Both driver ICs
have an enable input (MAX22200 ENABLE on GPIO2, TLE92466ED EN on GPIO5) that gates the whole bank in hardware,
but only the drivers' own bring-up touched them. Two smaller defects sat next to it: the pins started as plain
outputs with whatever level the MCU left them at, and the FAULT_N lines of both chips were created as outputs and
driven until ValveManager reconfigured them.
The product's port design (architecture-port §3.4, §3.7, §3.8) gives the safety thread a SafeHold that ends with both enable pins low, reachable without SPI. Whether a side is vented before the hold (vent-then-hold) and whether any vent valve is normally open are open owner questions (Q1, Q2); the first port step keeps today's hold.
Options¶
- Drop the pins inside
ValveManageron any fault it sees. Puts safety policy in the HAL and changes behaviour today. - Expose the hardware path, do not call it on the HAL's own initiative except at shutdown. The product's arbiter decides when.
Decision¶
Option 2.
ValveManager::DropEnablePins()drives both enables low directly through their GPIOs: no SPI, no mutex, no allocation, no logging, whether or not the manager is initialised. It latches: channel-energising calls are then refused withVALVE_ERR_WRONG_MODEuntilRearmEnablePins(), which re-runs the valve bring-up (the MAX22200 is not relied on to keep its configuration across an ENABLE low period).flux::hal::ValveBank::EnablePins(bool)is the facade the product calls.GpioManagercreates the twoFAULT_Nlines as inputs and the two enables driven low from the first instruction (kInputPins,kValveEnablePinsinbsp_bind/board/flux_v1). The banks stay off until the valve drivers' own bring-up raises the enables, exactly as before.ValveManager::Deinitialize()(and soFlux::Shutdown()) ends in SafeHold: every channel off over SPI, then both enables low.- Nothing else drops the pins. Normal operation,
DisableAllChannels()and fault handling behave as before.
Consequences¶
- The product's safety thread can de-energise both banks in one GPIO write each, without depending on the valve bus or its owner thread (design B2: pins low within 6 ms of a latch).
- External pull-downs on
ENABLE,ENandRESN(owner question Q3) are still needed for reset, brown-out and the boot ROM; software cannot hold a pin it does not drive yet. - Vent-then-hold, if the owner chooses it (Q2), is a sequence in the product (relief valves energised for a bounded
time, then
EnablePins(false)); it needs no HAL change.