Skip to content

Instantly share code, notes, and snippets.

@Lillecarl
Created July 13, 2026 10:26
Show Gist options
  • Select an option

  • Save Lillecarl/3c6853bb17958627dae4aeb44dfb28f6 to your computer and use it in GitHub Desktop.

Select an option

Save Lillecarl/3c6853bb17958627dae4aeb44dfb28f6 to your computer and use it in GitHub Desktop.
# Volvo P2 DIM (Driver Information Module) CAN Protocol Reference
Decoded from [VolvoDIMLib](https://github.com/agabler/VolvoDIMLib) — an Arduino library that reverse-engineers the P2 platform instrument cluster CAN bus.
**Platform:** Volvo P2 (S60, V70, XC70, S80, ~2000–2007)
**Bus speed:** 125 kbps
**CAN format:** 29-bit extended IDs
**Target:** Driver Information Module (instrument cluster)
---
## CAN Message IDs
| # | Hex ID | Decimal ID | Description |
|---|--------|------------|-------------|
| 0 | `0x217FFC` | 2197500 | Speed value, odometer mileage, keep-alive heartbeat |
| 1 | `0x2803008` | 2621448 | RPM (tachometer), backlight brightness |
| 2 | `0x3C01428` | 6296680 | Coolant temperature gauge, outdoor temperature display |
| 3 | `0x381526C` | 5882476 | Clock time, fuel/gas level gauge |
| 4 | `0x3600008` | 5672968 | Brake system keep-alive |
| 5 | `0xA10408` | 10552328 | Turn signal indicators (left/right/hazard) |
| 6 | `0x2006428` | 3359784 | Anti-skid / traction control warning light |
| 7 | `0x1A0600A` | 27262986 | SRS airbag warning light — requires init sequence |
| 8 | `0x2616CFC` | 3993852 | 4C active chassis keep-alive — prevents dash errors |
| 9 | `0x1017FFC` | 16875516 | Car equipment configuration (16 frames of option codes) |
| 10 | `0x3200408` | 5245960 | Gear position display + warning light states |
| 11 | `0x3E0004A` | 6488138 | Trailer attached indicator |
| 12 | `0x02A0240E` | 44084238 | DIM text window control |
| 13 | `0x1800008` | 25165832 | DIM custom text content (sent in 7-byte chunks) |
---
## Gauge Value Encoding
### Speed (`0x217FFC`)
| Item | Byte(s) | Encoding |
|------|---------|----------|
| Speed value | Byte 6 | `speed * 6.375` (0–160 km/h → 0–1020 range) |
| Scale quadrant | Byte 5 | `0x58` (0–40), `0x59` (40–80), `0x5A` (80–120), `0x5B` (120–160) |
| Odometer mileage | Byte 7 | Incremented counter, wraps at 255 |
### RPM / Tachometer (`0x2803008`)
| Item | Byte(s) | Encoding |
|------|---------|----------|
| RPM value | Byte 6 | `floor(rpm * 0.031875 / 32) * 32 + floor(rpm * 0.031875 / 8)` |
| Overhead brightness | Byte 2 | `0`–`255` |
| LCD brightness | Byte 4 | `0`–`63` (input 0–256 is divided by 32; values >250 clamp to `0x3F`) |
### Coolant Temperature (`0x3C01428`)
| Item | Byte(s) | Encoding |
|------|---------|----------|
| Coolant temp | Byte 3 | 0°C → `88` (0x58), 55°C → `143` (0x8F), 100°C → `173` (0xAD) |
| Outdoor temp range | Byte 4 | `0x0D` (-49–32°F), `0x0E` (33–146°F), `0x0F` (147–176°F) |
| Outdoor temp value | Byte 5 | Scale factor ~2.2× depending on range |
### Fuel Level (`0x381526C`)
| Item | Byte(s) | Encoding |
|------|---------|----------|
| Fuel gauge | Bytes 6–7 | `level_percent * 0.64` (both bytes identical, 0–100% → 0–64) |
### Time (`0x381526C`)
| Item | Byte(s) | Encoding |
|------|---------|----------|
| Clock time | Bytes 4–5 | Minutes since midnight (0–1439 encoded as base-256: `byte4 = minutes / 256`, `byte5 = minutes % 256`) |
### Gear Position (`0x3200408`)
| Gear | Byte 4 (hex) | Byte 4 (decimal) | Byte 6 (hex) | Byte 6 (decimal) |
|------|-------------|-------------------|-------------|-------------------|
| L (Low) | `0x40` | 64 | `0x96` | 150 |
| P (Park) | `0x24` | 36 | `0x10` | 16 |
| R (Reverse) | `0xE4` | 228 | `0x20` | 32 |
| N (Neutral) | `0x24` | 36 | `0x30` | 48 |
| 1st | `0x34` | 52 | `0x40` | 64 |
| 2nd | `0x40` | 64 | `0x70` | 112 |
| 3rd | `0x40` | 64 | `0x60` | 96 |
| 4th | `0x44` | 68 | `0x50` | 80 |
| 5th | `0xBE` | 190 | `0x00` | 0 |
| 6th | `0xD5` | 213 | `0x00` | 0 |
| None (blank) | `0x10` | 16 | `0x40` | 64 |
---
## Warning / Indicator Lights
All on **byte 3** of CAN message `0x3200408` (gear position message).
| Light | Hex | Decimal | Description |
|-------|-----|---------|-------------|
| Engine service required | `0x10` | 16 | Orange engine warning |
| Reduced brake performance (orange) | `0x30` | 48 | Orange brake warning |
| Fuel filler cap loose | `0x40` | 64 | Loose/missing fuel cap |
| Slow down or shift up (orange) | `0x01` | 1 | Upshift or reduce speed |
| Reduced engine performance (orange) | `0x0E` | 14 | Orange engine performance limit |
| Engine system service urgent (red) | `0x90` | 144 | Red urgent engine fault |
| Brake performance reduced (red) | `0xAA` | 170 | Red brake system fault |
| Reduced engine performance (red) | `0xBB` | 187 | Red engine performance limit |
| Slow down or shift up (red) | `0xDD` | 221 | Red upshift warning |
---
## Turn Signal States
On **byte 7** of CAN message `0xA10408`.
| State | Hex | Decimal |
|-------|-----|---------|
| Off | `0x00` | 0 |
| Left blinker on | `0x0A` | 10 |
| Right blinker on | `0x0C` | 12 |
| Hazard (both) | `0x0E` | 14 |
---
## Trailer Attached
On `0x3E0004A`, bytes 4–5.
| State | Byte 4 | Byte 4 (dec) | Byte 5 | Byte 5 (dec) |
|-------|--------|--------------|--------|--------------|
| Not attached | `0x1D` | 29 | `0xE0` | 224 |
| Attached | `0x11` | 17 | `0xE4` | 228 |
---
## Custom Text (DIM Message Display)
Displaying custom text on the DIM's message screen requires sending to two CAN IDs:
1. **Priming the window** (`0x02A0240E`):
- Set byte 7 to `0x31` (49 decimal)
- Send to open/activate the text display area
2. **Sending the content** (`0x1800008`):
- Text is sent in up to 5 frames, each carrying 7 bytes
- Frame 1: byte 0 = `0xA7` (167), bytes 2–7 = first 6 chars
- Frames 2–5: byte 0 = `0x21` through `0x24` (33–36), bytes 1–7 = 7 chars each
- Max message length: 32 characters
3. **Closing** (`0x1800008`):
- Final frame: byte 0 = `0x65` (101), remaining bytes = spaces
---
## Initialization Sequences
### SRS / Airbag Light (`0x1A0600A`)
Four messages must be sent on startup to initialize the airbag module and clear the warning light:
| Step | Byte 0 | Byte 6 | Delay |
|------|--------|--------|-------|
| 1 | `0xC0` (192) | `0xDB` (219) | 15 ms |
| 2 | `0x00` (0) | unchanged | 15 ms |
| 3 | `0xC0` (192) | `0xC9` (201) | 15 ms |
| 4 | `0x80` (128) | unchanged | — |
### 4C Active Chassis (`0x2616CFC`)
Four messages prevent "Chassis settings service urgent" popups:
| Step | Byte 0 | Delay |
|------|--------|-------|
| 1 | `0x09` (9) | 15 ms |
| 2 | `0x09` (9) | 15 ms |
| 3 | `0x0B` (11) | 15 ms |
| 4 | `0x0B` (11) | — |
---
## Default CAN Frame Data (Raw)
The 8-byte default payloads the library sends for each message:
| # | CAN ID | Bytes 0–7 (hex) |
|---|--------|-----------------|
| 0 | `0x217FFC` | `01 EB 00 D8 F0 58 00 00` |
| 1 | `0x2803008` | `FF E1 FF F0 FF CF 00 00` |
| 2 | `0x3C01428` | `C0 80 51 89 0E 00 00 00` |
| 3 | `0x381526C` | `00 01 05 BC 05 A0 40 40` |
| 4 | `0x3600008` | `00 00 B0 60 30 00 00 00` |
| 5 | `0xA10408` | `00 00 00 00 00 00 00 00` |
| 6 | `0x2006428` | `01 E3 E0 00 00 00 00 00` |
| 7 | `0x1A0600A` | `00 00 00 00 00 BE 49 00` |
| 8 | `0x2616CFC` | `0B 42 00 00 FD 1F 00 FF` |
| 9 | `0x1017FFC` | `01 0F F7 FA 00 00 00 C0` |
| 10 | `0x3200408` | `11 DE 53 00 24 00 10 00` |
| 11 | `0x3E0004A` | `00 00 00 00 1D E0 00 00` |
| 12 | `0x02A0240E` | `C0 00 00 00 00 00 00 35` |
| 13 | `0x1800008` | `00 00 00 00 00 00 00 00` |
---
## Practical Notes for Sniffing & Replay
- The DIM **powers down** if it doesn't receive keep-alive messages on `0x217FFC` and `0x3600008` at regular intervals
- All messages are cycled through in a round-robin loop at ~15ms intervals. If running on an Arduino, the whole 14-message cycle takes roughly 200–250ms
- The car config at `0x1017FFC` is car-specific. The 16 frames in this library were captured from a 2007 S60R with M66 manual transmission, climate package, and rear parking sensors but no navigation. Your car will have different option bytes
- The SRS light will stay on permanently if the 4-step init sequence is not sent at startup
- The 4C suspension message prevents "Chassis settings service urgent" — cars without Four-C may not need this
- Ding/chime sounds are controlled by byte 1 of `0x381526C`: `0x30` (48) disables, `0x18` (24) enables
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment