BMW I/K-Bus interface design brief (ESP32, optocoupler isolated)
Optocoupler-based design from muki01/I-K_Bus for BMW E-series I-Bus/K-Bus communication. Includes protocol spec (9600 8E1, XOR checksum, multi-master contention), module address map, E46 command codes, IbusSerial library architecture, and comparison with OBD-II K-line (Tucker project).
This commit is contained in:
commit
5d87dc2cac
285
CLAUDE.md
Normal file
285
CLAUDE.md
Normal file
@ -0,0 +1,285 @@
|
||||
# BMW I-Bus / K-Bus Interface Board (ESP32, Optocoupler Isolated)
|
||||
|
||||
## Attribution
|
||||
|
||||
Circuit design and protocol library based on **[muki01/I-K_Bus](https://github.com/muki01/I-K_Bus)** by [@muki01](https://github.com/muki01), licensed under MIT. Optocoupler schematic, IbusSerial library, E46 command codes, and bus documentation are from that project.
|
||||
|
||||
## Project Overview
|
||||
|
||||
Interface board for BMW I-Bus (Instrumentation Bus) and K-Bus (Body Bus) communication. Uses an ESP32 with PC817 optocouplers for galvanic isolation from the vehicle's electrical system.
|
||||
|
||||
**This is NOT the same as OBD-II K-line.** The Tucker project (`~/claude/tucker/k-line-board/`) handles ISO 9141/14230 OBD diagnostics using a transistor-based interface. This project targets BMW's proprietary body/instrumentation bus for module control (lights, windows, locks, multimedia).
|
||||
|
||||
### Protocol Comparison: BMW I/K-Bus vs OBD-II K-line
|
||||
|
||||
| Parameter | BMW I/K-Bus (this project) | OBD-II K-line (Tucker) |
|
||||
|-----------|---------------------------|----------------------|
|
||||
| **Baud rate** | 9600 | 10400 |
|
||||
| **Framing** | 8E1 (even parity) | 8N1 (no parity) |
|
||||
| **Bus topology** | Multi-master (any module can talk) | Master/slave (tester initiates) |
|
||||
| **Checksum** | XOR of all bytes | Additive sum mod 256 |
|
||||
| **Init sequence** | None (always-on bus) | 5-baud wake-up or fast init pulse |
|
||||
| **Message format** | Source + Length + Dest + Data + XOR | Header + Source + Mode + PID + Sum |
|
||||
| **Idle detection** | ~1.5ms bus quiet before TX | 5.5s quiet before init |
|
||||
| **Isolation needed** | Yes (multi-master, risk to bus) | Nice to have (point-to-point) |
|
||||
| **Vehicles** | BMW E31/E38/E39/E46/E53/E83/E85/E87 | Ford and other ISO 9141/14230 |
|
||||
|
||||
### Why Different Hardware
|
||||
|
||||
The transistor circuit (Tucker) shares ground with the car and directly drives the K-line. Fine for OBD-II because it's a dedicated diagnostic port — the tester is the only external device, and the ECU expects it.
|
||||
|
||||
BMW I/K-Bus is a live multi-master network with dozens of modules (GM5, IKE, LCM, RAD, MFL, DSP, etc.) all communicating constantly. Injecting signals requires:
|
||||
1. **Galvanic isolation** — a ground fault from your board can't propagate to the entire bus network
|
||||
2. **Bus contention awareness** — you must listen for 1.5ms of silence before transmitting
|
||||
3. **Proper framing** — even parity, XOR checksum, valid source/destination addresses
|
||||
|
||||
The optocoupler design satisfies requirement #1. The IbusSerial library handles #2 and #3.
|
||||
|
||||
## Circuit Design — Optocoupler Interface
|
||||
|
||||
Reference image: `reference/muki01-optocoupler-schematic.png`
|
||||
Alternative (non-isolated): `reference/muki01-transistor-schematic.png`
|
||||
|
||||
### Schematic Components
|
||||
|
||||
```
|
||||
I/K-Bus Side (12V) MCU Side (3.3V/5V)
|
||||
================== ====================
|
||||
|
||||
12V ────── D1 (1N4007) ──────────────── 12V (to regulator)
|
||||
(reverse protection)
|
||||
|
||||
I/K-Bus ─── R1 (2k) ──→ U1 pin 1 U1 pin 4 ←── 5V/3.3V
|
||||
(LED anode) (PC817) (collector)
|
||||
GND ←── U1 pin 2 U1 pin 3 ──→ RX_Pin
|
||||
(LED cathode) (emitter)
|
||||
R4 (1k) pull-down to GND
|
||||
|
||||
┊ photons ┊
|
||||
|
||||
I/K-Bus ←── U2 pin 4 U2 pin 1 ←── R2 (470)
|
||||
(collector) (LED anode) │
|
||||
U2 pin 3 U2 pin 2 ←── Q1 collector (BC547)
|
||||
(emitter) (LED cathode)
|
||||
│ Q1 base ←── R3 (10k) ←── R5 (470) ←── TX_Pin
|
||||
GND Q1 emitter ──→ GND
|
||||
```
|
||||
|
||||
### RX Path (Bus -> MCU via U1)
|
||||
|
||||
- Bus HIGH (12V idle): Current = (12V - 1.2V_LED) / 2k = **5.4mA** through U1 LED
|
||||
- PC817 CTR (Current Transfer Ratio) >= 50% at 5mA -> phototransistor saturates
|
||||
- U1 emitter (pin 3) pulled toward collector voltage (VCC) -> RX = HIGH
|
||||
- Bus LOW (module transmitting): No LED current -> phototransistor OFF -> RX pulled LOW by R4
|
||||
|
||||
**Signal inversion:** Bus HIGH -> RX HIGH, Bus LOW -> RX LOW. Polarity is preserved because the emitter-follower config doesn't invert.
|
||||
|
||||
### TX Path (MCU -> Bus via U2 + Q1)
|
||||
|
||||
- TX HIGH (idle): Through R5 (470) + R3 (10k) -> Q1 base driven -> Q1 ON -> current through U2 LED via R2 (470) -> U2 phototransistor ON -> pulls bus node LOW
|
||||
- TX LOW (transmitting): Q1 OFF -> U2 LED OFF -> phototransistor OFF -> bus released (goes HIGH via bus pull-up)
|
||||
|
||||
**Signal inversion:** TX HIGH -> bus LOW. This inverts the UART signal. The software must account for this, or use `SoftwareSerial` with inverted logic, or the bus idle state interpretation handles it. The muki01 library is written for this hardware — it works as-is.
|
||||
|
||||
### D1 (1N4007) Purpose
|
||||
|
||||
Bridges the bus-side 12V to the MCU-side 12V rail. This powers the MCU (via a 3.3V regulator) from the car battery while maintaining signal isolation through the optocouplers. The diode blocks reverse current if the MCU has its own power source (USB during development).
|
||||
|
||||
## Bill of Materials
|
||||
|
||||
| Ref | Value | Package | Qty | Notes |
|
||||
|-----|-------|---------|-----|-------|
|
||||
| U1, U2 | PC817 | DIP-4 | 2 | Optocoupler, CTR >= 50% at 5mA |
|
||||
| Q1 | BC547 | TO-92 | 1 | Or 2N3904 — TX LED driver |
|
||||
| R1 | 2k | 0805/TH | 1 | RX LED current limiter |
|
||||
| R2 | 470 | 0805/TH | 1 | TX LED current limiter |
|
||||
| R3 | 10k | 0805/TH | 1 | Q1 base resistor |
|
||||
| R4 | 1k | 0805/TH | 1 | RX pull-down (defines LOW when opto OFF) |
|
||||
| R5 | 470 | 0805/TH | 1 | TX input series resistor |
|
||||
| D1 | 1N4007 | DO-41 | 1 | Reverse polarity protection, 12V bridge |
|
||||
| U3 | ESP32-C3 | Module | 1 | Any ESP32 with hardware UART |
|
||||
| J1 | OBD-II / roundel | — | 1 | Or direct wire to CD changer connector |
|
||||
|
||||
**Optional for permanent install:**
|
||||
- AMS1117-3.3 or MP1584 buck: 12V -> 3.3V for ESP32
|
||||
- 10uF + 100nF ceramic caps on 3.3V rail
|
||||
- TVS diode (SMBJ16A) on bus line
|
||||
- Status LED on spare GPIO (NOT in signal path)
|
||||
|
||||
## ESP32 Pin Assignments
|
||||
|
||||
| Function | GPIO | UART | Notes |
|
||||
|----------|------|------|-------|
|
||||
| I/K-Bus TX | GPIO 17 | UART1 TX | Through R5 -> R3 -> Q1 -> U2 |
|
||||
| I/K-Bus RX | GPIO 16 | UART1 RX | From U1 emitter (pin 3) |
|
||||
| Debug TX | GPIO 1 | UART0 TX | USB serial monitor |
|
||||
| Debug RX | GPIO 3 | UART0 RX | USB serial monitor |
|
||||
| Status LED | GPIO 2 | — | Activity indicator |
|
||||
|
||||
UART config: `Serial1.begin(9600, SERIAL_8E1, RX_PIN, TX_PIN);`
|
||||
|
||||
## BMW I-Bus / K-Bus Protocol
|
||||
|
||||
### Message Format
|
||||
|
||||
```
|
||||
Byte 0: Source address (which module sent this)
|
||||
Byte 1: Length (count of remaining bytes: dest + data + checksum)
|
||||
Byte 2: Destination address (target module, 0xBF = broadcast)
|
||||
Byte 3: Command type
|
||||
Byte 4+: Data field(s)
|
||||
Last: Checksum (XOR of all preceding bytes)
|
||||
```
|
||||
|
||||
**Example:** `50 04 68 32 11 1F` (steering wheel volume up)
|
||||
- `0x50` = MFL (Multi-Function steering wheel)
|
||||
- `0x04` = 4 bytes follow
|
||||
- `0x68` = RAD (radio)
|
||||
- `0x32` = volume control command
|
||||
- `0x11` = volume up
|
||||
- `0x1F` = XOR checksum (50 ^ 04 ^ 68 ^ 32 ^ 11 = 1F)
|
||||
|
||||
### Module Address Map
|
||||
|
||||
| Addr | ID | Module |
|
||||
|------|-----|--------|
|
||||
| `0x00` | GM5 | Body control module |
|
||||
| `0x18` | CDC | CD Changer |
|
||||
| `0x3F` | DIA | Diagnostic computer |
|
||||
| `0x44` | EWS | Immobilizer |
|
||||
| `0x50` | MFL | Steering wheel controls |
|
||||
| `0x5B` | IHKA | Climate control |
|
||||
| `0x68` | RAD | Radio |
|
||||
| `0x6A` | DSP | Digital Sound Processor |
|
||||
| `0x80` | IKE | Instrument cluster |
|
||||
| `0xB0` | SES | Speed-dependent volume |
|
||||
| `0xBF` | ALL | Broadcast |
|
||||
| `0xC8` | TEL | Telephone |
|
||||
| `0xD0` | LCM | Light Control Module |
|
||||
| `0xE7` | ANZV | Display (phone status) |
|
||||
| `0xE8` | RLS | Rain/Light Sensor |
|
||||
| `0xFF` | LOC | Local (post-reset broadcast) |
|
||||
|
||||
### Bus Contention Protocol
|
||||
|
||||
BMW I/K-Bus is multi-master. Before transmitting:
|
||||
1. Monitor bus for activity (SEN/STA pin on TH3122, or RX line with optocoupler)
|
||||
2. Wait for **1.5ms of bus silence** (no transitions)
|
||||
3. Only then begin transmitting
|
||||
4. Maintain **10ms minimum gap** between your own packets
|
||||
5. If bus activity detected during your transmission, back off and retry
|
||||
|
||||
The muki01 IbusSerial library uses AVR Timer2 in CTC mode (OCR2A=94, prescaler=256) to time the 1.5ms idle window. For ESP32, this needs porting to a hardware timer or `esp_timer`.
|
||||
|
||||
### Supported BMW Models
|
||||
|
||||
| Chassis | Series | Years | I-Bus | K-Bus |
|
||||
|---------|--------|-------|-------|-------|
|
||||
| E31 | 8 Series | 1989-1999 | Yes | — |
|
||||
| E38 | 7 Series | 1999-2001 | Yes | Yes |
|
||||
| E39 | 5 Series | 1995-2004 | Yes | Yes |
|
||||
| E46 | 3 Series | 1997-2006 | — | Yes |
|
||||
| E52 | Z8 | 2000-2003 | — | Yes |
|
||||
| E53 | X5 | 1999-2006 | Yes | Yes |
|
||||
| E83 | X3 | 2003-2010 | — | Yes |
|
||||
| E85 | Z4 | 2002-2008 | — | Yes |
|
||||
| E87 | 1 Series | 2004-2013 | — | Yes |
|
||||
|
||||
### K-Bus Connection Points (E46)
|
||||
|
||||
1. **CD Changer Connector** (trunk, driver's side) — Connector X18180
|
||||
- K-Bus wire: White/Red with Yellow dots
|
||||
- Ground: Brown
|
||||
- 12V: Red/Green
|
||||
2. **K-Bus junction block** (above fuse box)
|
||||
- K-Bus wire: White/Red with Yellow dots
|
||||
- 12V and GND from a separate source
|
||||
|
||||
## Software Reference
|
||||
|
||||
### Primary: muki01/I-K_Bus
|
||||
|
||||
Repository: https://github.com/muki01/I-K_Bus
|
||||
|
||||
**Library files** (`I-K Bus Library/`):
|
||||
- `IbusSerial.h` / `IbusSerial.cpp` — State machine protocol handler (FIND_SOURCE -> FIND_LENGTH -> FIND_MESSAGE -> checksum validation), ring buffers for RX (128 bytes) and TX (64 bytes), bus contention timer, sleep management
|
||||
- `RingBuffer.h` / `RingBuffer.cpp` — Circular buffer implementation for async message handling
|
||||
|
||||
**Example code** (`Codes/`):
|
||||
- `Basic_Code/Basic_Code.ino` — Minimal sniffer: prints all bus traffic via debug serial
|
||||
- `E46_KBus_Code/E46_KBus_Code.ino` — E46-specific: goodbye lights on lock, follow-me-home on double-lock, park lights on unlock
|
||||
- `E46_KBus_Code/E46_Codes.h` — Complete command table: lighting (22 commands), windows (8), door locks (6), trunk (3), wipers (2), interior lighting (4), instrument cluster (4), remote (3), ignition (6), MFL (7), CD control (7), DSP (12), telephone (4), and more
|
||||
|
||||
### Porting to ESP32
|
||||
|
||||
The IbusSerial library targets AVR (Arduino Nano) with:
|
||||
- `HardwareSerial` at 9600 8E1 for bus communication
|
||||
- `SoftwareSerial` on pins 7/8 for debug
|
||||
- AVR Timer2 CTC for 1.5ms bus idle detection
|
||||
- `digitalPinToInterrupt(3)` for SEN/STA pin change
|
||||
|
||||
For ESP32 port, replace:
|
||||
- Timer2 -> `esp_timer_create()` or `hw_timer_t`
|
||||
- SoftwareSerial -> hardware UART0 (USB) for debug
|
||||
- `PROGMEM` -> not needed (ESP32 flash is memory-mapped)
|
||||
- Pin interrupts -> `attachInterrupt()` works directly on any GPIO
|
||||
- Bus idle detection via RX pin interrupt + timer (no SEN/STA without TH3122)
|
||||
|
||||
### Alternative Hardware: Dedicated Transceiver ICs
|
||||
|
||||
The repo also documents three IC-based alternatives (schematics in `Schematics/`):
|
||||
- **TH3122.4 / ELMOS 10026B** — BMW's own bus transceiver, has SEN/STA pin for hardware contention detection, EN pin for sleep. The IbusSerial library was designed for this IC.
|
||||
- **MCP2025** — Microchip LIN bus transceiver, repurposed for I/K-Bus
|
||||
- **SN65HVDA195** — TI automotive K-line transceiver
|
||||
|
||||
## SPICE Simulation
|
||||
|
||||
The `mcp-ltspice` MCP server is available for circuit simulation. To validate the optocoupler design:
|
||||
|
||||
```
|
||||
# Key tools:
|
||||
mcp__mcp-ltspice__create_netlist(title, components, directives, output_path)
|
||||
mcp__mcp-ltspice__simulate_netlist(netlist_path) -> returns raw_file path
|
||||
mcp__mcp-ltspice__get_waveform(raw_file_path, signal_names, max_points)
|
||||
mcp__mcp-ltspice__analyze_waveform(raw_file_path, signal_name, analyses)
|
||||
```
|
||||
|
||||
**Not yet simulated.** The optocoupler circuit needs a PC817 SPICE model with CTR curve and switching time parameters. A generic model:
|
||||
```spice
|
||||
* PC817 optocoupler (simplified)
|
||||
* LED: forward voltage ~1.2V at 5mA
|
||||
* Phototransistor: CTR ~100% at 5mA, rise ~4us, fall ~3us
|
||||
```
|
||||
|
||||
The Tucker project's validated transistor netlist is at `~/claude/tucker/k-line-board/reference/kline_esp32_validated.cir` for comparison.
|
||||
|
||||
## Docs Archive
|
||||
|
||||
The repo includes an extensive documentation collection (`Docs/`):
|
||||
- **BMW BUS Information/** — 5 PDFs on BMW bus architecture
|
||||
- **BMW Communication Codes/** — 12 files with I-Bus message codes for E39/E46
|
||||
- **HackTheIBus/** — 21 PDFs covering individual module protocols (IKE, LCM, MFL, EWS, DSP, etc.)
|
||||
|
||||
## What's Been Done
|
||||
|
||||
1. Optocoupler schematic analyzed (RX path, TX path, isolation topology)
|
||||
2. Protocol differences documented (vs OBD-II K-line for Tucker project)
|
||||
3. Software reference identified (IbusSerial library, E46 command codes)
|
||||
4. Module address map and message format documented
|
||||
|
||||
## What's Next
|
||||
|
||||
1. **Simulate** optocoupler circuit with mcp-ltspice (need PC817 model)
|
||||
2. **Port IbusSerial** library to ESP32 (replace AVR Timer2, adapt pin config)
|
||||
3. **Breadboard** prototype with PC817 + BC547 + ESP32
|
||||
4. **Test** on BMW E46 K-Bus (CD changer connector in trunk)
|
||||
5. **Build** command library for target features (lights, locks, windows)
|
||||
|
||||
## Safety Notes
|
||||
|
||||
- BMW I/K-Bus is a **live vehicle control network**. Malformed messages can trigger unintended behavior (lights, locks, wipers).
|
||||
- Always test with ignition OFF or key position 1 (accessories) first.
|
||||
- The optocoupler isolation protects the ESP32 from the car AND the car from the ESP32.
|
||||
- Sniff bus traffic (RX only) before attempting any TX operations.
|
||||
- The bus has no authentication — any properly formatted message will be accepted by target modules. Use responsibly.
|
||||
- Parasitic drain: the interface draws ~6mA from the bus 12V through R1 and U2. Disconnect or add a sleep circuit for long-term parking.
|
||||
BIN
reference/muki01-optocoupler-schematic.png
Normal file
BIN
reference/muki01-optocoupler-schematic.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 78 KiB |
BIN
reference/muki01-transistor-schematic.png
Normal file
BIN
reference/muki01-transistor-schematic.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 100 KiB |
Loading…
x
Reference in New Issue
Block a user