obd2
Differences
This shows you the differences between two versions of the page.
| Next revision | Previous revision | ||
| obd2 [2026/08/09 18:01] – created - external edit 127.0.0.1 | obd2 [2026/08/10 13:47] (current) – external edit 127.0.0.1 | ||
|---|---|---|---|
| Line 1: | Line 1: | ||
| ====== OBD-II diagnostics ====== | ====== OBD-II diagnostics ====== | ||
| - | What you can and cannot get from the OBD-II socket on the U5, worked out by probing it with a | + | What you can and cannot get from the OBD-II socket on the U5, worked out by probing it with a cheap |
| - | cheap USB-CAN adapter. Short version: **you can read a lot, you cannot write anything.** See | + | USB-CAN adapter |
| + | read a great deal, but you cannot write anything | ||
| [[canbus|CAN bus]] for how this port differs from the internal buses. | [[canbus|CAN bus]] for how this port differs from the internal buses. | ||
| ===== The port is a query-only diagnostic gateway ===== | ===== The port is a query-only diagnostic gateway ===== | ||
| - | * OBD-II **pin 6 = CAN-H, pin 14 = CAN-L** (ground on 4/5, permanent 12 V on 16). This is the only CAN pair on the connector. | + | * OBD-II **pin 6 = CAN-H, pin 14 = CAN-L** (ground on 4/5, permanent 12 V on 16). This is the only CAN pair on the connector |
| * **Passive listening is silent** at every bitrate — nothing is broadcast here. | * **Passive listening is silent** at every bitrate — nothing is broadcast here. | ||
| * **Active requests are answered** at **500 kbit/s, 11-bit** (ISO 15765-4). 29-bit and other bitrates stay silent. | * **Active requests are answered** at **500 kbit/s, 11-bit** (ISO 15765-4). 29-bit and other bitrates stay silent. | ||
| - | * The port sits on a **dedicated diagnostic CAN that dead-ends at the central gateway**. The gateway bridges the car's separate internal buses (powertrain, body, chassis, infotainment, | + | * The port sits on a **dedicated diagnostic CAN that dead-ends at the central gateway**. The gateway bridges the car's separate internal buses — **powertrain, chassis, body/ |
| ===== Generic OBD-II — any scan tool ===== | ===== Generic OBD-II — any scan tool ===== | ||
| - | Standard emissions services work, addressed functionally to **0x7DF** (responses on 0x7E8): | + | Standard emissions services work, addressed functionally to **0x7DF** (responses on **0x7E8**): |
| * **Mode 09** — VIN ('' | * **Mode 09** — VIN ('' | ||
| * **Mode 03 / 07 / 0A** — stored / pending / permanent DTCs. | * **Mode 03 / 07 / 0A** — stored / pending / permanent DTCs. | ||
| - | * **Mode 01** — live PIDs. The primary powertrain | + | * **Mode 01** — live PIDs. The primary powertrain |
| + | * **Mode 04** — clear emissions DTCs (see //Clearing fault codes// below). | ||
| - | As on any EV, generic OBD exposes little — VIN, generic fault codes, a few values. Everything | + | As on any EV, generic OBD exposes little — VIN, generic fault codes, a couple of values |
| - | interesting | + | parked). Everything interesting |
| + | layer below. | ||
| - | ===== Manufacturer diagnostics | + | ===== The ECU map (UDS) ===== |
| - | The gateway **routes UDS requests to the internal ECUs**. | + | The gateway **routes UDS requests to the internal ECUs**. |
| - | single functional **TesterPresent** ('' | + | functional **TesterPresent** ('' |
| - | answers from its own ID. On the U5 this finds **24 ECUs**. Response ID = request ID **+ 8**. | + | from its own ID. On the U5 this finds **24 ECUs**. Response ID = request ID **+ 8** (e.g. 0x701 → 0x709). |
| - | ^ Request ID(s) ^ What it is (inferred from what it exposes) | + | ^ Request ID ^ Notes ^ |
| - | | **0x7E0** | Generic-OBD powertrain endpoint | + | | **0x7E0** | Generic-OBD powertrain endpoint. Answers |
| - | | **0x7E1** | **Battery management system** — exposes | + | | **0x7E1** | **Battery management system** — pack voltage / current / SoC / cell data live here (below). | |
| - | | **0x7E2, 0x7E3** | Powertrain pair (consecutive part numbers) — e.g. motor/ | + | | **0x7E2, 0x7E3** | Powertrain pair (consecutive part numbers) — motor/ |
| - | | **0x700–0x707, | + | | **0x700–0x707, |
| - | Roles above are **our inferences** from each ECU' | + | The internal ECUs reachable this way are the usual EV set: **BMS, VCU, motor controller, on-board |
| + | charger, gear selector** (powertrain); | ||
| + | low-speed warning** (body); **ESP, EPS, iBooster, airbag, steering-angle sensor, cameras/ | ||
| + | (chassis); **head unit, instrument cluster** (infotainment); | ||
| + | address↔module mapping is only confirmed for 0x7E0/ | ||
| + | address block. | ||
| ===== Reading data (non-destructive) ===== | ===== Reading data (non-destructive) ===== | ||
| Line 41: | Line 49: | ||
| In the **default session** (no session change) you can typically: | In the **default session** (no session change) you can typically: | ||
| - | * **0x19 ReadDTCInformation** — stored fault codes, decoded (e.g. '' | + | * **0x19 ReadDTCInformation** — stored fault codes, decoded ('' |
| * **0x22 ReadDataByIdentifier** — read data by 16-bit DID. | * **0x22 ReadDataByIdentifier** — read data by 16-bit DID. | ||
| - | The **identification block** (DIDs '' | + | The **identification block** (DIDs '' |
| - | (an '' | + | '' |
| - | from one ECU: part '' | + | Example |
| + | these across all 24 ECUs builds a full part-number / build map of the car — no public Aiways ECU list | ||
| + | exists otherwise. | ||
| The **BMS (0x7E1)** carries a live measurement block around DIDs **'' | The **BMS (0x7E1)** carries a live measurement block around DIDs **'' | ||
| - | 120 aggregate battery values | + | **120 aggregate battery values**: pack voltage, current, cell voltages, SoC, temperatures, |
| + | words. This is where the numbers the head unit does //not// expose (cell min/max, temperatures, | ||
| + | state-of-health) should live. | ||
| ===== ⚠ Do not disturb the car while it is used ===== | ===== ⚠ Do not disturb the car while it is used ===== | ||
| - | A **broad scan** — sweeping many ECU addresses and forcing an **extended session** ('' | + | A **broad scan** — sweeping many ECU addresses and forcing an **extended session** ('' |
| - | makes ECUs **stop their normal CAN broadcasts**. The instrument cluster then flags the " | + | ECUs **stop their normal CAN broadcasts**. The instrument cluster then flags the " |
| - | modules with **warning icons**, and downstream | + | **warning icons**, and a downstream |
| - | saw the outside-temperature reading stick). It is **read-only and reverts** once probing stops, but: | + | outside-temperature reading stick). It is **read-only and reverts** once probing stops, but: |
| * **Never run a broad/ | * **Never run a broad/ | ||
| * Prefer the **gentle method**: functional discovery + **default-session reads only** (0x19 / 0x22), no session control. A single-ECU default-session read does not disturb the dash. | * Prefer the **gentle method**: functional discovery + **default-session reads only** (0x19 / 0x22), no session control. A single-ECU default-session read does not disturb the dash. | ||
| - | | + | |
| + | ===== The fault codes you will see ===== | ||
| + | |||
| + | The last two hex digits of a DTC are the standardised **failure-type byte**: **…88 = CAN Bus Off**, | ||
| + | **…87 = missing message / timeout**, **…82/83 = rolling-counter / checksum**. So a `U…87` / `U…88` | ||
| + | code means **"lost communication" | ||
| + | |||
| + | A consequence: | ||
| + | log "lost communication" | ||
| + | U-codes** (and contiguous B-/C-code ranges); these are **artifacts, self-clearing | ||
| + | cycles**. The codes worth attention are the **powertrain P-codes**, which point at real sensor / HV | ||
| + | faults. Read them all with 0x19 first, then judge. | ||
| + | |||
| + | ===== Battery management fault codes ===== | ||
| + | |||
| + | Manufacturer-specific codes (second character `1`, e.g. '' | ||
| + | |||
| + | ^ Code ^ Meaning ^ | ||
| + | | '' | ||
| + | | '' | ||
| + | | '' | ||
| + | | '' | ||
| + | | '' | ||
| + | | '' | ||
| + | | '' | ||
| + | | '' | ||
| + | | '' | ||
| + | | '' | ||
| + | | '' | ||
| + | | '' | ||
| + | | '' | ||
| + | | '' | ||
| + | | '' | ||
| + | | '' | ||
| + | | '' | ||
| + | | '' | ||
| + | | '' | ||
| + | | '' | ||
| + | | '' | ||
| + | | '' | ||
| + | | '' | ||
| + | | '' | ||
| + | | '' | ||
| + | | '' | ||
| + | | '' | ||
| + | | '' | ||
| + | | '' | ||
| + | | '' | ||
| + | | '' | ||
| + | | '' | ||
| + | | '' | ||
| + | | '' | ||
| + | | '' | ||
| + | | '' | ||
| + | | '' | ||
| + | | '' | ||
| + | | '' | ||
| + | | '' | ||
| + | | '' | ||
| + | | '' | ||
| + | | '' | ||
| + | | '' | ||
| + | |||
| + | Every code here clears automatically if absent for 40 drive cycles, or via a diagnostic tool. The standard repair escalation is: cross-check codes on other modules → inspect harness/ | ||
| + | |||
| + | By contrast, the **generic/ | ||
| + | |||
| + | Charging-system codes have also turned up, though only as bare identifiers so far (no definitions found yet): '' | ||
| + | |||
| + | Coverage note: a systematic search turned up fault-code documentation **only** for the battery-management codes above and this bare charging-system | ||
| ===== Decoding the raw values ===== | ===== Decoding the raw values ===== | ||
| There is no public scaling for the manufacturer DIDs, so raw values are decoded by **correlation** — | There is no public scaling for the manufacturer DIDs, so raw values are decoded by **correlation** — | ||
| - | read a DID while you know the true value from another source, and find the field + scale that match. | + | read a DID while you know the true value from another source |
| - | Confirmed | + | and find the field + scale that match. |
| + | a big HV load (A/C compressor) | ||
| - | * **Pack voltage** = DID **'' | + | Confirmed on the BMS (0x7E1) this way: |
| - | * **Pack current** = DID **'' | + | |
| - | State-of-charge and the 12 V system voltage have plausible candidates but are not yet nailed — | + | * **Pack voltage** = DID **'' |
| - | near-constant signals need the vehicle | + | * **Pack current** = DID **'' |
| - | and scale can be confirmed. A logger that records reference values and DIDs together across normal | + | |
| - | driving is the clean way to finish the map. | + | State-of-charge and the 12 V system voltage have plausible candidates but are **not yet nailed** — |
| + | near-constant signals need the car in **different states** (a drive, a charge) before their field and | ||
| + | scale can be confirmed. The decoded numbers sanity-check against the known pack spec (≈**268–417 V** | ||
| + | range, **24 modules**, cell **2.8–4.35 V**), so e.g. a '' | ||
| + | voltage. A logger that records reference values and DIDs together across normal driving is the clean way | ||
| + | to finish the map. | ||
| ===== Clearing fault codes ===== | ===== Clearing fault codes ===== | ||
| - | Clearing DTCs is the one " | + | Clearing DTCs is the one " |
| - | for repair). Two ways: | + | |
| - | * **Generic — Mode 04** ('' | + | * **Generic — Mode 04** ('' |
| * **Manufacturer — UDS service 0x14**: send '' | * **Manufacturer — UDS service 0x14**: send '' | ||
| - | Notes: clearing **masks real faults** (good and bad alike), so read the codes first. **Permanent | + | Notes: clearing **masks real faults** (good and bad alike) |
| - | DTCs** cannot be cleared by a tool — the ECU clears them itself after its readiness monitors pass. | + | cannot be cleared by a tool; the ECU clears them itself after its readiness monitors pass. A 12 V battery |
| - | A 12 V battery disconnect resets volatile display state but does **not** clear stored DTCs (they are | + | disconnect resets volatile display state but does **not** clear stored DTCs (non-volatile) — for that you |
| - | in non-volatile | + | need a clear command. |
| ===== Waking the car ===== | ===== Waking the car ===== | ||
| - | Diagnostic requests on this port **wake the gateway and addressed ECUs** for diagnostics (that is how | + | Diagnostic requests on this port **wake the gateway and addressed ECUs** for diagnostics (that is how a |
| - | a scan tool works on a parked car). That is a diagnostic wake only — it does **not** power up the HV | + | scan tool works on a parked car). That is a diagnostic wake only — it does **not** power up the HV |
| - | system, close the main contactors, or start climate. Those are actuation functions behind Security | + | system, close the main contactors, or start climate. Those are actuation functions behind Security |
| - | Access (below). | + | |
| + | ===== What is locked — and the one interesting exception ===== | ||
| + | |||
| + | Everything that **changes or actuates** — writing configuration (0x2E), actuator tests (0x2F), routines | ||
| + | (0x31), ECU reset (0x11), flashing (0x34/ | ||
| + | answers a **seed** request, but the **key algorithm is an OEM secret** that is not public for this car. So | ||
| + | in practice **OBD-II here is read-only**: | ||
| + | |||
| + | **The interesting exception: | ||
| + | **security-gated routine (0x31)** over this **same diagnostic CAN**. So the diagnostic port is not | ||
| + | architecturally a dead end for control — with the correct Security-Access key, **remote preconditioning | ||
| + | could in principle be commanded straight over OBD-II**, no internal-bus tap required. The key is the | ||
| + | missing piece (see [[roadmap]]). | ||
| + | |||
| + | ===== It is all standard ===== | ||
| - | ===== What is locked ===== | + | Under the hood this is plain **UDS (ISO 14229)** over **ISO-TP (ISO 15765-2)** on 500 k / 11-bit CAN — |
| + | nothing proprietary at the wire level. That means standard open tools work: a small ISO-TP + UDS client in | ||
| + | Python, or off-the-shelf car-diagnostic tools, will talk to this car. What is //not// open is the | ||
| + | **data dictionary** (which DID means what, with what scaling) and the **Security-Access key** — both live | ||
| + | in the manufacturer' | ||
| - | Everything that **changes or actuates** — writing configuration (0x2E), actuator tests (0x2F), | + | ===== Wiring & tools ===== |
| - | routines (0x31), ECU reset (0x11), flashing (0x34/ | + | |
| - | (0x27)**. The gateway answers a seed request but the **key algorithm is an OEM secret** that is not | + | |
| - | public for this car. So in practice **OBD-II here is read-only**: | + | |
| - | ===== Tools ===== | + | A **CANable-class USB-CAN adapter** (gs_usb) on **500 k / 11-bit**, driven from Python (raw frames + a |
| + | small ISO-TP layer for multi-frame UDS). | ||
| - | A **CANable-class USB-CAN adapter** (gs_usb) on 500 k / 11-bit, driven from Python ('' | + | |
| - | style: raw frames + a small ISO-TP layer for multi-frame UDS). Set the adapter to **Boot OFF, R120 | + | * Adapter DIPs: **Boot OFF** (run), **R120 OFF** (the OBD-II bus is already terminated |
| - | OFF** (the OBD-II bus is already terminated). Confirm wiring by watching the TX **and** RX LEDs blink | + | * Confirm wiring by watching the adapter' |
| - | during an active probe. | + | |
obd2.1786291309.txt.gz · Last modified: by 127.0.0.1