diff --git a/Architecture/IO_ARCHITECTURE.md b/Architecture/IO_ARCHITECTURE.md
index feffb04..0a50456 100644
--- a/Architecture/IO_ARCHITECTURE.md
+++ b/Architecture/IO_ARCHITECTURE.md
@@ -68,13 +68,14 @@ external analogue-pin pool, so they increase concurrent conversion capacity
rather than doubling the number of physical sensor pins. The proposed V1
allocation occupies 16 conditioned ADC channels:
-```text
-4 thermistor inputs
-9 general 0-5 V inputs
-1 VBAT_PROT sense input
-1 +5V_SENS sense input
-1 +12V_SENS sense input
-```
+| Conditioned ADC input class | Channels |
+| --- | ---: |
+| Thermistors | 4 |
+| General 0–5 V inputs | 9 |
+| `VBAT_PROT` sense | 1 |
+| `+5V_SENS` sense | 1 |
+| `+12V_SENS` sense | 1 |
+| **Total** | **16** |
This leaves meaningful MCU ADC and pin margin, but the final STM32 package and
pin assignment must reserve all analogue pins alongside timer, CAN, debug,
@@ -90,11 +91,7 @@ because an open thermistor drives the node towards 5 V. Firmware calculates the
thermistor resistance from the ratio of its ADC result to the `+5V_SENS` ADC
result, then applies the calibration map for the selected sensor.
-```text
-+5V_SENS -- precision pull-up --+-- thermistor -- sensor ground
- |
- attenuation/filter --> ADC
-```
+
The pull-up value is selected from the actual NTC curve and required
temperature range, balancing resolution against self-heating. The attenuation
@@ -169,13 +166,9 @@ released. It has two independent destinations:
- `DEADMAN_OK` is combined in hardware with the MCU's `MCU_RUN_PERMIT` output
to produce `ENGINE_PERMIT`.
-```text
-deadman contact A --> protected input --> DEADMAN_A_HELD --------+
- +--> valid-state logic --> DEADMAN_OK --+
-deadman contact B --> protected input --> inverted --> DEADMAN_B_RELEASED -+ |
- AND --> ENGINE_PERMIT
-MCU_RUN_PERMIT ----------------------------------------------------------------------------------------------+
-```
+
+
+
`ENGINE_PERMIT` controls the enable inputs of the injector and ignition drivers
where those inputs are provided. If a selected driver has no suitable enable
@@ -239,9 +232,7 @@ only when the selected external starter switch accepts that interface.
Analogue output is not a V1 functional requirement. Reserve two MCU pins and
board footprints for future 0-5 V outputs. The intended future path is:
-```text
-DAC --> rail-to-rail buffer --> protection / series impedance --> connector
-```
+
A true calibrated 0-5 V output may require an external 5 V-referenced DAC or
a suitably characterised buffer stage. A general 0-12 V analogue output is not
diff --git a/Architecture/IO_MODULES/ANALOG_INPUTS.md b/Architecture/IO_MODULES/ANALOG_INPUTS.md
index 6ca918e..c7d3dab 100644
--- a/Architecture/IO_MODULES/ANALOG_INPUTS.md
+++ b/Architecture/IO_MODULES/ANALOG_INPUTS.md
@@ -9,13 +9,7 @@ use `SENSOR_GND` and are kept separate from ignition/injector return currents.
## General 0--5 V channels
-```text
-connector -- transient clamp -- R_TOP --+-- ADC-local C_HOLD -- ADC
- |
- R_BOTTOM
- |
- SENSOR_GND
-```
+
`R_TOP` is the divider's upper resistor; do not add a separate series
`R_PROT` in the normal passive channel. It is the element that limits current
@@ -45,11 +39,7 @@ of `+5V_SENS` and sample it close to the sensor channel.
## NTC temperature channels
-```text
-+5V_SENS -- R_PULLUP --+-- NTC -- SENSOR_GND
- |
- attenuator / local filter --> ADC
-```
+
The attenuator and ADC protection are required even if a normal temperature
range appears below 3.3 V: an open thermistor raises the node to `+5V_SENS`.
diff --git a/Architecture/IO_MODULES/DEAD_MAN.md b/Architecture/IO_MODULES/DEAD_MAN.md
index da2dd1b..ff3789f 100644
--- a/Architecture/IO_MODULES/DEAD_MAN.md
+++ b/Architecture/IO_MODULES/DEAD_MAN.md
@@ -48,22 +48,11 @@ not the safety-critical shutoff path.
The permission gates operate from `+5V_MAIN` and accept 3.3 V MCU logic
levels. Their outputs are 5 V logic levels.
-```text
-protected 5 V --> independent NO contact A --> protected A input
- +--> 3.3 V --> DEADMAN_A_STATUS --> MCU
- `--> 5 V --> DEADMAN_A_HELD -----+
- |
-protected 5 V --> independent NO contact B --> protected B input +--> AND --> DEADMAN_OK --+
- +--> 3.3 V --> DEADMAN_B_STATUS --> MCU ^ |
- `--> inverter --> DEADMAN_B_RELEASED -- NOT-+ |
- |
-MCU_RUN_PERMIT ---------------------------------------------------------------------------------------------AND --> ENGINE_PERMIT --+
- |
- ignition-permission inverter
- --> SAFE_IGNITION_INHIBIT
+
-MCU_INJECTOR_SIG -------------------------------------------------------------------------------------------AND --> SAFE_INJECTOR_SIG
-```
+
+
+
The logic equations are:
diff --git a/Architecture/IO_MODULES/DIGITAL_INPUTS.md b/Architecture/IO_MODULES/DIGITAL_INPUTS.md
index 2dd7daf..02e1fb5 100644
--- a/Architecture/IO_MODULES/DIGITAL_INPUTS.md
+++ b/Architecture/IO_MODULES/DIGITAL_INPUTS.md
@@ -113,9 +113,6 @@ The comparator's 40 V fail-safe input capability eliminates power-backfeed
through the comparator; it does not replace harness fault protection. Every
channel shall include the following protection functions:
-The right-hand side of the figure above shows the required functional
-protection arrangement.
-
- **Primary positive clamp:** use a connector-side TVS or equivalent
protection element. Its working standoff shall exceed the 16.8 V maximum
normal battery input. Its worst-case dynamic clamp voltage, including
diff --git a/Architecture/IO_MODULES/DIGITAL_OUTPUTS.md b/Architecture/IO_MODULES/DIGITAL_OUTPUTS.md
index 3266651..6a3e18e 100644
--- a/Architecture/IO_MODULES/DIGITAL_OUTPUTS.md
+++ b/Architecture/IO_MODULES/DIGITAL_OUTPUTS.md
@@ -22,15 +22,7 @@ may use either class only when the external starter interface accepts it.
Use the automotive-qualified TI `TPS4H000-Q1` quad smart high-side switch.
It is supplied from `+5V_AUX`, not directly from `+5V_MAIN`.
-```text
-+5V_MAIN --> +5V_AUX eFuse / load switch --> TPS4H000-Q1 VBB
- |
-MCU GPIO --> TPS4H000-Q1 INx OUTx --> LOGIC_OUTx --> connector
- | |
- R_IN_PD R_OUT_PD
- | |
- GND GND
-```
+
- `+5V_AUX` isolates an external logic-output fault from `+5V_MAIN`, the MCU,
and the sensor-excitation rail.
@@ -67,28 +59,11 @@ fault and transient specification before schematic freeze.
Use the automotive-qualified Infineon `TLE9104SH` smart quad low-side switch.
It drives battery-domain loads supplied from `VBAT_PROT`.
-```text
-VBAT_PROT --> external load --> SINK_OUTx --> TLE9104SH OUTx
- |
- internal low-side MOSFET
- |
- OUT_PGND --> power-entry ground star
+
-VBAT_PROT --> TLE9104SH VS +5V_MAIN --> TLE9104SH VDD
- +3V3_MAIN --> TLE9104SH VIO
+
-MCU GPIO --> TLE9104SH INx MCU SPI <--> TLE9104SH SPI
- | |
- R_IN_PD diagnostics
- |
- TLE9104SH local ground reference
-
-MCU enable --> TLE9104SH EN
- |
- R_EN_PD
- |
- TLE9104SH local ground reference
-```
+
- The TLE9104SH supplies active inductive-load clamping, configurable
overcurrent protection, short-circuit and thermal protection, direct channel
diff --git a/Architecture/IO_MODULES/ENGINE_POSITION_INPUTS.md b/Architecture/IO_MODULES/ENGINE_POSITION_INPUTS.md
index 6b9578e..08e5e82 100644
--- a/Architecture/IO_MODULES/ENGINE_POSITION_INPUTS.md
+++ b/Architecture/IO_MODULES/ENGINE_POSITION_INPUTS.md
@@ -39,18 +39,7 @@ freezing `R_PULLUP`. The crank-sensor part number remains to be selected.
## Electrical interface
-```text
- ECU
- +12V_SENS ------------------------+--------------------------> sensor supply
- SENSOR_GND ---------------------------------------------------> sensor return
- |
- +12V_SENS -- R_PULLUP -- TRIG_x ---+-- connector -- sensor output
- |
- +-- connector-side transient protection
- +-- R_DIV_TOP --+-- Schmitt buffer --> 3.3 V timer input
- +-- R_DIV_BOTTOM -- SENSOR_GND
- +-- C_FILTER ------ SENSOR_GND
-```
+
- Supply the sensor from `+12V_SENS`; its rail generation, protection, current
limit, and diagnostics belong to `POWER_ARCHITECTURE.md`.
diff --git a/Architecture/IO_MODULES/IGNITION.md b/Architecture/IO_MODULES/IGNITION.md
index d5b4974..c110740 100644
--- a/Architecture/IO_MODULES/IGNITION.md
+++ b/Architecture/IO_MODULES/IGNITION.md
@@ -14,13 +14,7 @@ confirmed.
## Power path
-```text
-VBAT_PROT --> coil primary --> VBG08H HVC
- |
- internal IGBT
- |
- PGND1 + PGND2 --> IGN_PGND --> power-entry ground
-```
+
- `HVC` connects to one coil-primary terminal; the other terminal connects to
`VBAT_PROT`.
@@ -37,23 +31,7 @@ VBAT_PROT --> coil primary --> VBG08H HVC
`INP` is active high: a rising edge begins coil dwell and a falling edge
causes the normal spark event.
-```text
-STM32 ignition timing output
- --> 3.3 V-to-5 V non-inverting buffer --> 1 kOhm --> INP
- |
- low-capacitance
- Zener clamp
- |
- VBG local Kelvin-ground reference
-
-SAFE_IGNITION_INHIBIT
- --> 1 kOhm --> EN
- |
- low-capacitance
- Zener clamp
- |
- VBG local Kelvin-ground reference
-```
+
The VBG08H-E input-high requirement is 3 V. A 5 V buffer is used rather than
direct STM32 drive to preserve high-level margin across MCU output tolerance,
@@ -91,9 +69,7 @@ and must not create a path that can pull `EN` low during a fault.
internal threshold and releases when the current reaches the nominal 6.5 A
threshold. The threshold is not externally programmable.
-```text
-VBG08H C.F. --> reference-style R/C filter and 3.3 V pull-up --> STM32 GPIO
-```
+
The pull-up voltage must not exceed 5.5 V; `+3V3_MAIN` is suitable. The signal
is a diagnostic confirmation of primary-current buildup and is not part of the
@@ -105,13 +81,7 @@ maximum dwell time.
Define `IGN_PGND` as the ignition module's high-current return domain.
-```text
-PGND1 -- matched heavy copper --+
- +--> IGN_PGND local joining point --> power-entry ground
-PGND2 -- matched heavy copper --+
- |
-VBG08H GND -- short, separate Kelvin reference trace --+
-```
+
- `PGND1` and `PGND2` must use equal-length, equal-width, and similarly
shaped copper paths to the `IGN_PGND` joining point. The VBG08H-E uses these
diff --git a/Architecture/IO_MODULES/INJECTON.md b/Architecture/IO_MODULES/INJECTON.md
index 787d318..91824f6 100644
--- a/Architecture/IO_MODULES/INJECTON.md
+++ b/Architecture/IO_MODULES/INJECTON.md
@@ -13,13 +13,7 @@ low-impedance injector requires a different architecture.
## Power path
-```text
-VBAT_PROT --> injector positive terminal --> injector coil --> VNL5050 DRAIN
- |
- internal low-side MOSFET
- |
- SOURCE --> INJ_PGND --> power-entry ground
-```
+
- The injector's positive terminal connects to `VBAT_PROT`; its negative
terminal connects to `DRAIN`.
@@ -37,12 +31,7 @@ VBAT_PROT --> injector positive terminal --> injector coil --> VNL5050 DRAIN
`INPUT` is active high. It receives only the hardware-permitted injector
command defined by the two-channel deadman interlock.
-```text
-SAFE_INJECTOR_SIG --> 1 kOhm Rprot --> INPUT
- |-- 10 kOhm ---------> INJ_PGND
- `-- low-capacitance
- Zener clamp ------> INJ_PGND
-```
+
```text
SAFE_INJECTOR_SIG = ENGINE_PERMIT AND MCU_INJECTOR_SIG
@@ -70,9 +59,7 @@ status inputs disagree.
`STATUS` is an open-drain diagnostic output. It is read by the MCU through a
1 kOhm protection resistor and a `+3V3_MAIN` pull-up.
-```text
-+3V3_MAIN pull-up --> MCU-side status node --> 1 kOhm Rprot --> STATUS
-```
+
The 3.3 V pull-up is within the pin rating and provides a safe MCU logic level.
The diagnostic path supports off-state open-load detection and indicates
@@ -84,9 +71,7 @@ separate, unambiguous MCU-readable short-circuit/current-limit indication.
Define `INJ_PGND` as the injector module's high-current return domain.
-```text
-VNL5050 SOURCE --> short, low-impedance INJ_PGND copper --> power-entry ground star
-```
+
- `INJ_PGND` runs directly to the power-entry ground star, where it joins the
battery return, `IGN_PGND`, `DGND`, and sensor return domains.
diff --git a/Architecture/POWER_ARCHITECTURE.md b/Architecture/POWER_ARCHITECTURE.md
index 93cbc0b..44b14cf 100644
--- a/Architecture/POWER_ARCHITECTURE.md
+++ b/Architecture/POWER_ARCHITECTURE.md
@@ -25,39 +25,9 @@ part numbers remain to be selected after the loads and packaging are confirmed.
## Rail Tree
-```text
-4S LiPo
- |
- +-- input fuse, reverse-polarity protection, TVS/transient protection
- |
- +-- VBAT_PROT ---------------------------------> ignition branch
- | injector branch
- | protected low-side outputs
- | protected VBAT sense
- |
- +-- synchronous buck --------------------------> +5V_MAIN
- | | internal 5 V circuitry
- | |
- | +-- eFuse / load switch ------------------> +5V_AUX
- | | external logic-level outputs
- | |
- | +-- eFuse / load switch, ferrite/filter --> +5V_SENS
- | protected sensor supply
- |
- +-- synchronous buck --------------------------> +3V3_MAIN
- | | MCU digital supplies
- | | 3.3 V logic / communications
- | |
- | +-- ferrite bead / filtering -------------> +5V_AUX
- | MCU analogue domain
- | analogue front ends
- | ADC reference
- |
- +-- regulated buck-boost ----------------------> +12V_SENS
- 12 V sensor supply
- crank/cam Hall sensors
+
-```
+
## Input and Raw-Battery Domain
@@ -148,13 +118,7 @@ to track `+5V_SENS`. Therefore 5 V ratiometric sensor readings are made
ratiometric in measurement and firmware rather than by requiring a fixed
relationship between the rails.
-```text
-+5V_SENS ----> sensor excitation
- |
- +--> sensor output -- matched divider --> ADC sensor channel
- |
- +--> +5V_SENS sense - matched divider --> ADC 5-V-sense channel
-```
+
Firmware shall calculate the sensor signal as a ratio of the two ADC readings:
@@ -186,13 +150,7 @@ conventional automotive ECU sensor interface. The thermistor itself is passive
and would operate with a 3.3 V excitation, but using the protected 5 V sensor
rail gives a common, diagnosable excitation supply for external sensors.
-```text
-+5V_SENS -- precision pull-up --+-- thermistor -- sensor ground
- |
- +-- matched divider/filter --> ADC thermistor channel
-
-+5V_SENS ------ matched divider/filter -----------------> ADC 5-V-sense channel
-```
+
Firmware shall use the ratio of the thermistor-channel and 5-V-sense ADC
readings to calculate the thermistor resistance. This cancels variation in
diff --git a/Architecture/README.md b/Architecture/README.md
index 29c792a..b001418 100644
--- a/Architecture/README.md
+++ b/Architecture/README.md
@@ -143,3 +143,8 @@ selection are finalised:
requirements.
5. CAN connector and bus topology.
6. Detailed trigger sensor wiring, connector, and cable-length information.
+
+## Diagram sources
+
+The architecture figures are embedded as SVGs. Editable sources, PNG previews,
+and regeneration instructions are in [diagrams/](diagrams/README.md).
diff --git a/Architecture/diagrams/README.md b/Architecture/diagrams/README.md
new file mode 100644
index 0000000..51ae236
--- /dev/null
+++ b/Architecture/diagrams/README.md
@@ -0,0 +1,79 @@
+# Architecture diagram sources
+
+The architecture Markdown embeds these 22 SVG figures. Matching PNG previews
+are provided for viewers that do not support SVG. Diagrams describe the working
+architecture; component qualification and schematic-release requirements remain
+in the parent documents.
+
+## Figures
+
+| Topic | Figures |
+| --- | --- |
+| Power | [Sources](power-sources.svg), [protected branches](power-branches.svg) |
+| Analogue acquisition | [Passive input](analog-input.svg), [thermistor](thermistor.svg), [ratiometric acquisition](ratiometric.svg) |
+| Timing inputs | [Crank/cam interface](trigger-input.svg) |
+| Deadman | [Contacts and diagnostics](deadman-inputs.svg), [permit gates](deadman-permit.svg), [output gates](deadman-outputs.svg) |
+| Ignition | [Power](ignition-power.svg), [commands](ignition-command.svg), [current flag](ignition-flag.svg), [grounding](ignition-ground.svg) |
+| Injection | [Power](injector-power.svg), [command](injector-command.svg), [status](injector-status.svg), [grounding](injector-ground.svg) |
+| Generic outputs | [5 V logic](logic-output.svg), [low-side power](sink-power.svg), [supplies and SPI](sink-interfaces.svg), [command bias](sink-command.svg) |
+| Optional DAC | [Output provision](dac-output.svg) |
+
+## Editing and regeneration
+
+- The 12 block figures have editable `.drawio` sources. Open them in draw.io.
+ `build_blocks.py` recreates their baseline layout and `block-connections.json`.
+ Running it overwrites manual layout edits, so update the generator when those
+ edits should be reproducible, or export the edited `.drawio` directly.
+- The 10 circuit/logic figures are generated by `build_circuits.py`, with a
+ separate `*.topology.json` connection manifest for each figure. Change the
+ relevant component/net definitions and layout together in that script;
+ rerunning it overwrites the generated topology and images. JSON is a review
+ manifest, not an independently interpreted rendering input.
+- Reference designators introduced by these drawings are documentation labels,
+ not KiCad assignments. Named continuation ports are electrically identical
+ only when their names match within the documented domain.
+
+Run from this directory using the configured schematic environment:
+
+```bash
+python build_blocks.py
+~/.venvs/codex-schematics/bin/python export_blocks.py
+~/.venvs/codex-schematics/bin/python build_circuits.py
+```
+
+`export_blocks.py` requires the installed draw.io desktop renderer; restricted
+Electron sandboxes may require an authorized external execution. It exports
+only `.drawio` inputs, keeps editable sources, checks for native SVG text, and
+creates PNG previews. The circuit builder uses Schemdraw and CairoSVG.
+Inspect changed figures at their intended embedded size after rebuilding.
+
+Validate each circuit manifest with the installed topology validator:
+
+```bash
+~/.venvs/codex-schematics/bin/python \
+ ~/.codex/skills/electronics-schematic-rendering/scripts/validate_topology.py \
+ analog-input.topology.json
+```
+
+## Source clarifications in this redraw
+
+- The former power-tree branch labelled `+5V_AUX` after 3.3 V filtering is now
+ `+3V3_ANA`, matching the dedicated rail description. `+5V_AUX` remains a
+ protected branch of `+5V_MAIN`.
+- The passive ADC drawing now shows `C_HOLD` as a shunt capacitor after the
+ small isolation resistor specified in the prose. It does not add a separate
+ connector-side `R_PROT`. Exact values remain unspecified.
+- The Hall-input drawing separates sensor supply, sensor return and signal;
+ the original ASCII alignment could suggest an unintended join. The pull-up,
+ divider and parallel filter follow the existing prose.
+- The deadman equations are unchanged. Contact observations, permission gates
+ and output gates occupy separate figures; shared net names connect them.
+- `VBG_LOCAL_KELVIN` labels the documented local ignition reference at the
+ `IGN_PGND` joining point. `LOCAL_GND` in the sink-command figure denotes the
+ TLE9104SH local ground reference. Neither denotes a new remote ground path.
+- The obsolete reference to a missing figure in `DIGITAL_INPUTS.md` was removed.
+ That module remains described by its existing component-level prose.
+
+Protection blocks whose devices or ratings remain unselected are deliberately
+functional. Supply-loss behavior, real pin mappings, ratings and physical fault
+responses still require the validation specified in the module documents.
diff --git a/Architecture/diagrams/analog-input.png b/Architecture/diagrams/analog-input.png
new file mode 100644
index 0000000..816060a
Binary files /dev/null and b/Architecture/diagrams/analog-input.png differ
diff --git a/Architecture/diagrams/analog-input.svg b/Architecture/diagrams/analog-input.svg
new file mode 100644
index 0000000..423d772
--- /dev/null
+++ b/Architecture/diagrams/analog-input.svg
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/Architecture/diagrams/analog-input.topology.json b/Architecture/diagrams/analog-input.topology.json
new file mode 100644
index 0000000..bbd7992
--- /dev/null
+++ b/Architecture/diagrams/analog-input.topology.json
@@ -0,0 +1,130 @@
+{
+ "title": "Passive 0\u20135 V ADC channel",
+ "source": "IO_MODULES/ANALOG_INPUTS.md: General 0--5 V channels",
+ "reference_scope": "documentation only",
+ "components": [
+ {
+ "ref": "J",
+ "kind": "port",
+ "pins": [
+ "P"
+ ],
+ "value": "Sensor signal"
+ },
+ {
+ "ref": "CLAMP",
+ "kind": "transient-protection",
+ "pins": [
+ "SIG",
+ "RET"
+ ],
+ "value": "Connector clamp\nPart / rating TBD"
+ },
+ {
+ "ref": "GC",
+ "kind": "ground-port",
+ "pins": [
+ "P"
+ ],
+ "value": "SENSOR_GND"
+ },
+ {
+ "ref": "R_TOP",
+ "kind": "resistor",
+ "pins": [
+ "1",
+ "2"
+ ],
+ "value": "R_TOP"
+ },
+ {
+ "ref": "R_BOTTOM",
+ "kind": "resistor",
+ "pins": [
+ "1",
+ "2"
+ ],
+ "value": "R_BOTTOM"
+ },
+ {
+ "ref": "GR",
+ "kind": "ground-port",
+ "pins": [
+ "P"
+ ],
+ "value": "SENSOR_GND"
+ },
+ {
+ "ref": "R_ISO",
+ "kind": "resistor",
+ "pins": [
+ "1",
+ "2"
+ ],
+ "value": "Isolation R\nValue TBD"
+ },
+ {
+ "ref": "C_HOLD",
+ "kind": "capacitor",
+ "pins": [
+ "1",
+ "2"
+ ],
+ "value": "C_HOLD"
+ },
+ {
+ "ref": "GH",
+ "kind": "ground-port",
+ "pins": [
+ "P"
+ ],
+ "value": "SENSOR_GND"
+ },
+ {
+ "ref": "ADC",
+ "kind": "port",
+ "pins": [
+ "P"
+ ],
+ "value": "ADC_IN"
+ }
+ ],
+ "nets": [
+ {
+ "name": "Sensor signal",
+ "connections": [
+ "J.P",
+ "CLAMP.SIG",
+ "R_TOP.1"
+ ]
+ },
+ {
+ "name": "SENSOR_GND",
+ "connections": [
+ "CLAMP.RET",
+ "GC.P",
+ "R_BOTTOM.2",
+ "GR.P",
+ "C_HOLD.2",
+ "GH.P"
+ ]
+ },
+ {
+ "name": "DIVIDED",
+ "connections": [
+ "R_TOP.2",
+ "R_BOTTOM.1",
+ "R_ISO.1"
+ ]
+ },
+ {
+ "name": "ADC_IN",
+ "connections": [
+ "R_ISO.2",
+ "C_HOLD.1",
+ "ADC.P"
+ ]
+ }
+ ],
+ "no_connects": []
+}
diff --git a/Architecture/diagrams/block-connections.json b/Architecture/diagrams/block-connections.json
new file mode 100644
index 0000000..4a50c03
--- /dev/null
+++ b/Architecture/diagrams/block-connections.json
@@ -0,0 +1,1484 @@
+{
+ "power-sources": {
+ "title": "Power sources and battery loads",
+ "source": "POWER_ARCHITECTURE.md: Rail Tree",
+ "nodes": {
+ "title": {
+ "label": "Power sources and battery loads",
+ "kind": "note",
+ "bounds": [
+ 30,
+ 18,
+ 980,
+ 42
+ ]
+ },
+ "battery": {
+ "label": "4S LiPo\n14.8 V nominal \u00b7 16.8 V full",
+ "kind": "power",
+ "bounds": [
+ 30,
+ 90,
+ 290,
+ 80
+ ]
+ },
+ "protection": {
+ "label": "Input fuse \u00b7 reverse protection\nTVS / transient protection",
+ "kind": "power",
+ "bounds": [
+ 390,
+ 90,
+ 310,
+ 80
+ ]
+ },
+ "vbat": {
+ "label": "VBAT_PROT",
+ "kind": "power",
+ "bounds": [
+ 770,
+ 90,
+ 230,
+ 80
+ ]
+ },
+ "loadsin": {
+ "label": "VBAT_PROT",
+ "kind": "power",
+ "bounds": [
+ 30,
+ 245,
+ 190,
+ 74
+ ]
+ },
+ "loads": {
+ "label": "Protected battery branches",
+ "kind": "power",
+ "bounds": [
+ 300,
+ 245,
+ 310,
+ 74
+ ]
+ },
+ "loadsout": {
+ "label": "Ignition \u00b7 injector\nLow-side outputs \u00b7 VBAT sense",
+ "kind": "power",
+ "bounds": [
+ 690,
+ 245,
+ 310,
+ 74
+ ]
+ },
+ "fivein": {
+ "label": "VBAT_PROT",
+ "kind": "power",
+ "bounds": [
+ 30,
+ 365,
+ 190,
+ 74
+ ]
+ },
+ "five": {
+ "label": "Synchronous buck \u00b7 5 V",
+ "kind": "power",
+ "bounds": [
+ 300,
+ 365,
+ 310,
+ 74
+ ]
+ },
+ "fiveout": {
+ "label": "+5V_MAIN\nInternal 5 V circuitry",
+ "kind": "power",
+ "bounds": [
+ 690,
+ 365,
+ 310,
+ 74
+ ]
+ },
+ "threein": {
+ "label": "VBAT_PROT",
+ "kind": "power",
+ "bounds": [
+ 30,
+ 485,
+ 190,
+ 74
+ ]
+ },
+ "three": {
+ "label": "Synchronous buck \u00b7 3.3 V",
+ "kind": "power",
+ "bounds": [
+ 300,
+ 485,
+ 310,
+ 74
+ ]
+ },
+ "threeout": {
+ "label": "+3V3_MAIN\nMCU / digital / communications",
+ "kind": "power",
+ "bounds": [
+ 690,
+ 485,
+ 310,
+ 74
+ ]
+ },
+ "twelvein": {
+ "label": "VBAT_PROT",
+ "kind": "power",
+ "bounds": [
+ 30,
+ 605,
+ 190,
+ 74
+ ]
+ },
+ "twelve": {
+ "label": "Regulated buck-boost \u00b7 12 V",
+ "kind": "power",
+ "bounds": [
+ 300,
+ 605,
+ 310,
+ 74
+ ]
+ },
+ "twelveout": {
+ "label": "+12V_SENS\nProtected Hall-sensor supply",
+ "kind": "power",
+ "bounds": [
+ 690,
+ 605,
+ 310,
+ 74
+ ]
+ },
+ "note725": {
+ "label": "Repeated VBAT_PROT labels denote the same rail. Protected branch details are shown separately.",
+ "kind": "note",
+ "bounds": [
+ 30,
+ 725,
+ 980,
+ 60
+ ]
+ }
+ },
+ "connections": [
+ {
+ "from": "battery",
+ "to": "protection",
+ "label": "",
+ "kind": "power"
+ },
+ {
+ "from": "protection",
+ "to": "vbat",
+ "label": "",
+ "kind": "power"
+ },
+ {
+ "from": "loadsin",
+ "to": "loads",
+ "label": "",
+ "kind": "power"
+ },
+ {
+ "from": "loads",
+ "to": "loadsout",
+ "label": "",
+ "kind": "power"
+ },
+ {
+ "from": "fivein",
+ "to": "five",
+ "label": "",
+ "kind": "power"
+ },
+ {
+ "from": "five",
+ "to": "fiveout",
+ "label": "",
+ "kind": "power"
+ },
+ {
+ "from": "threein",
+ "to": "three",
+ "label": "",
+ "kind": "power"
+ },
+ {
+ "from": "three",
+ "to": "threeout",
+ "label": "",
+ "kind": "power"
+ },
+ {
+ "from": "twelvein",
+ "to": "twelve",
+ "label": "",
+ "kind": "power"
+ },
+ {
+ "from": "twelve",
+ "to": "twelveout",
+ "label": "",
+ "kind": "power"
+ }
+ ]
+ },
+ "power-branches": {
+ "title": "Protected and filtered rail branches",
+ "source": "POWER_ARCHITECTURE.md: rail descriptions",
+ "nodes": {
+ "title": {
+ "label": "Protected and filtered rail branches",
+ "kind": "note",
+ "bounds": [
+ 30,
+ 18,
+ 980,
+ 42
+ ]
+ },
+ "a0": {
+ "label": "+5V_MAIN",
+ "kind": "power",
+ "bounds": [
+ 30,
+ 95,
+ 240,
+ 90
+ ]
+ },
+ "b0": {
+ "label": "eFuse / protected load switch",
+ "kind": "power",
+ "bounds": [
+ 340,
+ 95,
+ 320,
+ 90
+ ]
+ },
+ "c0": {
+ "label": "+5V_AUX\nExternal logic outputs",
+ "kind": "power",
+ "bounds": [
+ 730,
+ 95,
+ 280,
+ 90
+ ]
+ },
+ "a1": {
+ "label": "+5V_MAIN",
+ "kind": "power",
+ "bounds": [
+ 30,
+ 230,
+ 240,
+ 90
+ ]
+ },
+ "b1": {
+ "label": "eFuse / load switch\nFerrite bead + local filter",
+ "kind": "power",
+ "bounds": [
+ 340,
+ 230,
+ 320,
+ 90
+ ]
+ },
+ "c1": {
+ "label": "+5V_SENS\n5 V sensor excitation",
+ "kind": "power",
+ "bounds": [
+ 730,
+ 230,
+ 280,
+ 90
+ ]
+ },
+ "a2": {
+ "label": "+3V3_MAIN",
+ "kind": "power",
+ "bounds": [
+ 30,
+ 365,
+ 240,
+ 90
+ ]
+ },
+ "b2": {
+ "label": "Ferrite bead + local filter",
+ "kind": "power",
+ "bounds": [
+ 340,
+ 365,
+ 320,
+ 90
+ ]
+ },
+ "c2": {
+ "label": "+3V3_ANA\nAnalogue supplies /\nADC reference",
+ "kind": "power",
+ "bounds": [
+ 730,
+ 365,
+ 280,
+ 90
+ ]
+ },
+ "a3": {
+ "label": "12 V buck-boost output",
+ "kind": "power",
+ "bounds": [
+ 30,
+ 500,
+ 240,
+ 90
+ ]
+ },
+ "b3": {
+ "label": "Current limit / protected switch\nHarness filter + decoupling",
+ "kind": "power",
+ "bounds": [
+ 340,
+ 500,
+ 320,
+ 90
+ ]
+ },
+ "c3": {
+ "label": "+12V_SENS\nCrank / cam Hall sensors",
+ "kind": "power",
+ "bounds": [
+ 730,
+ 500,
+ 280,
+ 90
+ ]
+ },
+ "note630": {
+ "label": "Optional analogue LDO and final current limits remain validation items; see the rail descriptions.",
+ "kind": "note",
+ "bounds": [
+ 30,
+ 630,
+ 980,
+ 60
+ ]
+ }
+ },
+ "connections": [
+ {
+ "from": "a0",
+ "to": "b0",
+ "label": "",
+ "kind": "power"
+ },
+ {
+ "from": "b0",
+ "to": "c0",
+ "label": "",
+ "kind": "power"
+ },
+ {
+ "from": "a1",
+ "to": "b1",
+ "label": "",
+ "kind": "power"
+ },
+ {
+ "from": "b1",
+ "to": "c1",
+ "label": "",
+ "kind": "power"
+ },
+ {
+ "from": "a2",
+ "to": "b2",
+ "label": "",
+ "kind": "power"
+ },
+ {
+ "from": "b2",
+ "to": "c2",
+ "label": "",
+ "kind": "power"
+ },
+ {
+ "from": "a3",
+ "to": "b3",
+ "label": "",
+ "kind": "power"
+ },
+ {
+ "from": "b3",
+ "to": "c3",
+ "label": "",
+ "kind": "power"
+ }
+ ]
+ },
+ "ratiometric": {
+ "title": "Ratiometric sensor acquisition",
+ "source": "POWER_ARCHITECTURE.md: Ratiometric 5 V Sensor Measurements",
+ "nodes": {
+ "title": {
+ "label": "Ratiometric sensor acquisition",
+ "kind": "note",
+ "bounds": [
+ 30,
+ 18,
+ 980,
+ 42
+ ]
+ },
+ "rail": {
+ "label": "+5V_SENS",
+ "kind": "power",
+ "bounds": [
+ 30,
+ 90,
+ 220,
+ 74
+ ]
+ },
+ "sensor": {
+ "label": "5 V sensor\nExcitation input",
+ "kind": "device",
+ "bounds": [
+ 340,
+ 90,
+ 280,
+ 74
+ ]
+ },
+ "sig": {
+ "label": "Sensor output",
+ "kind": "signal",
+ "bounds": [
+ 30,
+ 240,
+ 220,
+ 74
+ ]
+ },
+ "div": {
+ "label": "Matched divider / filter",
+ "kind": "signal",
+ "bounds": [
+ 340,
+ 240,
+ 280,
+ 74
+ ]
+ },
+ "adc": {
+ "label": "ADC sensor channel",
+ "kind": "signal",
+ "bounds": [
+ 730,
+ 240,
+ 280,
+ 74
+ ]
+ },
+ "rail2": {
+ "label": "+5V_SENS",
+ "kind": "power",
+ "bounds": [
+ 30,
+ 380,
+ 220,
+ 74
+ ]
+ },
+ "sense": {
+ "label": "Matched divider / filter",
+ "kind": "signal",
+ "bounds": [
+ 340,
+ 380,
+ 280,
+ 74
+ ]
+ },
+ "adc2": {
+ "label": "ADC 5-V-sense channel",
+ "kind": "signal",
+ "bounds": [
+ 730,
+ 380,
+ 280,
+ 74
+ ]
+ },
+ "note470": {
+ "label": "Sensor output is the sensor\u2019s signal pin. Both ADC channels use +3V3_ANA as their reference.",
+ "kind": "note",
+ "bounds": [
+ 30,
+ 470,
+ 980,
+ 60
+ ]
+ }
+ },
+ "connections": [
+ {
+ "from": "rail",
+ "to": "sensor",
+ "label": "",
+ "kind": "power"
+ },
+ {
+ "from": "sig",
+ "to": "div",
+ "label": "",
+ "kind": "signal"
+ },
+ {
+ "from": "div",
+ "to": "adc",
+ "label": "",
+ "kind": "signal"
+ },
+ {
+ "from": "rail2",
+ "to": "sense",
+ "label": "",
+ "kind": "signal"
+ },
+ {
+ "from": "sense",
+ "to": "adc2",
+ "label": "",
+ "kind": "signal"
+ }
+ ]
+ },
+ "dac-output": {
+ "title": "Optional analogue-output provision",
+ "source": "IO_ARCHITECTURE.md: Analogue-output provision",
+ "nodes": {
+ "title": {
+ "label": "Optional analogue-output provision",
+ "kind": "note",
+ "bounds": [
+ 30,
+ 18,
+ 980,
+ 42
+ ]
+ },
+ "0": {
+ "label": "MCU DAC",
+ "kind": "signal",
+ "bounds": [
+ 40.0,
+ 95,
+ 210.0,
+ 85
+ ]
+ },
+ "1": {
+ "label": "Rail-to-rail buffer",
+ "kind": "signal",
+ "bounds": [
+ 290.0,
+ 95,
+ 210.0,
+ 85
+ ]
+ },
+ "2": {
+ "label": "Protection /\nseries impedance",
+ "kind": "signal",
+ "bounds": [
+ 540.0,
+ 95,
+ 210.0,
+ 85
+ ]
+ },
+ "3": {
+ "label": "Connector",
+ "kind": "signal",
+ "bounds": [
+ 790.0,
+ 95,
+ 210.0,
+ 85
+ ]
+ },
+ "note195": {
+ "label": "Provision only; final electrical range, load and protection remain to be defined.",
+ "kind": "note",
+ "bounds": [
+ 30,
+ 195,
+ 980,
+ 60
+ ]
+ }
+ },
+ "connections": [
+ {
+ "from": "0",
+ "to": "1",
+ "label": "",
+ "kind": "signal"
+ },
+ {
+ "from": "1",
+ "to": "2",
+ "label": "",
+ "kind": "signal"
+ },
+ {
+ "from": "2",
+ "to": "3",
+ "label": "",
+ "kind": "signal"
+ }
+ ]
+ },
+ "deadman-inputs": {
+ "title": "Deadman contacts and observations",
+ "source": "IO_MODULES/DEAD_MAN.md: Logic domains",
+ "nodes": {
+ "title": {
+ "label": "Deadman contacts and observations",
+ "kind": "note",
+ "bounds": [
+ 30,
+ 18,
+ 980,
+ 42
+ ]
+ },
+ "As": {
+ "label": "Protected 5 V\nIndependent NO contact A",
+ "kind": "power",
+ "bounds": [
+ 30,
+ 100,
+ 260,
+ 80
+ ]
+ },
+ "Ap": {
+ "label": "Protected input A\nOwn filter + default-low bias",
+ "kind": "signal",
+ "bounds": [
+ 370,
+ 100,
+ 290,
+ 80
+ ]
+ },
+ "Ah": {
+ "label": "DEADMAN_A_HELD\n5 V \u00b7 non-inverting",
+ "kind": "signal",
+ "bounds": [
+ 750,
+ 100,
+ 260,
+ 80
+ ]
+ },
+ "Ad": {
+ "label": "DEADMAN_A_STATUS\n3.3 V \u00b7 held = high \u2192 MCU",
+ "kind": "device",
+ "bounds": [
+ 370,
+ 220,
+ 330,
+ 75
+ ]
+ },
+ "Bs": {
+ "label": "Protected 5 V\nIndependent NO contact B",
+ "kind": "power",
+ "bounds": [
+ 30,
+ 345,
+ 260,
+ 80
+ ]
+ },
+ "Bp": {
+ "label": "Protected input B\nOwn filter + default-low bias",
+ "kind": "signal",
+ "bounds": [
+ 370,
+ 345,
+ 290,
+ 80
+ ]
+ },
+ "Bh": {
+ "label": "DEADMAN_B_RELEASED\n5 V \u00b7 inverting",
+ "kind": "signal",
+ "bounds": [
+ 750,
+ 345,
+ 260,
+ 80
+ ]
+ },
+ "Bd": {
+ "label": "DEADMAN_B_STATUS\n3.3 V \u00b7 held = high \u2192 MCU",
+ "kind": "device",
+ "bounds": [
+ 370,
+ 465,
+ 330,
+ 75
+ ]
+ },
+ "note575": {
+ "label": "Separate harness paths. MCU status observations are diagnostic; the 5 V signals feed the permit gates.",
+ "kind": "note",
+ "bounds": [
+ 30,
+ 575,
+ 980,
+ 60
+ ]
+ }
+ },
+ "connections": [
+ {
+ "from": "As",
+ "to": "Ap",
+ "label": "",
+ "kind": "signal"
+ },
+ {
+ "from": "Ap",
+ "to": "Ah",
+ "label": "",
+ "kind": "signal"
+ },
+ {
+ "from": "Ap",
+ "to": "Ad",
+ "label": "",
+ "kind": "signal"
+ },
+ {
+ "from": "Bs",
+ "to": "Bp",
+ "label": "",
+ "kind": "signal"
+ },
+ {
+ "from": "Bp",
+ "to": "Bh",
+ "label": "",
+ "kind": "signal"
+ },
+ {
+ "from": "Bp",
+ "to": "Bd",
+ "label": "",
+ "kind": "signal"
+ }
+ ]
+ },
+ "ignition-power": {
+ "title": "Ignition power path",
+ "source": "IO_MODULES/IGNITION.md: Power path",
+ "nodes": {
+ "title": {
+ "label": "Ignition power path",
+ "kind": "note",
+ "bounds": [
+ 30,
+ 18,
+ 980,
+ 42
+ ]
+ },
+ "rail": {
+ "label": "VBAT_PROT",
+ "kind": "power",
+ "bounds": [
+ 30,
+ 100,
+ 230,
+ 80
+ ]
+ },
+ "load": {
+ "label": "Coil primary",
+ "kind": "device",
+ "bounds": [
+ 350,
+ 100,
+ 280,
+ 80
+ ]
+ },
+ "driver": {
+ "label": "VBG08H-E\nHVC",
+ "kind": "device",
+ "bounds": [
+ 720,
+ 100,
+ 290,
+ 80
+ ]
+ },
+ "switch": {
+ "label": "Internal IGBT",
+ "kind": "device",
+ "bounds": [
+ 720,
+ 230,
+ 290,
+ 70
+ ]
+ },
+ "return": {
+ "label": "PGND1 + PGND2 \u2192 IGN_PGND",
+ "kind": "ground",
+ "bounds": [
+ 350,
+ 350,
+ 660,
+ 60
+ ]
+ },
+ "note410": {
+ "label": "Functional current path. IGN_PGND returns separately to the power-entry ground star.",
+ "kind": "note",
+ "bounds": [
+ 30,
+ 410,
+ 980,
+ 60
+ ]
+ }
+ },
+ "connections": [
+ {
+ "from": "rail",
+ "to": "load",
+ "label": "",
+ "kind": "power"
+ },
+ {
+ "from": "load",
+ "to": "driver",
+ "label": "",
+ "kind": "power"
+ },
+ {
+ "from": "driver",
+ "to": "switch",
+ "label": "",
+ "kind": "power"
+ },
+ {
+ "from": "switch",
+ "to": "return",
+ "label": "",
+ "kind": "power"
+ }
+ ]
+ },
+ "injector-power": {
+ "title": "Injector power path",
+ "source": "IO_MODULES/INJECTON.md: Power path",
+ "nodes": {
+ "title": {
+ "label": "Injector power path",
+ "kind": "note",
+ "bounds": [
+ 30,
+ 18,
+ 980,
+ 42
+ ]
+ },
+ "rail": {
+ "label": "VBAT_PROT",
+ "kind": "power",
+ "bounds": [
+ 30,
+ 100,
+ 230,
+ 80
+ ]
+ },
+ "load": {
+ "label": "Injector coil",
+ "kind": "device",
+ "bounds": [
+ 350,
+ 100,
+ 280,
+ 80
+ ]
+ },
+ "driver": {
+ "label": "VNL5050S5-E\nDRAIN",
+ "kind": "device",
+ "bounds": [
+ 720,
+ 100,
+ 290,
+ 80
+ ]
+ },
+ "switch": {
+ "label": "Internal low-side MOSFET",
+ "kind": "device",
+ "bounds": [
+ 720,
+ 230,
+ 290,
+ 70
+ ]
+ },
+ "return": {
+ "label": "SOURCE \u2192 INJ_PGND",
+ "kind": "ground",
+ "bounds": [
+ 350,
+ 350,
+ 660,
+ 60
+ ]
+ },
+ "note410": {
+ "label": "Functional current path. INJ_PGND returns separately to the power-entry ground star.",
+ "kind": "note",
+ "bounds": [
+ 30,
+ 410,
+ 980,
+ 60
+ ]
+ }
+ },
+ "connections": [
+ {
+ "from": "rail",
+ "to": "load",
+ "label": "",
+ "kind": "power"
+ },
+ {
+ "from": "load",
+ "to": "driver",
+ "label": "",
+ "kind": "power"
+ },
+ {
+ "from": "driver",
+ "to": "switch",
+ "label": "",
+ "kind": "power"
+ },
+ {
+ "from": "switch",
+ "to": "return",
+ "label": "",
+ "kind": "power"
+ }
+ ]
+ },
+ "sink-power": {
+ "title": "Generic low-side power path",
+ "source": "IO_MODULES/DIGITAL_OUTPUTS.md: Power path",
+ "nodes": {
+ "title": {
+ "label": "Generic low-side power path",
+ "kind": "note",
+ "bounds": [
+ 30,
+ 18,
+ 980,
+ 42
+ ]
+ },
+ "rail": {
+ "label": "VBAT_PROT",
+ "kind": "power",
+ "bounds": [
+ 30,
+ 100,
+ 230,
+ 80
+ ]
+ },
+ "load": {
+ "label": "External load\nvia SINK_OUTx",
+ "kind": "device",
+ "bounds": [
+ 350,
+ 100,
+ 280,
+ 80
+ ]
+ },
+ "driver": {
+ "label": "TLE9104SH\nOUTx",
+ "kind": "device",
+ "bounds": [
+ 720,
+ 100,
+ 290,
+ 80
+ ]
+ },
+ "switch": {
+ "label": "Internal low-side MOSFET",
+ "kind": "device",
+ "bounds": [
+ 720,
+ 230,
+ 290,
+ 70
+ ]
+ },
+ "return": {
+ "label": "Power return \u2192 OUT_PGND",
+ "kind": "ground",
+ "bounds": [
+ 350,
+ 350,
+ 660,
+ 60
+ ]
+ },
+ "note410": {
+ "label": "Functional current path. OUT_PGND returns separately to the power-entry ground star.",
+ "kind": "note",
+ "bounds": [
+ 30,
+ 410,
+ 980,
+ 60
+ ]
+ }
+ },
+ "connections": [
+ {
+ "from": "rail",
+ "to": "load",
+ "label": "",
+ "kind": "power"
+ },
+ {
+ "from": "load",
+ "to": "driver",
+ "label": "",
+ "kind": "power"
+ },
+ {
+ "from": "driver",
+ "to": "switch",
+ "label": "",
+ "kind": "power"
+ },
+ {
+ "from": "switch",
+ "to": "return",
+ "label": "",
+ "kind": "power"
+ }
+ ]
+ },
+ "ignition-flag": {
+ "title": "Ignition current-flag diagnostic",
+ "source": "IO_MODULES/IGNITION.md: Current-flag diagnostic",
+ "nodes": {
+ "title": {
+ "label": "Ignition current-flag diagnostic",
+ "kind": "note",
+ "bounds": [
+ 30,
+ 18,
+ 980,
+ 42
+ ]
+ },
+ "0": {
+ "label": "VBG08H-E C.F.\nOpen-drain output",
+ "kind": "signal",
+ "bounds": [
+ 40.0,
+ 95,
+ 293.3333333333333,
+ 85
+ ]
+ },
+ "1": {
+ "label": "Reference-style R/C filter\n+3V3_MAIN pull-up",
+ "kind": "signal",
+ "bounds": [
+ 373.3333333333333,
+ 95,
+ 293.3333333333333,
+ 85
+ ]
+ },
+ "2": {
+ "label": "STM32 GPIO",
+ "kind": "signal",
+ "bounds": [
+ 706.6666666666666,
+ 95,
+ 293.3333333333333,
+ 85
+ ]
+ },
+ "note195": {
+ "label": "Diagnostic current-threshold observation; separate from the hardware inhibit path.",
+ "kind": "note",
+ "bounds": [
+ 30,
+ 195,
+ 980,
+ 60
+ ]
+ }
+ },
+ "connections": [
+ {
+ "from": "0",
+ "to": "1",
+ "label": "",
+ "kind": "signal"
+ },
+ {
+ "from": "1",
+ "to": "2",
+ "label": "",
+ "kind": "signal"
+ }
+ ]
+ },
+ "ignition-ground": {
+ "title": "Ignition ground and Kelvin reference",
+ "source": "IO_MODULES/IGNITION.md: Ground and layout",
+ "nodes": {
+ "title": {
+ "label": "Ignition ground and Kelvin reference",
+ "kind": "note",
+ "bounds": [
+ 30,
+ 18,
+ 980,
+ 42
+ ]
+ },
+ "p1": {
+ "label": "VBG08H-E PGND1",
+ "kind": "ground",
+ "bounds": [
+ 30,
+ 100,
+ 230,
+ 64
+ ]
+ },
+ "p2": {
+ "label": "VBG08H-E PGND2",
+ "kind": "ground",
+ "bounds": [
+ 30,
+ 215,
+ 230,
+ 64
+ ]
+ },
+ "g": {
+ "label": "VBG08H-E GND",
+ "kind": "ground",
+ "bounds": [
+ 30,
+ 330,
+ 230,
+ 64
+ ]
+ },
+ "join": {
+ "label": "IGN_PGND\nLocal joining point",
+ "kind": "ground",
+ "bounds": [
+ 490,
+ 170,
+ 220,
+ 105
+ ]
+ },
+ "star": {
+ "label": "Power-entry\nground star",
+ "kind": "ground",
+ "bounds": [
+ 800,
+ 170,
+ 210,
+ 105
+ ]
+ },
+ "note410": {
+ "label": "GND carries the local reference, not coil current. No separate remote-DGND connection.",
+ "kind": "note",
+ "bounds": [
+ 30,
+ 410,
+ 980,
+ 60
+ ]
+ }
+ },
+ "connections": [
+ {
+ "from": "p1",
+ "to": "join",
+ "label": "Matched heavy copper",
+ "kind": "signal"
+ },
+ {
+ "from": "p2",
+ "to": "join",
+ "label": "Matched heavy copper",
+ "kind": "signal"
+ },
+ {
+ "from": "g",
+ "to": "join",
+ "label": "Separate Kelvin trace",
+ "kind": "signal"
+ },
+ {
+ "from": "join",
+ "to": "star",
+ "label": "",
+ "kind": "signal"
+ }
+ ]
+ },
+ "injector-ground": {
+ "title": "Injector ground return",
+ "source": "IO_MODULES/INJECTON.md: Ground and layout",
+ "nodes": {
+ "title": {
+ "label": "Injector ground return",
+ "kind": "note",
+ "bounds": [
+ 30,
+ 18,
+ 980,
+ 42
+ ]
+ },
+ "0": {
+ "label": "VNL5050S5-E SOURCE",
+ "kind": "ground",
+ "bounds": [
+ 40.0,
+ 95,
+ 293.3333333333333,
+ 85
+ ]
+ },
+ "1": {
+ "label": "INJ_PGND\nShort, low-impedance copper",
+ "kind": "ground",
+ "bounds": [
+ 373.3333333333333,
+ 95,
+ 293.3333333333333,
+ 85
+ ]
+ },
+ "2": {
+ "label": "Power-entry ground star",
+ "kind": "ground",
+ "bounds": [
+ 706.6666666666666,
+ 95,
+ 293.3333333333333,
+ 85
+ ]
+ },
+ "note195": {
+ "label": "SOURCE is both power return and local logic reference. No separate Kelvin pin.",
+ "kind": "note",
+ "bounds": [
+ 30,
+ 195,
+ 980,
+ 60
+ ]
+ }
+ },
+ "connections": [
+ {
+ "from": "0",
+ "to": "1",
+ "label": "",
+ "kind": "ground"
+ },
+ {
+ "from": "1",
+ "to": "2",
+ "label": "",
+ "kind": "ground"
+ }
+ ]
+ },
+ "sink-interfaces": {
+ "title": "Low-side driver supplies and diagnostics",
+ "source": "IO_MODULES/DIGITAL_OUTPUTS.md: Protected low-side outputs",
+ "nodes": {
+ "title": {
+ "label": "Low-side driver supplies and diagnostics",
+ "kind": "note",
+ "bounds": [
+ 30,
+ 18,
+ 980,
+ 42
+ ]
+ },
+ "s0": {
+ "label": "VBAT_PROT",
+ "kind": "power",
+ "bounds": [
+ 30,
+ 95,
+ 230,
+ 70
+ ]
+ },
+ "p0": {
+ "label": "TLE9104SH VS",
+ "kind": "device",
+ "bounds": [
+ 380,
+ 95,
+ 280,
+ 70
+ ]
+ },
+ "s1": {
+ "label": "+5V_MAIN",
+ "kind": "power",
+ "bounds": [
+ 30,
+ 205,
+ 230,
+ 70
+ ]
+ },
+ "p1": {
+ "label": "TLE9104SH VDD",
+ "kind": "device",
+ "bounds": [
+ 380,
+ 205,
+ 280,
+ 70
+ ]
+ },
+ "s2": {
+ "label": "+3V3_MAIN",
+ "kind": "power",
+ "bounds": [
+ 30,
+ 315,
+ 230,
+ 70
+ ]
+ },
+ "p2": {
+ "label": "TLE9104SH VIO",
+ "kind": "device",
+ "bounds": [
+ 380,
+ 315,
+ 280,
+ 70
+ ]
+ },
+ "mcu": {
+ "label": "MCU SPI",
+ "kind": "signal",
+ "bounds": [
+ 30,
+ 440,
+ 230,
+ 80
+ ]
+ },
+ "spi": {
+ "label": "TLE9104SH SPI\nCommands + diagnostics",
+ "kind": "device",
+ "bounds": [
+ 380,
+ 440,
+ 280,
+ 80
+ ]
+ },
+ "note540": {
+ "label": "INx / EN default-low networks are shown in the companion circuit. Decouple supplies locally.",
+ "kind": "note",
+ "bounds": [
+ 30,
+ 540,
+ 980,
+ 60
+ ]
+ }
+ },
+ "connections": [
+ {
+ "from": "s0",
+ "to": "p0",
+ "label": "",
+ "kind": "power"
+ },
+ {
+ "from": "s1",
+ "to": "p1",
+ "label": "",
+ "kind": "power"
+ },
+ {
+ "from": "s2",
+ "to": "p2",
+ "label": "",
+ "kind": "power"
+ },
+ {
+ "from": "mcu",
+ "to": "spi",
+ "label": "",
+ "kind": "signal"
+ }
+ ]
+ }
+}
diff --git a/Architecture/diagrams/build_blocks.py b/Architecture/diagrams/build_blocks.py
new file mode 100644
index 0000000..fe49cb6
--- /dev/null
+++ b/Architecture/diagrams/build_blocks.py
@@ -0,0 +1,144 @@
+"""Rebuild editable architectural figures (standard-library Python).
+
+Export the resulting .drawio files with the installed draw.io desktop renderer.
+Node/edge records are retained as a source-traceable connection manifest.
+"""
+from pathlib import Path
+import json
+import xml.etree.ElementTree as ET
+
+OUT = Path(__file__).resolve().parent
+COLORS = {'power': '#fff1d6', 'signal': '#e8f0fc', 'device': '#e8f4ed',
+ 'ground': '#eef0f3', 'note': '#ffffff'}
+manifest = {}
+
+class Figure:
+ def __init__(self, name, title, source, width=1040, height=620):
+ self.name, self.width, self.height = name, width, height
+ self.data = {'title': title, 'source': source, 'nodes': {}, 'connections': []}
+ self.root = ET.Element('mxfile', host='app.diagrams.net')
+ diagram = ET.SubElement(self.root, 'diagram', name=title, id=name)
+ model = ET.SubElement(diagram, 'mxGraphModel', page='1', pageWidth=str(width), pageHeight=str(height), grid='1', gridSize='10')
+ self.cells = ET.SubElement(model, 'root')
+ ET.SubElement(self.cells, 'mxCell', id='0')
+ ET.SubElement(self.cells, 'mxCell', id='1', parent='0')
+ self.node('title', title, 30, 18, width-60, 42, 'note', text=True, size=26)
+
+ def node(self, key, label, x, y, w=220, h=74, kind='signal', text=False, size=18):
+ style = f'rounded=1;html=0;fontFamily=DejaVu Sans;fontSize={size};fontColor=#172b40;strokeColor=#577086;fillColor={COLORS[kind]};spacing=10;'
+ if text:
+ style += 'strokeColor=none;fillColor=none;align=left;'
+ cell = ET.SubElement(self.cells, 'mxCell', id='node_'+key, value=label, style=style, vertex='1', parent='1')
+ ET.SubElement(cell, 'mxGeometry', x=str(x), y=str(y), width=str(w), height=str(h), **{'as':'geometry'})
+ self.data['nodes'][key] = {'label': label, 'kind':kind, 'bounds':[x,y,w,h]}
+ return key
+
+ def edge(self, a, b, label='', points=(), exit=(1,.5), entry=(0,.5), kind='signal', arrows=True):
+ assert a in self.data['nodes'] and b in self.data['nodes']
+ idx = 'e'+str(len(self.data['connections']))
+ color = '#946221' if kind=='power' else '#416680'
+ bidirectional = label == 'Bidirectional'
+ if bidirectional: label = ''
+ style = f'edgeStyle=orthogonalEdgeStyle;rounded=0;html=0;strokeWidth=2;strokeColor={color};fontSize=16;fontFamily=DejaVu Sans;labelBackgroundColor=#ffffff;endArrow={"block" if arrows else "none"};endFill=1;exitX={exit[0]};exitY={exit[1]};entryX={entry[0]};entryY={entry[1]};'
+ if bidirectional: style += 'startArrow=block;startFill=1;'
+ cell = ET.SubElement(self.cells, 'mxCell', id=idx, source='node_'+a, target='node_'+b, value=label, style=style, edge='1', parent='1')
+ geo = ET.SubElement(cell, 'mxGeometry', relative='1', **{'as':'geometry'})
+ if points:
+ arr = ET.SubElement(geo, 'Array', **{'as':'points'})
+ for x,y in points: ET.SubElement(arr, 'mxPoint', x=str(x), y=str(y))
+ self.data['connections'].append({'from':a,'to':b,'label':label,'kind':kind})
+
+ def note(self, label, y):
+ self.node('note'+str(y), label, 30, y, self.width-60, 60, 'note', text=True, size=16)
+
+ def save(self):
+ ET.indent(self.root)
+ ET.ElementTree(self.root).write(OUT/(self.name+'.drawio'), encoding='utf-8', xml_declaration=True)
+ manifest[self.name] = self.data
+
+def chain(name, title, source, labels, note='', kind='signal'):
+ f = Figure(name,title,source,1040,270)
+ w = (960-(len(labels)-1)*40)/len(labels)
+ for i,label in enumerate(labels):
+ f.node(str(i),label,40+i*(w+40),95,w,85,kind)
+ if i: f.edge(str(i-1),str(i),kind=kind)
+ if note: f.note(note,195)
+ f.save()
+
+f = Figure('power-sources','Power sources and battery loads','POWER_ARCHITECTURE.md: Rail Tree',1040,790)
+f.node('battery','4S LiPo\n14.8 V nominal · 16.8 V full',30,90,290,80,'power')
+f.node('protection','Input fuse · reverse protection\nTVS / transient protection',390,90,310,80,'power')
+f.node('vbat','VBAT_PROT',770,90,230,80,'power')
+f.edge('battery','protection',kind='power'); f.edge('protection','vbat',kind='power')
+for i,(key,label,out) in enumerate([
+ ('loads','Protected battery branches','Ignition · injector\nLow-side outputs · VBAT sense'),
+ ('five','Synchronous buck · 5 V','+5V_MAIN\nInternal 5 V circuitry'),
+ ('three','Synchronous buck · 3.3 V','+3V3_MAIN\nMCU / digital / communications'),
+ ('twelve','Regulated buck-boost · 12 V','+12V_SENS\nProtected Hall-sensor supply')]):
+ y=245+i*120
+ f.node(key+'in','VBAT_PROT',30,y,190,74,'power')
+ f.node(key,label,300,y,310,74,'power'); f.node(key+'out',out,690,y,310,74,'power')
+ f.edge(key+'in',key,kind='power'); f.edge(key,key+'out',kind='power')
+f.note('Repeated VBAT_PROT labels denote the same rail. Protected branch details are shown separately.',725); f.save()
+
+f = Figure('power-branches','Protected and filtered rail branches','POWER_ARCHITECTURE.md: rail descriptions',1040,700)
+for i,(a,b,c) in enumerate([
+ ('+5V_MAIN','eFuse / protected load switch','+5V_AUX\nExternal logic outputs'),
+ ('+5V_MAIN','eFuse / load switch\nFerrite bead + local filter','+5V_SENS\n5 V sensor excitation'),
+ ('+3V3_MAIN','Ferrite bead + local filter','+3V3_ANA\nAnalogue supplies /\nADC reference'),
+ ('12 V buck-boost output','Current limit / protected switch\nHarness filter + decoupling','+12V_SENS\nCrank / cam Hall sensors')]):
+ y=95+i*135
+ f.node(f'a{i}',a,30,y,240,90,'power'); f.node(f'b{i}',b,340,y,320,90,'power'); f.node(f'c{i}',c,730,y,280,90,'power')
+ f.edge(f'a{i}',f'b{i}',kind='power'); f.edge(f'b{i}',f'c{i}',kind='power')
+f.note('Optional analogue LDO and final current limits remain validation items; see the rail descriptions.',630); f.save()
+
+f=Figure('ratiometric','Ratiometric sensor acquisition','POWER_ARCHITECTURE.md: Ratiometric 5 V Sensor Measurements',1040,540)
+for key,label,x,y,w,kind in [('rail','+5V_SENS',30,90,220,'power'),('sensor','5 V sensor\nExcitation input',340,90,280,'device'),('sig','Sensor output',30,240,220,'signal'),('div','Matched divider / filter',340,240,280,'signal'),('adc','ADC sensor channel',730,240,280,'signal'),('rail2','+5V_SENS',30,380,220,'power'),('sense','Matched divider / filter',340,380,280,'signal'),('adc2','ADC 5-V-sense channel',730,380,280,'signal')]: f.node(key,label,x,y,w,74,kind)
+f.edge('rail','sensor',kind='power'); f.edge('sig','div'); f.edge('div','adc'); f.edge('rail2','sense'); f.edge('sense','adc2')
+f.note('Sensor output is the sensor’s signal pin. Both ADC channels use +3V3_ANA as their reference.',470); f.save()
+
+chain('dac-output','Optional analogue-output provision','IO_ARCHITECTURE.md: Analogue-output provision',['MCU DAC','Rail-to-rail buffer','Protection /\nseries impedance','Connector'],'Provision only; final electrical range, load and protection remain to be defined.')
+
+f=Figure('deadman-inputs','Deadman contacts and observations','IO_MODULES/DEAD_MAN.md: Logic domains',1040,650)
+for i,c in enumerate('AB'):
+ y=100+i*245
+ f.node(c+'s','Protected 5 V\nIndependent NO contact '+c,30,y,260,80,'power')
+ f.node(c+'p','Protected input '+c+'\nOwn filter + default-low bias',370,y,290,80,'signal')
+ f.node(c+'h','DEADMAN_A_HELD\n5 V · non-inverting' if c=='A' else 'DEADMAN_B_RELEASED\n5 V · inverting',750,y,260,80,'signal')
+ f.node(c+'d','DEADMAN_'+c+'_STATUS\n3.3 V · held = high → MCU',370,y+120,330,75,'device')
+ f.edge(c+'s',c+'p'); f.edge(c+'p',c+'h'); f.edge(c+'p',c+'d',exit=(.5,1),entry=(.5,0))
+f.note('Separate harness paths. MCU status observations are diagnostic; the 5 V signals feed the permit gates.',575);f.save()
+
+for name,title,part,pin,load,ground,source in [
+ ('ignition-power','Ignition power path','VBG08H-E','HVC','Coil primary','IGN_PGND','IGNITION'),
+ ('injector-power','Injector power path','VNL5050S5-E','DRAIN','Injector coil','INJ_PGND','INJECTON'),
+ ('sink-power','Generic low-side power path','TLE9104SH','OUTx','External load\nvia SINK_OUTx','OUT_PGND','DIGITAL_OUTPUTS')]:
+ f=Figure(name,title,'IO_MODULES/'+source+'.md: Power path',1040,460)
+ f.node('rail','VBAT_PROT',30,100,230,80,'power'); f.node('load',load,350,100,280,80,'device');f.node('driver',part+'\n'+pin,720,100,290,80,'device')
+ f.node('switch','Internal IGBT' if source=='IGNITION' else 'Internal low-side MOSFET',720,230,290,70,'device')
+ f.node('return',('PGND1 + PGND2' if source=='IGNITION' else 'SOURCE' if source=='INJECTON' else 'Power return')+' → '+ground,350,350,660,60,'ground')
+ f.edge('rail','load',kind='power');f.edge('load','driver',kind='power');f.edge('driver','switch',exit=(.5,1),entry=(.5,0),kind='power');f.edge('switch','return',exit=(.5,1),entry=(.8,0),kind='power')
+ f.note('Functional current path. '+ground+' returns separately to the power-entry ground star.',410);f.save()
+
+chain('ignition-flag','Ignition current-flag diagnostic','IO_MODULES/IGNITION.md: Current-flag diagnostic',['VBG08H-E C.F.\nOpen-drain output','Reference-style R/C filter\n+3V3_MAIN pull-up','STM32 GPIO'],'Diagnostic current-threshold observation; separate from the hardware inhibit path.')
+
+f=Figure('ignition-ground','Ignition ground and Kelvin reference','IO_MODULES/IGNITION.md: Ground and layout',1040,480)
+for i,(key,label) in enumerate([('p1','VBG08H-E PGND1'),('p2','VBG08H-E PGND2'),('g','VBG08H-E GND')]):
+ f.node(key,label,30,100+i*115,230,64,'ground')
+f.node('join','IGN_PGND\nLocal joining point',490,170,220,105,'ground');f.node('star','Power-entry\nground star',800,170,210,105,'ground')
+f.edge('p1','join','Matched heavy copper',points=[(400,132),(400,190)],entry=(0,.2),arrows=False)
+f.edge('p2','join','Matched heavy copper',entry=(0,.65),arrows=False)
+f.edge('g','join','Separate Kelvin trace',points=[(600,362)],entry=(.5,1),arrows=False)
+f.edge('join','star',arrows=False)
+f.note('GND carries the local reference, not coil current. No separate remote-DGND connection.',410);f.save()
+chain('injector-ground','Injector ground return','IO_MODULES/INJECTON.md: Ground and layout',['VNL5050S5-E SOURCE','INJ_PGND\nShort, low-impedance copper','Power-entry ground star'],'SOURCE is both power return and local logic reference. No separate Kelvin pin.',kind='ground')
+
+f=Figure('sink-interfaces','Low-side driver supplies and diagnostics','IO_MODULES/DIGITAL_OUTPUTS.md: Protected low-side outputs',1040,610)
+for i,(a,b) in enumerate([('VBAT_PROT','TLE9104SH VS'),('+5V_MAIN','TLE9104SH VDD'),('+3V3_MAIN','TLE9104SH VIO')]):
+ y=95+i*110
+ f.node('s'+str(i),a,30,y,230,70,'power'); f.node('p'+str(i),b,380,y,280,70,'device');f.edge('s'+str(i),'p'+str(i),kind='power')
+f.node('mcu','MCU SPI',30,440,230,80);f.node('spi','TLE9104SH SPI\nCommands + diagnostics',380,440,280,80,'device');f.edge('mcu','spi','Bidirectional')
+f.note('INx / EN default-low networks are shown in the companion circuit. Decouple supplies locally.',540);f.save()
+
+(OUT/'block-connections.json').write_text(json.dumps(manifest,indent=2)+'\n')
+print(f'Wrote {len(manifest)} editable block figures.')
diff --git a/Architecture/diagrams/build_circuits.py b/Architecture/diagrams/build_circuits.py
new file mode 100644
index 0000000..5809c5a
--- /dev/null
+++ b/Architecture/diagrams/build_circuits.py
@@ -0,0 +1,176 @@
+"""Rebuild documentation schematics with Schemdraw.
+
+Run with ~/.venvs/codex-schematics/bin/python. Topology JSON is emitted beside
+each figure. References identify documentation symbols, not CAD placements.
+"""
+from pathlib import Path
+import json
+import xml.etree.ElementTree as ET
+import schemdraw
+import schemdraw.elements as e
+import schemdraw.logic as logic
+import cairosvg
+
+OUT = Path(__file__).resolve().parent
+
+class Circuit:
+ def __init__(self,name,title,source):
+ self.name=name
+ self.d=schemdraw.Drawing(show=False)
+ self.d.config(unit=2.5,fontsize=12,font='DejaVu Sans',lw=1.5,color='#20394e',bgcolor='white')
+ self.top={'title':title,'source':source,'reference_scope':'documentation only','components':[],'nets':[],'no_connects':[]}
+ self.nets={}
+ def component(self,ref,kind,pins,value=''):
+ assert ref not in [c['ref'] for c in self.top['components']],ref
+ self.top['components'].append({'ref':ref,'kind':kind,'pins':list(pins),'value':value})
+ for pin,net in pins.items(): self.nets.setdefault(net,[]).append(ref+'.'+pin)
+ def label(self,xy,text,loc='top',size=12):
+ self.d.add(e.Label().at(xy).label(text,loc=loc,fontsize=size))
+ def wire(self,a,b): self.d.add(e.Line().at(a).to(b))
+ def dot(self,xy): self.d.add(e.Dot().at(xy))
+ def port(self,ref,xy,net,loc='left'):
+ self.component(ref,'port',{'P':net},net)
+ self.d.add(e.Dot(open=True).at(xy).label(net,loc=loc))
+ def res(self,ref,a,b,n1,n2,label=None):
+ self.component(ref,'resistor',{'1':n1,'2':n2},label or ref)
+ self.d.add(e.Resistor().at(a).to(b).label(label or ref))
+ def cap(self,ref,a,b,n1,n2,label=None):
+ self.component(ref,'capacitor',{'1':n1,'2':n2},label or ref)
+ self.d.add(e.Capacitor().at(a).to(b).label(label or ref))
+ def zener(self,ref,a,b,n1,n2):
+ self.component(ref,'zener',{'K':n1,'A':n2},'Low-C clamp\nVoltage TBD')
+ self.d.add(e.Zener().at(a).to(b).reverse().label('Low-C Zener\nVoltage TBD'))
+ def ground(self,ref,xy,net='SENSOR_GND'):
+ self.component(ref,'ground-port',{'P':net},net)
+ self.d.add(e.Ground().at(xy).label(net,loc='bottom'))
+ def block(self,ref,xy,label,ins,outs,w=3.5,h=2):
+ pins=[]
+ for side,ports in [('L',ins),('R',outs)]:
+ for i,(pin,net) in enumerate(ports):
+ pins.append(e.IcPin(name=pin,anchorname=pin,side=side,pos=(i+1)/(len(ports)+1)))
+ self.component(ref,'functional-block',dict(ins+outs),label)
+ return self.d.add(e.Ic(size=(w,h),pins=pins).at(xy).theta(0).label(label,loc='top'))
+ def save(self):
+ for net,ends in self.nets.items():
+ entry={'name':net,'connections':ends}
+ if len(ends)==1: entry.update(allow_single=True,note='Named boundary or supply shown in the documentation figure')
+ self.top['nets'].append(entry)
+ (OUT/(self.name+'.topology.json')).write_text(json.dumps(self.top,indent=2)+'\n')
+ self.d.save(str(OUT/(self.name+'.svg')))
+ svg_path = OUT/(self.name+'.svg')
+ ET.register_namespace('', 'http://www.w3.org/2000/svg')
+ tree = ET.parse(svg_path); root = tree.getroot()
+ x,y,w,h = map(float,root.get('viewBox').split())
+ root.set('viewBox', f'{x-16} {y-16} {w+32} {h+32}')
+ root.set('width', f'{w+32}pt'); root.set('height', f'{h+32}pt')
+ tree.write(svg_path, encoding='utf-8', xml_declaration=True)
+ cairosvg.svg2png(url=str(OUT/(self.name+'.svg')),write_to=str(OUT/(self.name+'.png')),background_color='white',output_width=1200)
+
+# Shunt protection and ADC reservoir are deliberately drawn as branches.
+c=Circuit('analog-input','Passive 0–5 V ADC channel','IO_MODULES/ANALOG_INPUTS.md: General 0--5 V channels')
+c.port('J',(0,0),'Sensor signal')
+c.wire((0,0),(2,0));c.dot((2,0))
+c.component('CLAMP','transient-protection',{'SIG':'Sensor signal','RET':'SENSOR_GND'},'Connector clamp\nPart / rating TBD')
+cl=c.d.add(e.Ic(size=(2,1),pins=[e.IcPin(name='SIG',side='T',anchorname='SIG'),e.IcPin(name='RET',side='B',anchorname='RET')]).at((1,-3)).theta(0).label('Transient clamp',loc='left'))
+c.wire((2,0),cl.SIG);c.ground('GC',cl.RET)
+c.res('R_TOP',(2,0),(6,0),'Sensor signal','DIVIDED')
+c.dot((6,0));c.res('R_BOTTOM',(6,0),(6,-3),'DIVIDED','SENSOR_GND');c.ground('GR',(6,-3))
+c.res('R_ISO',(6,0),(10,0),'DIVIDED','ADC_IN','Isolation R\nValue TBD')
+c.dot((10,0));c.cap('C_HOLD',(10,0),(10,-3),'ADC_IN','SENSOR_GND');c.ground('GH',(10,-3))
+c.wire((10,0),(13,0));c.port('ADC',(13,0),'ADC_IN',loc='right')
+c.label((6,2),'Passive analogue input',size=18);c.save()
+
+c=Circuit('thermistor','NTC excitation and acquisition','IO_MODULES/ANALOG_INPUTS.md: NTC temperature channels')
+c.port('V',(0,0),'+5V_SENS');c.res('R_PULLUP',(0,0),(4,0),'+5V_SENS','NTC_NODE','R_PULLUP\nSelected for sensor curve');c.dot((4,0))
+c.component('NTC','thermistor',{'1':'NTC_NODE','2':'SENSOR_GND'},'NTC')
+c.d.add(e.Thermistor().at((4,0)).to((4,-3)).label('NTC'));c.ground('GN',(4,-3))
+b=c.block('AFE',(7,-1),'Attenuation / local filter',[('IN','NTC_NODE')],[('OUT','ADC_NTC')],w=4)
+c.wire((4,0),b.IN);c.wire(b.OUT,(14,0));c.port('ADC',(14,0),'ADC_NTC',loc='right')
+c.port('VS',(0,-6),'+5V_SENS');b2=c.block('SENSE',(7,-7),'Matched divider / filter',[('IN','+5V_SENS')],[('OUT','ADC_5V_SENSE')],w=4)
+c.wire((0,-6),b2.IN);c.wire(b2.OUT,(14,-6));c.port('ADCS',(14,-6),'ADC_5V_SENSE',loc='right')
+c.label((7,2),'Thermistor + excitation-supply measurement',size=18)
+c.label((7,-9),'Both ADC channels use +3V3_ANA as reference. Filter and protection details remain in the text.',size=11);c.save()
+
+c=Circuit('trigger-input','Crank / cam Hall input','IO_MODULES/ENGINE_POSITION_INPUTS.md: Electrical interface')
+c.port('J',(0,0),'TRIG_x');c.wire((0,0),(3,0));c.dot((3,0))
+c.port('V',(3,4),'+12V_SENS',loc='top');c.res('R_PULLUP',(3,4),(3,0),'+12V_SENS','TRIG_x','R_PULLUP\n4.7 kΩ provision')
+c.component('CLAMP','transient-protection',{'SIG':'TRIG_x','RET':'SENSOR_GND'},'Harness clamp / ratings TBD')
+b=c.d.add(e.Ic(size=(2,1),pins=[e.IcPin(name='SIG',side='T',anchorname='SIG'),e.IcPin(name='RET',side='B',anchorname='RET')]).at((2,-3)).theta(0).label('Transient\nprotection',loc='left'))
+c.wire((3,0),b.SIG);c.ground('GC',b.RET)
+c.res('R_DIV_TOP',(3,0),(7,0),'TRIG_x','DIVIDED');c.dot((7,0))
+c.res('R_DIV_BOTTOM',(7,0),(7,-3),'DIVIDED','SENSOR_GND');c.ground('GB',(7,-3))
+c.wire((7,0),(10,0));c.dot((10,0));c.cap('C_FILTER',(10,0),(10,-3),'DIVIDED','SENSOR_GND','C_FILTER\n1 nF initial');c.ground('GF',(10,-3))
+c.wire((10,0),(12,0));s=c.d.add(logic.Schmitt().at((12,0)).right().label('SN74LVC2G17-Q1\nSupply: +3V3_MAIN',loc='top'))
+c.component('U','schmitt-buffer',{'IN':'DIVIDED','OUT':'TIMER_3V3'},'SN74LVC2G17-Q1')
+c.wire(s.out,(16,0));c.port('MCU',(16,0),'TIMER_3V3',loc='right')
+c.label((8,6),'Hall input · repeated for crank and cam',size=18)
+c.label((8,-5.5),'Sensor connector: supply = +12V_SENS; return = SENSOR_GND; output = TRIG_x. Pin numbers unassigned.',size=11);c.save()
+
+c=Circuit('ignition-command','Ignition timing and inhibit protection','IO_MODULES/IGNITION.md: Command and inhibit path')
+for i,(net,out) in enumerate([('STM32 timing (3.3 V)','INP'),('SAFE_IGNITION_INHIBIT','EN')]):
+ y=-i*7
+ c.port('J'+str(i),(0,y),net)
+ if i==0:
+ b=c.block('BUFFER',(2,y-1),'Non-inverting\n3.3 V → 5 V',[('IN',net)],[('OUT','TIMING_5V')],w=3)
+ c.wire((0,y),b.IN);c.wire(b.OUT,(7,y));net2='TIMING_5V'
+ else:c.wire((0,y),(7,y));net2=net
+ c.res('RP'+str(i),(7,y),(11,y),net2,out,'1 kΩ')
+ c.dot((11,y));c.zener('Z'+str(i),(11,y),(11,y-3),out,'VBG_LOCAL_KELVIN');c.ground('G'+str(i),(11,y-3),'VBG_LOCAL_KELVIN')
+ c.wire((11,y),(14,y));c.port('U'+str(i),(14,y),out,loc='right')
+c.label((7,2.5),'VBG08H-E command pins',size=18)
+c.label((6,-12),'INP: high = dwell; falling edge = spark. EN: high = inhibit; low = permission.',size=11);c.save()
+
+c=Circuit('injector-command','Injector command protection','IO_MODULES/INJECTON.md: Command path')
+c.port('J',(0,0),'SAFE_INJECTOR_SIG');c.res('Rprot',(0,0),(4,0),'SAFE_INJECTOR_SIG','INPUT','Rprot · 1 kΩ');c.dot((4,0))
+c.res('R_PD',(4,0),(4,-3),'INPUT','INJ_PGND','10 kΩ');c.ground('GR',(4,-3),'INJ_PGND')
+c.wire((4,0),(8,0));c.dot((8,0));c.zener('Z',(8,0),(8,-3),'INPUT','INJ_PGND');c.ground('GZ',(8,-3),'INJ_PGND')
+c.wire((8,0),(12,0));c.port('U',(12,0),'INPUT',loc='right');c.label((6,2),'VNL5050S5-E · active-high command',size=18);c.save()
+
+c=Circuit('injector-status','Injector status acquisition','IO_MODULES/INJECTON.md: Status diagnostic')
+c.port('U',(0,0),'STATUS');c.res('Rprot',(0,0),(5,0),'STATUS','MCU_STATUS','Rprot · 1 kΩ');c.dot((5,0))
+c.port('V',(5,4),'+3V3_MAIN',loc='top');c.res('R_PULLUP',(5,4),(5,0),'+3V3_MAIN','MCU_STATUS','Pull-up\nValue TBD')
+c.wire((5,0),(10,0));c.port('M',(10,0),'MCU_STATUS',loc='right');c.label((5,6),'VNL5050S5-E · open-drain diagnostic',size=18);c.save()
+
+c=Circuit('logic-output','Protected 5 V logic output','IO_MODULES/DIGITAL_OUTPUTS.md: Protected 5 V logic outputs')
+c.port('J',(0,0),'MCU GPIO');c.wire((0,0),(3,0));c.dot((3,0))
+c.res('R_IN_PD',(3,0),(3,-3),'MCU GPIO','GND');c.ground('GI',(3,-3),'GND')
+b=c.block('U',(6,-1),'TPS4H000-Q1\nVBB = +5V_AUX',[('INx','MCU GPIO')],[('OUTx','LOGIC_OUTx')],w=4)
+c.wire((3,0),b.INx);c.wire(b.OUTx,(13,0));c.dot((13,0));c.res('R_OUT_PD',(13,0),(13,-3),'LOGIC_OUTx','GND');c.ground('GO',(13,-3),'GND')
+c.wire((13,0),(17,0));c.port('O',(17,0),'LOGIC_OUTx',loc='right')
+c.label((8,3),'5 V high-side logic output',size=18)
+c.label((8,-5.5),'+5V_MAIN → eFuse / load switch → +5V_AUX. Connector TVS selection is specified in the text.',size=11);c.save()
+
+c=Circuit('sink-command','Low-side command default states','IO_MODULES/DIGITAL_OUTPUTS.md: Protected low-side outputs')
+for i,(net,pin) in enumerate([('MCU GPIO','INx'),('MCU enable','EN')]):
+ y=-i*6
+ c.port('J'+str(i),(0,y),net);c.wire((0,y),(4,y));c.dot((4,y))
+ c.res('R_IN_PD' if i==0 else 'R_EN_PD',(4,y),(4,y-2.5),net,'LOCAL_GND')
+ c.ground('G'+str(i),(4,y-2.5),'LOCAL_GND')
+ c.wire((4,y),(9,y));c.component('U'+str(i),'driver-pin',{pin:net},'TLE9104SH '+pin)
+ c.d.add(e.Dot(open=True).at((9,y)).label('TLE9104SH '+pin,loc='right'))
+c.label((4,2),'TLE9104SH · default-low commands',size=18);c.save()
+
+def equation_gate(c,ref,xy,a,b,out,invert_b=False):
+ x,y=xy
+ gate=c.d.add(logic.And(inputs=2,inputnots=[2] if invert_b else []).at(xy).right())
+ c.component(ref,'and-with-inverted-B' if invert_b else 'and',{'A':a,'B':b,'Y':out})
+ for idx,(anchor,net) in enumerate([(gate.in1,a),(gate.in2,b)]):
+ yy=y+1.4 if idx==0 else y-1.4
+ start=(x-5,yy); c.port(ref+'P'+str(idx),start,net)
+ c.wire(start,(x-1.2,yy));c.wire((x-1.2,yy),(x-1.2,anchor.y));c.wire((x-1.2,anchor.y),anchor)
+ c.wire(gate.out,(x+5,y));c.port(ref+'O',(x+5,y),out,loc='right')
+
+c=Circuit('deadman-permit','Hardware engine-permit equations','IO_MODULES/DEAD_MAN.md: Logic equations')
+equation_gate(c,'VALID',(0,0),'DEADMAN_A_HELD','DEADMAN_B_RELEASED','DEADMAN_OK',True)
+equation_gate(c,'PERMIT',(0,-6),'DEADMAN_OK','MCU_RUN_PERMIT','ENGINE_PERMIT')
+c.label((0,3),'Hardware permission · 5 V gate outputs',size=18)
+c.label((0,-9),'Bubble inverts channel B. MCU_RUN_PERMIT is 3.3 V; gates must accept that input level.',size=11);c.save()
+
+c=Circuit('deadman-outputs','Hardware permitted output commands','IO_MODULES/DEAD_MAN.md: Logic equations')
+equation_gate(c,'INJECT',(0,0),'ENGINE_PERMIT','MCU_INJECTOR_SIG','SAFE_INJECTOR_SIG')
+gate=c.d.add(logic.Not().at((0,-6)).right());c.component('INHIBIT','not',{'A':'ENGINE_PERMIT','Y':'SAFE_IGNITION_INHIBIT'})
+c.port('I',(-5,-6),'ENGINE_PERMIT');c.wire((-5,-6),gate.in1);c.wire(gate.out,(5,-6));c.port('O',(5,-6),'SAFE_IGNITION_INHIBIT',loc='right')
+c.label((0,3),'Injector permission and ignition inhibit',size=18)
+c.label((0,-8),'SAFE_IGNITION_INHIBIT: high = inhibited. Supply-loss default states require the documented bias networks.',size=11);c.save()
+
+print('Wrote 10 SVG circuits, previews and topology manifests.')
diff --git a/Architecture/diagrams/dac-output.drawio b/Architecture/diagrams/dac-output.drawio
new file mode 100644
index 0000000..99732ca
--- /dev/null
+++ b/Architecture/diagrams/dac-output.drawio
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Architecture/diagrams/dac-output.png b/Architecture/diagrams/dac-output.png
new file mode 100644
index 0000000..e9c01a5
Binary files /dev/null and b/Architecture/diagrams/dac-output.png differ
diff --git a/Architecture/diagrams/dac-output.svg b/Architecture/diagrams/dac-output.svg
new file mode 100644
index 0000000..59a469c
--- /dev/null
+++ b/Architecture/diagrams/dac-output.svg
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/Architecture/diagrams/deadman-inputs.drawio b/Architecture/diagrams/deadman-inputs.drawio
new file mode 100644
index 0000000..5385430
--- /dev/null
+++ b/Architecture/diagrams/deadman-inputs.drawio
@@ -0,0 +1,59 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Architecture/diagrams/deadman-inputs.png b/Architecture/diagrams/deadman-inputs.png
new file mode 100644
index 0000000..98221b5
Binary files /dev/null and b/Architecture/diagrams/deadman-inputs.png differ
diff --git a/Architecture/diagrams/deadman-inputs.svg b/Architecture/diagrams/deadman-inputs.svg
new file mode 100644
index 0000000..f5da9eb
--- /dev/null
+++ b/Architecture/diagrams/deadman-inputs.svg
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/Architecture/diagrams/deadman-outputs.png b/Architecture/diagrams/deadman-outputs.png
new file mode 100644
index 0000000..384a4f5
Binary files /dev/null and b/Architecture/diagrams/deadman-outputs.png differ
diff --git a/Architecture/diagrams/deadman-outputs.svg b/Architecture/diagrams/deadman-outputs.svg
new file mode 100644
index 0000000..8aa6354
--- /dev/null
+++ b/Architecture/diagrams/deadman-outputs.svg
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/Architecture/diagrams/deadman-outputs.topology.json b/Architecture/diagrams/deadman-outputs.topology.json
new file mode 100644
index 0000000..fef59ec
--- /dev/null
+++ b/Architecture/diagrams/deadman-outputs.topology.json
@@ -0,0 +1,99 @@
+{
+ "title": "Hardware permitted output commands",
+ "source": "IO_MODULES/DEAD_MAN.md: Logic equations",
+ "reference_scope": "documentation only",
+ "components": [
+ {
+ "ref": "INJECT",
+ "kind": "and",
+ "pins": [
+ "A",
+ "B",
+ "Y"
+ ],
+ "value": ""
+ },
+ {
+ "ref": "INJECTP0",
+ "kind": "port",
+ "pins": [
+ "P"
+ ],
+ "value": "ENGINE_PERMIT"
+ },
+ {
+ "ref": "INJECTP1",
+ "kind": "port",
+ "pins": [
+ "P"
+ ],
+ "value": "MCU_INJECTOR_SIG"
+ },
+ {
+ "ref": "INJECTO",
+ "kind": "port",
+ "pins": [
+ "P"
+ ],
+ "value": "SAFE_INJECTOR_SIG"
+ },
+ {
+ "ref": "INHIBIT",
+ "kind": "not",
+ "pins": [
+ "A",
+ "Y"
+ ],
+ "value": ""
+ },
+ {
+ "ref": "I",
+ "kind": "port",
+ "pins": [
+ "P"
+ ],
+ "value": "ENGINE_PERMIT"
+ },
+ {
+ "ref": "O",
+ "kind": "port",
+ "pins": [
+ "P"
+ ],
+ "value": "SAFE_IGNITION_INHIBIT"
+ }
+ ],
+ "nets": [
+ {
+ "name": "ENGINE_PERMIT",
+ "connections": [
+ "INJECT.A",
+ "INJECTP0.P",
+ "INHIBIT.A",
+ "I.P"
+ ]
+ },
+ {
+ "name": "MCU_INJECTOR_SIG",
+ "connections": [
+ "INJECT.B",
+ "INJECTP1.P"
+ ]
+ },
+ {
+ "name": "SAFE_INJECTOR_SIG",
+ "connections": [
+ "INJECT.Y",
+ "INJECTO.P"
+ ]
+ },
+ {
+ "name": "SAFE_IGNITION_INHIBIT",
+ "connections": [
+ "INHIBIT.Y",
+ "O.P"
+ ]
+ }
+ ],
+ "no_connects": []
+}
diff --git a/Architecture/diagrams/deadman-permit.png b/Architecture/diagrams/deadman-permit.png
new file mode 100644
index 0000000..591fa80
Binary files /dev/null and b/Architecture/diagrams/deadman-permit.png differ
diff --git a/Architecture/diagrams/deadman-permit.svg b/Architecture/diagrams/deadman-permit.svg
new file mode 100644
index 0000000..b113d76
--- /dev/null
+++ b/Architecture/diagrams/deadman-permit.svg
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/Architecture/diagrams/deadman-permit.topology.json b/Architecture/diagrams/deadman-permit.topology.json
new file mode 100644
index 0000000..f8dc4bf
--- /dev/null
+++ b/Architecture/diagrams/deadman-permit.topology.json
@@ -0,0 +1,115 @@
+{
+ "title": "Hardware engine-permit equations",
+ "source": "IO_MODULES/DEAD_MAN.md: Logic equations",
+ "reference_scope": "documentation only",
+ "components": [
+ {
+ "ref": "VALID",
+ "kind": "and-with-inverted-B",
+ "pins": [
+ "A",
+ "B",
+ "Y"
+ ],
+ "value": ""
+ },
+ {
+ "ref": "VALIDP0",
+ "kind": "port",
+ "pins": [
+ "P"
+ ],
+ "value": "DEADMAN_A_HELD"
+ },
+ {
+ "ref": "VALIDP1",
+ "kind": "port",
+ "pins": [
+ "P"
+ ],
+ "value": "DEADMAN_B_RELEASED"
+ },
+ {
+ "ref": "VALIDO",
+ "kind": "port",
+ "pins": [
+ "P"
+ ],
+ "value": "DEADMAN_OK"
+ },
+ {
+ "ref": "PERMIT",
+ "kind": "and",
+ "pins": [
+ "A",
+ "B",
+ "Y"
+ ],
+ "value": ""
+ },
+ {
+ "ref": "PERMITP0",
+ "kind": "port",
+ "pins": [
+ "P"
+ ],
+ "value": "DEADMAN_OK"
+ },
+ {
+ "ref": "PERMITP1",
+ "kind": "port",
+ "pins": [
+ "P"
+ ],
+ "value": "MCU_RUN_PERMIT"
+ },
+ {
+ "ref": "PERMITO",
+ "kind": "port",
+ "pins": [
+ "P"
+ ],
+ "value": "ENGINE_PERMIT"
+ }
+ ],
+ "nets": [
+ {
+ "name": "DEADMAN_A_HELD",
+ "connections": [
+ "VALID.A",
+ "VALIDP0.P"
+ ]
+ },
+ {
+ "name": "DEADMAN_B_RELEASED",
+ "connections": [
+ "VALID.B",
+ "VALIDP1.P"
+ ]
+ },
+ {
+ "name": "DEADMAN_OK",
+ "connections": [
+ "VALID.Y",
+ "VALIDO.P",
+ "PERMIT.A",
+ "PERMITP0.P"
+ ]
+ },
+ {
+ "name": "MCU_RUN_PERMIT",
+ "connections": [
+ "PERMIT.B",
+ "PERMITP1.P"
+ ]
+ },
+ {
+ "name": "ENGINE_PERMIT",
+ "connections": [
+ "PERMIT.Y",
+ "PERMITO.P"
+ ]
+ }
+ ],
+ "no_connects": []
+}
diff --git a/Architecture/diagrams/export_blocks.py b/Architecture/diagrams/export_blocks.py
new file mode 100644
index 0000000..33743fd
--- /dev/null
+++ b/Architecture/diagrams/export_blocks.py
@@ -0,0 +1,35 @@
+"""Export only .drawio inputs, verify SVG content, and build PNG previews.
+
+Run with ~/.venvs/codex-schematics/bin/python. The desktop renderer may need
+execution outside a restricted Electron sandbox. It never edits source XML.
+"""
+from pathlib import Path
+import shutil
+import subprocess
+import tempfile
+import xml.etree.ElementTree as ET
+import cairosvg
+
+OUT=Path(__file__).resolve().parent
+sources=sorted(OUT.glob('*.drawio'))
+assert sources, 'No draw.io sources found'
+with tempfile.TemporaryDirectory(prefix='neoecu-drawio-') as tmp:
+ for source in sources: shutil.copy2(source,Path(tmp)/source.name)
+ subprocess.run(['/usr/bin/drawio','-x','-f','svg','-e','-b','20','--svg-theme','light','-o',str(OUT),tmp],check=True)
+
+ET.register_namespace('', 'http://www.w3.org/2000/svg')
+ET.register_namespace('xlink', 'http://www.w3.org/1999/xlink')
+for source in sources:
+ svg=source.with_suffix('.svg')
+ tree=ET.parse(svg);root=tree.getroot()
+ assert any(e.tag.endswith('text') for e in root.iter()),f'Empty figure: {svg}'
+ # draw.io emits an irrelevant fallback warning even for native SVG text.
+ # Remove only that advisory, and only when there is no foreignObject text.
+ assert not any(e.tag.endswith('foreignObject') for e in root.iter()),f'Nonportable SVG text: {svg}'
+ for parent in root.iter():
+ for child in list(parent):
+ if child.tag.endswith('switch') and 'Text is not SVG - cannot display' in ''.join(child.itertext()):
+ parent.remove(child)
+ tree.write(svg,encoding='utf-8',xml_declaration=True)
+ cairosvg.svg2png(url=str(svg),write_to=str(svg.with_suffix('.png')),background_color='white')
+print(f'Exported and checked {len(sources)} block figures.')
diff --git a/Architecture/diagrams/ignition-command.png b/Architecture/diagrams/ignition-command.png
new file mode 100644
index 0000000..20c4c1c
Binary files /dev/null and b/Architecture/diagrams/ignition-command.png differ
diff --git a/Architecture/diagrams/ignition-command.svg b/Architecture/diagrams/ignition-command.svg
new file mode 100644
index 0000000..325f685
--- /dev/null
+++ b/Architecture/diagrams/ignition-command.svg
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/Architecture/diagrams/ignition-command.topology.json b/Architecture/diagrams/ignition-command.topology.json
new file mode 100644
index 0000000..9705f41
--- /dev/null
+++ b/Architecture/diagrams/ignition-command.topology.json
@@ -0,0 +1,149 @@
+{
+ "title": "Ignition timing and inhibit protection",
+ "source": "IO_MODULES/IGNITION.md: Command and inhibit path",
+ "reference_scope": "documentation only",
+ "components": [
+ {
+ "ref": "J0",
+ "kind": "port",
+ "pins": [
+ "P"
+ ],
+ "value": "STM32 timing (3.3 V)"
+ },
+ {
+ "ref": "BUFFER",
+ "kind": "functional-block",
+ "pins": [
+ "IN",
+ "OUT"
+ ],
+ "value": "Non-inverting\n3.3 V \u2192 5 V"
+ },
+ {
+ "ref": "RP0",
+ "kind": "resistor",
+ "pins": [
+ "1",
+ "2"
+ ],
+ "value": "1 k\u03a9"
+ },
+ {
+ "ref": "Z0",
+ "kind": "zener",
+ "pins": [
+ "K",
+ "A"
+ ],
+ "value": "Low-C clamp\nVoltage TBD"
+ },
+ {
+ "ref": "G0",
+ "kind": "ground-port",
+ "pins": [
+ "P"
+ ],
+ "value": "VBG_LOCAL_KELVIN"
+ },
+ {
+ "ref": "U0",
+ "kind": "port",
+ "pins": [
+ "P"
+ ],
+ "value": "INP"
+ },
+ {
+ "ref": "J1",
+ "kind": "port",
+ "pins": [
+ "P"
+ ],
+ "value": "SAFE_IGNITION_INHIBIT"
+ },
+ {
+ "ref": "RP1",
+ "kind": "resistor",
+ "pins": [
+ "1",
+ "2"
+ ],
+ "value": "1 k\u03a9"
+ },
+ {
+ "ref": "Z1",
+ "kind": "zener",
+ "pins": [
+ "K",
+ "A"
+ ],
+ "value": "Low-C clamp\nVoltage TBD"
+ },
+ {
+ "ref": "G1",
+ "kind": "ground-port",
+ "pins": [
+ "P"
+ ],
+ "value": "VBG_LOCAL_KELVIN"
+ },
+ {
+ "ref": "U1",
+ "kind": "port",
+ "pins": [
+ "P"
+ ],
+ "value": "EN"
+ }
+ ],
+ "nets": [
+ {
+ "name": "STM32 timing (3.3 V)",
+ "connections": [
+ "J0.P",
+ "BUFFER.IN"
+ ]
+ },
+ {
+ "name": "TIMING_5V",
+ "connections": [
+ "BUFFER.OUT",
+ "RP0.1"
+ ]
+ },
+ {
+ "name": "INP",
+ "connections": [
+ "RP0.2",
+ "Z0.K",
+ "U0.P"
+ ]
+ },
+ {
+ "name": "VBG_LOCAL_KELVIN",
+ "connections": [
+ "Z0.A",
+ "G0.P",
+ "Z1.A",
+ "G1.P"
+ ]
+ },
+ {
+ "name": "SAFE_IGNITION_INHIBIT",
+ "connections": [
+ "J1.P",
+ "RP1.1"
+ ]
+ },
+ {
+ "name": "EN",
+ "connections": [
+ "RP1.2",
+ "Z1.K",
+ "U1.P"
+ ]
+ }
+ ],
+ "no_connects": []
+}
diff --git a/Architecture/diagrams/ignition-flag.drawio b/Architecture/diagrams/ignition-flag.drawio
new file mode 100644
index 0000000..d033dd7
--- /dev/null
+++ b/Architecture/diagrams/ignition-flag.drawio
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Architecture/diagrams/ignition-flag.png b/Architecture/diagrams/ignition-flag.png
new file mode 100644
index 0000000..22c0632
Binary files /dev/null and b/Architecture/diagrams/ignition-flag.png differ
diff --git a/Architecture/diagrams/ignition-flag.svg b/Architecture/diagrams/ignition-flag.svg
new file mode 100644
index 0000000..1424394
--- /dev/null
+++ b/Architecture/diagrams/ignition-flag.svg
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/Architecture/diagrams/ignition-ground.drawio b/Architecture/diagrams/ignition-ground.drawio
new file mode 100644
index 0000000..6398356
--- /dev/null
+++ b/Architecture/diagrams/ignition-ground.drawio
@@ -0,0 +1,53 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Architecture/diagrams/ignition-ground.png b/Architecture/diagrams/ignition-ground.png
new file mode 100644
index 0000000..b39a790
Binary files /dev/null and b/Architecture/diagrams/ignition-ground.png differ
diff --git a/Architecture/diagrams/ignition-ground.svg b/Architecture/diagrams/ignition-ground.svg
new file mode 100644
index 0000000..2d09993
--- /dev/null
+++ b/Architecture/diagrams/ignition-ground.svg
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/Architecture/diagrams/ignition-power.drawio b/Architecture/diagrams/ignition-power.drawio
new file mode 100644
index 0000000..0f788ab
--- /dev/null
+++ b/Architecture/diagrams/ignition-power.drawio
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Architecture/diagrams/ignition-power.png b/Architecture/diagrams/ignition-power.png
new file mode 100644
index 0000000..c6386b6
Binary files /dev/null and b/Architecture/diagrams/ignition-power.png differ
diff --git a/Architecture/diagrams/ignition-power.svg b/Architecture/diagrams/ignition-power.svg
new file mode 100644
index 0000000..aae4fab
--- /dev/null
+++ b/Architecture/diagrams/ignition-power.svg
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/Architecture/diagrams/injector-command.png b/Architecture/diagrams/injector-command.png
new file mode 100644
index 0000000..cdc791d
Binary files /dev/null and b/Architecture/diagrams/injector-command.png differ
diff --git a/Architecture/diagrams/injector-command.svg b/Architecture/diagrams/injector-command.svg
new file mode 100644
index 0000000..db2bc08
--- /dev/null
+++ b/Architecture/diagrams/injector-command.svg
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/Architecture/diagrams/injector-command.topology.json b/Architecture/diagrams/injector-command.topology.json
new file mode 100644
index 0000000..6b9fb4a
--- /dev/null
+++ b/Architecture/diagrams/injector-command.topology.json
@@ -0,0 +1,94 @@
+{
+ "title": "Injector command protection",
+ "source": "IO_MODULES/INJECTON.md: Command path",
+ "reference_scope": "documentation only",
+ "components": [
+ {
+ "ref": "J",
+ "kind": "port",
+ "pins": [
+ "P"
+ ],
+ "value": "SAFE_INJECTOR_SIG"
+ },
+ {
+ "ref": "Rprot",
+ "kind": "resistor",
+ "pins": [
+ "1",
+ "2"
+ ],
+ "value": "Rprot \u00b7 1 k\u03a9"
+ },
+ {
+ "ref": "R_PD",
+ "kind": "resistor",
+ "pins": [
+ "1",
+ "2"
+ ],
+ "value": "10 k\u03a9"
+ },
+ {
+ "ref": "GR",
+ "kind": "ground-port",
+ "pins": [
+ "P"
+ ],
+ "value": "INJ_PGND"
+ },
+ {
+ "ref": "Z",
+ "kind": "zener",
+ "pins": [
+ "K",
+ "A"
+ ],
+ "value": "Low-C clamp\nVoltage TBD"
+ },
+ {
+ "ref": "GZ",
+ "kind": "ground-port",
+ "pins": [
+ "P"
+ ],
+ "value": "INJ_PGND"
+ },
+ {
+ "ref": "U",
+ "kind": "port",
+ "pins": [
+ "P"
+ ],
+ "value": "INPUT"
+ }
+ ],
+ "nets": [
+ {
+ "name": "SAFE_INJECTOR_SIG",
+ "connections": [
+ "J.P",
+ "Rprot.1"
+ ]
+ },
+ {
+ "name": "INPUT",
+ "connections": [
+ "Rprot.2",
+ "R_PD.1",
+ "Z.K",
+ "U.P"
+ ]
+ },
+ {
+ "name": "INJ_PGND",
+ "connections": [
+ "R_PD.2",
+ "GR.P",
+ "Z.A",
+ "GZ.P"
+ ]
+ }
+ ],
+ "no_connects": []
+}
diff --git a/Architecture/diagrams/injector-ground.drawio b/Architecture/diagrams/injector-ground.drawio
new file mode 100644
index 0000000..4b35d35
--- /dev/null
+++ b/Architecture/diagrams/injector-ground.drawio
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Architecture/diagrams/injector-ground.png b/Architecture/diagrams/injector-ground.png
new file mode 100644
index 0000000..8357eaa
Binary files /dev/null and b/Architecture/diagrams/injector-ground.png differ
diff --git a/Architecture/diagrams/injector-ground.svg b/Architecture/diagrams/injector-ground.svg
new file mode 100644
index 0000000..dd210fc
--- /dev/null
+++ b/Architecture/diagrams/injector-ground.svg
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/Architecture/diagrams/injector-power.drawio b/Architecture/diagrams/injector-power.drawio
new file mode 100644
index 0000000..4b14d52
--- /dev/null
+++ b/Architecture/diagrams/injector-power.drawio
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Architecture/diagrams/injector-power.png b/Architecture/diagrams/injector-power.png
new file mode 100644
index 0000000..34214ed
Binary files /dev/null and b/Architecture/diagrams/injector-power.png differ
diff --git a/Architecture/diagrams/injector-power.svg b/Architecture/diagrams/injector-power.svg
new file mode 100644
index 0000000..3d33b83
--- /dev/null
+++ b/Architecture/diagrams/injector-power.svg
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/Architecture/diagrams/injector-status.png b/Architecture/diagrams/injector-status.png
new file mode 100644
index 0000000..e4e7423
Binary files /dev/null and b/Architecture/diagrams/injector-status.png differ
diff --git a/Architecture/diagrams/injector-status.svg b/Architecture/diagrams/injector-status.svg
new file mode 100644
index 0000000..4585d6b
--- /dev/null
+++ b/Architecture/diagrams/injector-status.svg
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/Architecture/diagrams/injector-status.topology.json b/Architecture/diagrams/injector-status.topology.json
new file mode 100644
index 0000000..2952b9d
--- /dev/null
+++ b/Architecture/diagrams/injector-status.topology.json
@@ -0,0 +1,74 @@
+{
+ "title": "Injector status acquisition",
+ "source": "IO_MODULES/INJECTON.md: Status diagnostic",
+ "reference_scope": "documentation only",
+ "components": [
+ {
+ "ref": "U",
+ "kind": "port",
+ "pins": [
+ "P"
+ ],
+ "value": "STATUS"
+ },
+ {
+ "ref": "Rprot",
+ "kind": "resistor",
+ "pins": [
+ "1",
+ "2"
+ ],
+ "value": "Rprot \u00b7 1 k\u03a9"
+ },
+ {
+ "ref": "V",
+ "kind": "port",
+ "pins": [
+ "P"
+ ],
+ "value": "+3V3_MAIN"
+ },
+ {
+ "ref": "R_PULLUP",
+ "kind": "resistor",
+ "pins": [
+ "1",
+ "2"
+ ],
+ "value": "Pull-up\nValue TBD"
+ },
+ {
+ "ref": "M",
+ "kind": "port",
+ "pins": [
+ "P"
+ ],
+ "value": "MCU_STATUS"
+ }
+ ],
+ "nets": [
+ {
+ "name": "STATUS",
+ "connections": [
+ "U.P",
+ "Rprot.1"
+ ]
+ },
+ {
+ "name": "MCU_STATUS",
+ "connections": [
+ "Rprot.2",
+ "R_PULLUP.2",
+ "M.P"
+ ]
+ },
+ {
+ "name": "+3V3_MAIN",
+ "connections": [
+ "V.P",
+ "R_PULLUP.1"
+ ]
+ }
+ ],
+ "no_connects": []
+}
diff --git a/Architecture/diagrams/logic-output.png b/Architecture/diagrams/logic-output.png
new file mode 100644
index 0000000..da40152
Binary files /dev/null and b/Architecture/diagrams/logic-output.png differ
diff --git a/Architecture/diagrams/logic-output.svg b/Architecture/diagrams/logic-output.svg
new file mode 100644
index 0000000..32b02a1
--- /dev/null
+++ b/Architecture/diagrams/logic-output.svg
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/Architecture/diagrams/logic-output.topology.json b/Architecture/diagrams/logic-output.topology.json
new file mode 100644
index 0000000..e08406c
--- /dev/null
+++ b/Architecture/diagrams/logic-output.topology.json
@@ -0,0 +1,94 @@
+{
+ "title": "Protected 5 V logic output",
+ "source": "IO_MODULES/DIGITAL_OUTPUTS.md: Protected 5 V logic outputs",
+ "reference_scope": "documentation only",
+ "components": [
+ {
+ "ref": "J",
+ "kind": "port",
+ "pins": [
+ "P"
+ ],
+ "value": "MCU GPIO"
+ },
+ {
+ "ref": "R_IN_PD",
+ "kind": "resistor",
+ "pins": [
+ "1",
+ "2"
+ ],
+ "value": "R_IN_PD"
+ },
+ {
+ "ref": "GI",
+ "kind": "ground-port",
+ "pins": [
+ "P"
+ ],
+ "value": "GND"
+ },
+ {
+ "ref": "U",
+ "kind": "functional-block",
+ "pins": [
+ "INx",
+ "OUTx"
+ ],
+ "value": "TPS4H000-Q1\nVBB = +5V_AUX"
+ },
+ {
+ "ref": "R_OUT_PD",
+ "kind": "resistor",
+ "pins": [
+ "1",
+ "2"
+ ],
+ "value": "R_OUT_PD"
+ },
+ {
+ "ref": "GO",
+ "kind": "ground-port",
+ "pins": [
+ "P"
+ ],
+ "value": "GND"
+ },
+ {
+ "ref": "O",
+ "kind": "port",
+ "pins": [
+ "P"
+ ],
+ "value": "LOGIC_OUTx"
+ }
+ ],
+ "nets": [
+ {
+ "name": "MCU GPIO",
+ "connections": [
+ "J.P",
+ "R_IN_PD.1",
+ "U.INx"
+ ]
+ },
+ {
+ "name": "GND",
+ "connections": [
+ "R_IN_PD.2",
+ "GI.P",
+ "R_OUT_PD.2",
+ "GO.P"
+ ]
+ },
+ {
+ "name": "LOGIC_OUTx",
+ "connections": [
+ "U.OUTx",
+ "R_OUT_PD.1",
+ "O.P"
+ ]
+ }
+ ],
+ "no_connects": []
+}
diff --git a/Architecture/diagrams/power-branches.drawio b/Architecture/diagrams/power-branches.drawio
new file mode 100644
index 0000000..d6094d6
--- /dev/null
+++ b/Architecture/diagrams/power-branches.drawio
@@ -0,0 +1,77 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Architecture/diagrams/power-branches.png b/Architecture/diagrams/power-branches.png
new file mode 100644
index 0000000..c8c62ad
Binary files /dev/null and b/Architecture/diagrams/power-branches.png differ
diff --git a/Architecture/diagrams/power-branches.svg b/Architecture/diagrams/power-branches.svg
new file mode 100644
index 0000000..d37a4b3
--- /dev/null
+++ b/Architecture/diagrams/power-branches.svg
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/Architecture/diagrams/power-sources.drawio b/Architecture/diagrams/power-sources.drawio
new file mode 100644
index 0000000..6db0306
--- /dev/null
+++ b/Architecture/diagrams/power-sources.drawio
@@ -0,0 +1,92 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Architecture/diagrams/power-sources.png b/Architecture/diagrams/power-sources.png
new file mode 100644
index 0000000..71795f0
Binary files /dev/null and b/Architecture/diagrams/power-sources.png differ
diff --git a/Architecture/diagrams/power-sources.svg b/Architecture/diagrams/power-sources.svg
new file mode 100644
index 0000000..25f9b3a
--- /dev/null
+++ b/Architecture/diagrams/power-sources.svg
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/Architecture/diagrams/ratiometric.drawio b/Architecture/diagrams/ratiometric.drawio
new file mode 100644
index 0000000..52252a8
--- /dev/null
+++ b/Architecture/diagrams/ratiometric.drawio
@@ -0,0 +1,56 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Architecture/diagrams/ratiometric.png b/Architecture/diagrams/ratiometric.png
new file mode 100644
index 0000000..092734d
Binary files /dev/null and b/Architecture/diagrams/ratiometric.png differ
diff --git a/Architecture/diagrams/ratiometric.svg b/Architecture/diagrams/ratiometric.svg
new file mode 100644
index 0000000..0348af9
--- /dev/null
+++ b/Architecture/diagrams/ratiometric.svg
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/Architecture/diagrams/sink-command.png b/Architecture/diagrams/sink-command.png
new file mode 100644
index 0000000..79a0821
Binary files /dev/null and b/Architecture/diagrams/sink-command.png differ
diff --git a/Architecture/diagrams/sink-command.svg b/Architecture/diagrams/sink-command.svg
new file mode 100644
index 0000000..d261aea
--- /dev/null
+++ b/Architecture/diagrams/sink-command.svg
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/Architecture/diagrams/sink-command.topology.json b/Architecture/diagrams/sink-command.topology.json
new file mode 100644
index 0000000..47fa1e6
--- /dev/null
+++ b/Architecture/diagrams/sink-command.topology.json
@@ -0,0 +1,101 @@
+{
+ "title": "Low-side command default states",
+ "source": "IO_MODULES/DIGITAL_OUTPUTS.md: Protected low-side outputs",
+ "reference_scope": "documentation only",
+ "components": [
+ {
+ "ref": "J0",
+ "kind": "port",
+ "pins": [
+ "P"
+ ],
+ "value": "MCU GPIO"
+ },
+ {
+ "ref": "R_IN_PD",
+ "kind": "resistor",
+ "pins": [
+ "1",
+ "2"
+ ],
+ "value": "R_IN_PD"
+ },
+ {
+ "ref": "G0",
+ "kind": "ground-port",
+ "pins": [
+ "P"
+ ],
+ "value": "LOCAL_GND"
+ },
+ {
+ "ref": "U0",
+ "kind": "driver-pin",
+ "pins": [
+ "INx"
+ ],
+ "value": "TLE9104SH INx"
+ },
+ {
+ "ref": "J1",
+ "kind": "port",
+ "pins": [
+ "P"
+ ],
+ "value": "MCU enable"
+ },
+ {
+ "ref": "R_EN_PD",
+ "kind": "resistor",
+ "pins": [
+ "1",
+ "2"
+ ],
+ "value": "R_EN_PD"
+ },
+ {
+ "ref": "G1",
+ "kind": "ground-port",
+ "pins": [
+ "P"
+ ],
+ "value": "LOCAL_GND"
+ },
+ {
+ "ref": "U1",
+ "kind": "driver-pin",
+ "pins": [
+ "EN"
+ ],
+ "value": "TLE9104SH EN"
+ }
+ ],
+ "nets": [
+ {
+ "name": "MCU GPIO",
+ "connections": [
+ "J0.P",
+ "R_IN_PD.1",
+ "U0.INx"
+ ]
+ },
+ {
+ "name": "LOCAL_GND",
+ "connections": [
+ "R_IN_PD.2",
+ "G0.P",
+ "R_EN_PD.2",
+ "G1.P"
+ ]
+ },
+ {
+ "name": "MCU enable",
+ "connections": [
+ "J1.P",
+ "R_EN_PD.1",
+ "U1.EN"
+ ]
+ }
+ ],
+ "no_connects": []
+}
diff --git a/Architecture/diagrams/sink-interfaces.drawio b/Architecture/diagrams/sink-interfaces.drawio
new file mode 100644
index 0000000..fbb6e93
--- /dev/null
+++ b/Architecture/diagrams/sink-interfaces.drawio
@@ -0,0 +1,53 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Architecture/diagrams/sink-interfaces.png b/Architecture/diagrams/sink-interfaces.png
new file mode 100644
index 0000000..85d7eda
Binary files /dev/null and b/Architecture/diagrams/sink-interfaces.png differ
diff --git a/Architecture/diagrams/sink-interfaces.svg b/Architecture/diagrams/sink-interfaces.svg
new file mode 100644
index 0000000..8c50002
--- /dev/null
+++ b/Architecture/diagrams/sink-interfaces.svg
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/Architecture/diagrams/sink-power.drawio b/Architecture/diagrams/sink-power.drawio
new file mode 100644
index 0000000..559b8d9
--- /dev/null
+++ b/Architecture/diagrams/sink-power.drawio
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Architecture/diagrams/sink-power.png b/Architecture/diagrams/sink-power.png
new file mode 100644
index 0000000..f77e759
Binary files /dev/null and b/Architecture/diagrams/sink-power.png differ
diff --git a/Architecture/diagrams/sink-power.svg b/Architecture/diagrams/sink-power.svg
new file mode 100644
index 0000000..3042a3d
--- /dev/null
+++ b/Architecture/diagrams/sink-power.svg
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/Architecture/diagrams/thermistor.png b/Architecture/diagrams/thermistor.png
new file mode 100644
index 0000000..716284d
Binary files /dev/null and b/Architecture/diagrams/thermistor.png differ
diff --git a/Architecture/diagrams/thermistor.svg b/Architecture/diagrams/thermistor.svg
new file mode 100644
index 0000000..4460a8c
--- /dev/null
+++ b/Architecture/diagrams/thermistor.svg
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/Architecture/diagrams/thermistor.topology.json b/Architecture/diagrams/thermistor.topology.json
new file mode 100644
index 0000000..7475a4c
--- /dev/null
+++ b/Architecture/diagrams/thermistor.topology.json
@@ -0,0 +1,124 @@
+{
+ "title": "NTC excitation and acquisition",
+ "source": "IO_MODULES/ANALOG_INPUTS.md: NTC temperature channels",
+ "reference_scope": "documentation only",
+ "components": [
+ {
+ "ref": "V",
+ "kind": "port",
+ "pins": [
+ "P"
+ ],
+ "value": "+5V_SENS"
+ },
+ {
+ "ref": "R_PULLUP",
+ "kind": "resistor",
+ "pins": [
+ "1",
+ "2"
+ ],
+ "value": "R_PULLUP\nSelected for sensor curve"
+ },
+ {
+ "ref": "NTC",
+ "kind": "thermistor",
+ "pins": [
+ "1",
+ "2"
+ ],
+ "value": "NTC"
+ },
+ {
+ "ref": "GN",
+ "kind": "ground-port",
+ "pins": [
+ "P"
+ ],
+ "value": "SENSOR_GND"
+ },
+ {
+ "ref": "AFE",
+ "kind": "functional-block",
+ "pins": [
+ "IN",
+ "OUT"
+ ],
+ "value": "Attenuation / local filter"
+ },
+ {
+ "ref": "ADC",
+ "kind": "port",
+ "pins": [
+ "P"
+ ],
+ "value": "ADC_NTC"
+ },
+ {
+ "ref": "VS",
+ "kind": "port",
+ "pins": [
+ "P"
+ ],
+ "value": "+5V_SENS"
+ },
+ {
+ "ref": "SENSE",
+ "kind": "functional-block",
+ "pins": [
+ "IN",
+ "OUT"
+ ],
+ "value": "Matched divider / filter"
+ },
+ {
+ "ref": "ADCS",
+ "kind": "port",
+ "pins": [
+ "P"
+ ],
+ "value": "ADC_5V_SENSE"
+ }
+ ],
+ "nets": [
+ {
+ "name": "+5V_SENS",
+ "connections": [
+ "V.P",
+ "R_PULLUP.1",
+ "VS.P",
+ "SENSE.IN"
+ ]
+ },
+ {
+ "name": "NTC_NODE",
+ "connections": [
+ "R_PULLUP.2",
+ "NTC.1",
+ "AFE.IN"
+ ]
+ },
+ {
+ "name": "SENSOR_GND",
+ "connections": [
+ "NTC.2",
+ "GN.P"
+ ]
+ },
+ {
+ "name": "ADC_NTC",
+ "connections": [
+ "AFE.OUT",
+ "ADC.P"
+ ]
+ },
+ {
+ "name": "ADC_5V_SENSE",
+ "connections": [
+ "SENSE.OUT",
+ "ADCS.P"
+ ]
+ }
+ ],
+ "no_connects": []
+}
diff --git a/Architecture/diagrams/trigger-input.png b/Architecture/diagrams/trigger-input.png
new file mode 100644
index 0000000..bb63314
Binary files /dev/null and b/Architecture/diagrams/trigger-input.png differ
diff --git a/Architecture/diagrams/trigger-input.svg b/Architecture/diagrams/trigger-input.svg
new file mode 100644
index 0000000..67709d1
--- /dev/null
+++ b/Architecture/diagrams/trigger-input.svg
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/Architecture/diagrams/trigger-input.topology.json b/Architecture/diagrams/trigger-input.topology.json
new file mode 100644
index 0000000..6d404ba
--- /dev/null
+++ b/Architecture/diagrams/trigger-input.topology.json
@@ -0,0 +1,155 @@
+{
+ "title": "Crank / cam Hall input",
+ "source": "IO_MODULES/ENGINE_POSITION_INPUTS.md: Electrical interface",
+ "reference_scope": "documentation only",
+ "components": [
+ {
+ "ref": "J",
+ "kind": "port",
+ "pins": [
+ "P"
+ ],
+ "value": "TRIG_x"
+ },
+ {
+ "ref": "V",
+ "kind": "port",
+ "pins": [
+ "P"
+ ],
+ "value": "+12V_SENS"
+ },
+ {
+ "ref": "R_PULLUP",
+ "kind": "resistor",
+ "pins": [
+ "1",
+ "2"
+ ],
+ "value": "R_PULLUP\n4.7 k\u03a9 provision"
+ },
+ {
+ "ref": "CLAMP",
+ "kind": "transient-protection",
+ "pins": [
+ "SIG",
+ "RET"
+ ],
+ "value": "Harness clamp / ratings TBD"
+ },
+ {
+ "ref": "GC",
+ "kind": "ground-port",
+ "pins": [
+ "P"
+ ],
+ "value": "SENSOR_GND"
+ },
+ {
+ "ref": "R_DIV_TOP",
+ "kind": "resistor",
+ "pins": [
+ "1",
+ "2"
+ ],
+ "value": "R_DIV_TOP"
+ },
+ {
+ "ref": "R_DIV_BOTTOM",
+ "kind": "resistor",
+ "pins": [
+ "1",
+ "2"
+ ],
+ "value": "R_DIV_BOTTOM"
+ },
+ {
+ "ref": "GB",
+ "kind": "ground-port",
+ "pins": [
+ "P"
+ ],
+ "value": "SENSOR_GND"
+ },
+ {
+ "ref": "C_FILTER",
+ "kind": "capacitor",
+ "pins": [
+ "1",
+ "2"
+ ],
+ "value": "C_FILTER\n1 nF initial"
+ },
+ {
+ "ref": "GF",
+ "kind": "ground-port",
+ "pins": [
+ "P"
+ ],
+ "value": "SENSOR_GND"
+ },
+ {
+ "ref": "U",
+ "kind": "schmitt-buffer",
+ "pins": [
+ "IN",
+ "OUT"
+ ],
+ "value": "SN74LVC2G17-Q1"
+ },
+ {
+ "ref": "MCU",
+ "kind": "port",
+ "pins": [
+ "P"
+ ],
+ "value": "TIMER_3V3"
+ }
+ ],
+ "nets": [
+ {
+ "name": "TRIG_x",
+ "connections": [
+ "J.P",
+ "R_PULLUP.2",
+ "CLAMP.SIG",
+ "R_DIV_TOP.1"
+ ]
+ },
+ {
+ "name": "+12V_SENS",
+ "connections": [
+ "V.P",
+ "R_PULLUP.1"
+ ]
+ },
+ {
+ "name": "SENSOR_GND",
+ "connections": [
+ "CLAMP.RET",
+ "GC.P",
+ "R_DIV_BOTTOM.2",
+ "GB.P",
+ "C_FILTER.2",
+ "GF.P"
+ ]
+ },
+ {
+ "name": "DIVIDED",
+ "connections": [
+ "R_DIV_TOP.2",
+ "R_DIV_BOTTOM.1",
+ "C_FILTER.1",
+ "U.IN"
+ ]
+ },
+ {
+ "name": "TIMER_3V3",
+ "connections": [
+ "U.OUT",
+ "MCU.P"
+ ]
+ }
+ ],
+ "no_connects": []
+}