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 -``` +![Thermistor](diagrams/thermistor.svg) 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 ----------------------------------------------------------------------------------------------+ -``` +![Deadman inputs](diagrams/deadman-inputs.svg) + +![Deadman permit](diagrams/deadman-permit.svg) `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 -``` +![Dac output](diagrams/dac-output.svg) 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 -``` +![Analog input](../diagrams/analog-input.svg) `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 -``` +![Thermistor](../diagrams/thermistor.svg) 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 +![Deadman inputs](../diagrams/deadman-inputs.svg) -MCU_INJECTOR_SIG -------------------------------------------------------------------------------------------AND --> SAFE_INJECTOR_SIG -``` +![Deadman permit](../diagrams/deadman-permit.svg) + +![Deadman outputs](../diagrams/deadman-outputs.svg) 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 -``` +![Logic output](../diagrams/logic-output.svg) - `+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 +![Sink power](../diagrams/sink-power.svg) -VBAT_PROT --> TLE9104SH VS +5V_MAIN --> TLE9104SH VDD - +3V3_MAIN --> TLE9104SH VIO +![Sink interfaces](../diagrams/sink-interfaces.svg) -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 -``` +![Sink command](../diagrams/sink-command.svg) - 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 -``` +![Trigger input](../diagrams/trigger-input.svg) - 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 -``` +![Ignition power](../diagrams/ignition-power.svg) - `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 -``` +![Ignition command](../diagrams/ignition-command.svg) 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 -``` +![Ignition flag](../diagrams/ignition-flag.svg) 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 --+ -``` +![Ignition ground](../diagrams/ignition-ground.svg) - `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 -``` +![Injector power](../diagrams/injector-power.svg) - 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 -``` +![Injector command](../diagrams/injector-command.svg) ```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 -``` +![Injector status](../diagrams/injector-status.svg) 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 -``` +![Injector ground](../diagrams/injector-ground.svg) - `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 +![Power sources](diagrams/power-sources.svg) -``` +![Power branches](diagrams/power-branches.svg) ## 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 -``` +![Ratiometric](diagrams/ratiometric.svg) 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 -``` +![Thermistor](diagrams/thermistor.svg) 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 @@ + +SIGRETTransient clampSENSOR_GNDR_TOPR_BOTTOMSENSOR_GNDIsolation RValue TBDC_HOLDSENSOR_GNDPassive analogue inputSensor signalADC_IN \ 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 @@ + +Optional analogue-output provisionMCU DACRail-to-rail bufferProtection /series impedanceConnectorProvision only; final electrical range, load and protection remain to be defined. \ 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 @@ + +Deadman contacts and observationsProtected 5 VIndependent NO contact AProtected input AOwn filter + default-low biasDEADMAN_A_HELD5 V · non-invertingDEADMAN_A_STATUS3.3 V · held = high → MCUProtected 5 VIndependent NO contact BProtected input BOwn filter + default-low biasDEADMAN_B_RELEASED5 V · invertingDEADMAN_B_STATUS3.3 V · held = high → MCUSeparate harness paths. MCU status observations are diagnostic; the 5 V signals feed the permit gates. \ 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 @@ + +Injector permission and ignition inhibitSAFE_IGNITION_INHIBIT: high = inhibited. Supply-loss default states require the documented bias networks.ENGINE_PERMITMCU_INJECTOR_SIGSAFE_INJECTOR_SIGENGINE_PERMITSAFE_IGNITION_INHIBIT \ 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 @@ + +Hardware permission · 5 V gate outputsBubble inverts channel B. MCU_RUN_PERMIT is 3.3 V; gates must accept that input level.DEADMAN_A_HELDDEADMAN_B_RELEASEDDEADMAN_OKDEADMAN_OKMCU_RUN_PERMITENGINE_PERMIT \ 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 @@ + +INOUTNon-inverting3.3 V → 5 V1 kΩLow-C ZenerVoltage TBDVBG_LOCAL_KELVIN1 kΩLow-C ZenerVoltage TBDVBG_LOCAL_KELVINVBG08H-E command pinsINP: high = dwell; falling edge = spark. EN: high = inhibit; low = permission.STM32 timing (3.3 V)INPSAFE_IGNITION_INHIBITEN \ 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 @@ + +Ignition current-flag diagnosticVBG08H-E C.F.Open-drain outputReference-style R/C filter+3V3_MAIN pull-upSTM32 GPIODiagnostic current-threshold observation; separate from the hardware inhibit path. \ 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 @@ + +Ignition ground and Kelvin referenceVBG08H-E PGND1VBG08H-E PGND2VBG08H-E GNDIGN_PGNDLocal joining pointPower-entryground starMatched heavy copperMatched heavy copperSeparate Kelvin traceGND carries the local reference, not coil current. No separate remote-DGND connection. \ 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 @@ + +Ignition power pathVBAT_PROTCoil primaryVBG08H-EHVCInternal IGBTPGND1 + PGND2 → IGN_PGNDFunctional current path. IGN_PGND returns separately to the power-entry ground star. \ 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 @@ + +Rprot · 1 kΩ10 kΩINJ_PGNDLow-C ZenerVoltage TBDINJ_PGNDVNL5050S5-E · active-high commandSAFE_INJECTOR_SIGINPUT \ 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 @@ + +Injector ground returnVNL5050S5-E SOURCEINJ_PGNDShort, low-impedance copperPower-entry ground starSOURCE is both power return and local logic reference. No separate Kelvin pin. \ 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 @@ + +Injector power pathVBAT_PROTInjector coilVNL5050S5-EDRAINInternal low-side MOSFETSOURCE → INJ_PGNDFunctional current path. INJ_PGND returns separately to the power-entry ground star. \ 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 @@ + +Rprot · 1 kΩPull-upValue TBDVNL5050S5-E · open-drain diagnosticSTATUS+3V3_MAINMCU_STATUS \ 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 @@ + +R_IN_PDGNDINxOUTxTPS4H000-Q1VBB = +5V_AUXR_OUT_PDGND5 V high-side logic output+5V_MAIN → eFuse / load switch → +5V_AUX. Connector TVS selection is specified in the text.MCU GPIOLOGIC_OUTx \ 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 @@ + +Protected and filtered rail branches+5V_MAINeFuse / protected load switch+5V_AUXExternal logic outputs+5V_MAINeFuse / load switchFerrite bead + local filter+5V_SENS5 V sensor excitation+3V3_MAINFerrite bead + local filter+3V3_ANAAnalogue supplies /ADC reference12 V buck-boost outputCurrent limit / protected switchHarness filter + decoupling+12V_SENSCrank / cam Hall sensorsOptional analogue LDO and final current limits remain validation items; see the rail descriptions. \ 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 @@ + +Power sources and battery loads4S LiPo14.8 V nominal · 16.8 V fullInput fuse · reverse protectionTVS / transient protectionVBAT_PROTVBAT_PROTProtected battery branchesIgnition · injectorLow-side outputs · VBAT senseVBAT_PROTSynchronous buck · 5 V+5V_MAINInternal 5 V circuitryVBAT_PROTSynchronous buck · 3.3 V+3V3_MAINMCU / digital / communicationsVBAT_PROTRegulated buck-boost · 12 V+12V_SENSProtected Hall-sensor supplyRepeated VBAT_PROT labels denote the same rail. Protected branch details are shown separately. \ 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 @@ + +Ratiometric sensor acquisition+5V_SENS5 V sensorExcitation inputSensor outputMatched divider / filterADC sensor channel+5V_SENSMatched divider / filterADC 5-V-sense channelSensor output is the sensor’s signal pin. Both ADC channels use +3V3_ANA as their reference. \ 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 @@ + +R_IN_PDLOCAL_GNDR_EN_PDLOCAL_GNDTLE9104SH · default-low commandsMCU GPIOTLE9104SH INxMCU enableTLE9104SH EN \ 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 @@ + +Low-side driver supplies and diagnosticsVBAT_PROTTLE9104SH VS+5V_MAINTLE9104SH VDD+3V3_MAINTLE9104SH VIOMCU SPITLE9104SH SPICommands + diagnosticsINx / EN default-low networks are shown in the companion circuit. Decouple supplies locally. \ 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 @@ + +Generic low-side power pathVBAT_PROTExternal loadvia SINK_OUTxTLE9104SHOUTxInternal low-side MOSFETPower return → OUT_PGNDFunctional current path. OUT_PGND returns separately to the power-entry ground star. \ 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 @@ + +R_PULLUPSelected for sensor curveNTCSENSOR_GNDINOUTAttenuation / local filterINOUTMatched divider / filterThermistor + excitation-supply measurementBoth ADC channels use +3V3_ANA as reference. Filter and protection details remain in the text.+5V_SENSADC_NTC+5V_SENSADC_5V_SENSE \ 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 @@ + +R_PULLUP4.7 kΩ provisionSIGRETTransientprotectionSENSOR_GNDR_DIV_TOPR_DIV_BOTTOMSENSOR_GNDC_FILTER1 nF initialSENSOR_GNDSN74LVC2G17-Q1Supply: +3V3_MAINHall input · repeated for crank and camSensor connector: supply = +12V_SENS; return = SENSOR_GND; output = TRIG_x. Pin numbers unassigned.TRIG_x+12V_SENSTIMER_3V3 \ 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": [] +}