CAN bus
Hardware level
CAN bus (Controller Area Network)
- CAN 2.0 - common spec
- differential-pair signal
- shared bus for all devices, prioritization by address field bits
- asynchronous, clock syncing by signal edge
- address arbitration: dominant bit wins
bit transmitting: 1 ("dominant", "L" on input) pulls line from idle state, 0 ("recessive", "H", or inactive) leaves it idle/undriven
- low-speed CAN - up to 125 kbit/s
- ISO 11898-3
- fault-tolerant
- each node terminated separately, total termination should add up (parallel) to 100 ohms
- CANH pulled down to GND, CANL pulled up to 5V
- active bit transmit when CANH pulled to H, CANL to L
- high-speed CAN - up to 1 Mbit/s (CAN) or 5 Mbit/s (CAN-FD)
- ISO 11898-2
- 120-ohm termination on both ends of bus
- inactive state, both lines at 2.5V
- transmitting 1 ("L" on input): Can Hi goes up, Can Lo goes down - differential voltage
- transmitting 0 ("H" on input): inactive state
- message-based protocol
- message has ID and payload
- 11-bit ID for CAN 2.0A
- 29-bit ID for CAN 2.0B
- 11-bit ID, "base id", + 18-bit "identifier extension"
packet format
arbitration field
- start-bit: always 0, then ID with LSB-first
- identifier: 11 bits
- RTR, Remote Transmission Request: 1 bit; dominant for data frame, recessive for 29-bit address or request frame (called SRR then, Substitute Remote Request)
control field
- IDE, Identifier Extension: 1bit; dominant for 11-bit, recessive for 29-bit
- if 29-bit: identifier extension, 18 bits
- if 29-bit: RTR, Remote Transmission Request: 1 bit; dominant for data frame, recessive for request frame
- if 29-bit: R1, reserved bit; set dominant
- R0, reserved bit; set dominant
- DLC, Data Length Code, 4 bit; payload length, 0..8 bytes; for Remote Frame it indicates the length of message expected
data field
- data bytes, 8x DLC bits (or none for Remote Frame)
CRC field
- CRC, cyclic redundancy check: 15 bits
- CRC delimiter, 1 bit, recessive
end of frame
- ACK slot: 1 bit, transmitted recessive, recipient can set dominant to signal reception
- ACK slot delimiter: 1 bit, recessive
- EOF, 7 bits, recessive (interframe padding)
bit stuffing
except CRC-delimiter, ACK slot and and end-of-frame sequence, bit stuffing is used to prevent too long sequences without an edge
- after 5 bits of the same value, sixth bit of opposite value is inserted into stream by sender and thrown away by the receiver
- in UART streams this role is played by start/stop bits
- count applies to such inserted bits too
- examples:
- hhhhhhhh -> hhhhhLhhh
- hhhhllll -> no stuffing
- hhhhhlll -> hhhhhLlll
- hhhhhllllhhhhh -> hhhhhLllllHhhhhLh
- hhhhhllllhhhhllll -> hhhhhLllllHhhhhLllllH
- six consecutive bits of the same value == error
- six dominant bits in sequence = error packet
- prone to bit errors on the bus
-
remote frame:
- for requesting data from source
- DLC set to length of message requested
- DATA field zero-lenght
CAN FD - Flexible Data
- protocol variant, with flexible data rates in payload, larger payload
- 29 bit ID (can handle 11bit), 64-byte payload
- 5x faster speed
- compatible with CAN2.0 buses
- lower capacitance budget
Protocol level - SAE J1939
SAE J1939, http://read.pudn.com/downloads344/ebook/1503048/A%20Comprehensible%20Guide%20to%20J1939.pdf
- specification for comm/diag for vehicle components
- usually CAN bus, CAN 2.0B (29-bit IDs)
- typically 250 kbps, recently also 500 kbps
J1939 specs
- J1939/1x - physical
- J1939/2x - data link
- J1939/3x - network
- J1939/4x - transport
- J1939/5x - session
- J1939/6x - presentation
- J1939/7x - application
PGN - Parameter Group Numbers
- 18-bit, part of the 29-bit ID of CAN2.0B
- starts on 9th bit (9..27)
- eg. message with ID 0x0CF00401, PGN=0x0F004
ID format with PGN:
- priority, 3-bit
- PGN, 18-bit
- reserved (ext.data page), 1bit - usually 0, further extension of PDU space
- data page, 1bit - usually 0, can be used to double the capacity of PDU space
- PF, PDU format, 8bit
- 0x00..0xEF - PDU1 - destination specific (can also be sent to 0xFF, broadcast); PS=destination address, used for peer-to-peer comm; 0x00.. to 0xEF..
- 0x00..0xEE - SAE-assigned
- 0xEF - mfg-assigned
- 0xF0..0xFF - PDU2 - broadcasts; PS=group extension, used for broadcasts; 0xF000..0xFFFF
- 0xF000..0xFEFF - SAE-assigned
- 0xFF00..0xFFFF - mfg-assigned
- 0xFF - global destination, for broadcasts
- PS, PDU-specific, 8bit
- source addr, 8bit
hex format:
- as right-aligned 32bit number
- 0x0000-0000 to 0x1FFF-FFFF
- 0x....-..XX - source address
- 0x....-XX.. - PGN:PS, parameter-specific
- 0x..XX-.... - PGN:PF, parameter-format
- 0x.0..-.... to 0x.3..-.... - data page, ext data page
- 0x00..-.... to 0x1C..-.... - priority (the lower number the higher prio - zero wins in arbitration)
- sometimes also additional 3-bit external bus ID:
- 0x0...-.... to 0xE...-.... - which CAN bus it is (part of some "whole" PGNs, not sent in the ID)
SPN - Suspect Parameter Number
- message payload
- defines a signal (parameter value) within a message with a given PGN
- bit start/length, scaling, offset, unit
- some are standardized, most are vehicle/vendor specific
- typically described by DBC files
payload
- for PDU1 format (0x00..0xEF), 0 to 1785 bytes (multipacket)
- for PDU2 format, 0 to 8 bytes
multipacket
- send BAM, Broadcast Announcement Message (PGN=60416, 0xEC00, Transport Protocol-Connection Management, TP.CM)
- with PGN of the multipacket msg, size, number of packages
- payload in PGN=60160 (0xEB00, Data Transfer)
other common protocols
- J1939-based
- J1939/ISO11783 (agricultural machines)
- MilCAN (military applications)
- NMEA 2000 (marine)
- J1708/J1587 (another kind of a vehicle network)
- LIN bus - cheap lower-speed less-mission-critical messages (broadcast network, 1 master, up to 15 slaves)
- ARINC 429 - aircraft, 32-bit messages
common CAN-based protocols
- SAE J1939 - heavy vehicles
- ISOBUS/ISO 11783 - agricultural vehicles, J1939 flavor
- MilCAN - military vehicles
- NMEA 2000 - marine industry; smaller version (micro/thin) with 5-pin M12 connector
- SAE J2284 - passenger cars
- Unified Diagnostic Services (UDS) - ISO 14229 - automotive diag
- CANopen - CiA 301/302-2, EN 50325-4 - industrial automation
- EnergyBus - battery charging bus, implements CANopen as CiA CiA-454
- ISO-TP - ISO 15765-2 (transport protocol for automotive diagnostics)
- DeviceNet - industrial automation, based on Common Industrial Protocol; 11-bit IDs, CAN 2.0A
-
Field definitions
DBC files
- usually format J1939 PG (ext. ID)
https://medium.com/@energee/what-are-dbc-files-469a3bf9b04b
EDS files
for CANopen
OBD-II connector
vehicle (female):
__--^^.
/ |
9 | O| |O | 1
SAE J1850 bus - 10 | O| |O | 2 + SAE J1850 bus
11 | O| |O | 3
12 | O| |O | 4 GND chassis
13 | O| |O | 5 GND signal
ISO 15765-4 CANL 14 | O| |O | 6 CANH - ISO 15765-4
L-line 15 | O| |O | 7 K-line
+12V 16 | O| |O | 8
\ |
^^--__'
Pins 1,9,3,11,12,13,8 are used at manufacturer discretion:
- GM
- 1=J2411 GMLAN/SWC/Single-Wire CAN
- 9=8192 baud ALDL where fitted
- Ford (Argentina, Brazil (pre OBD-II) 1997–2000, USA, Europe, etc.)
- 3=DCL+
- 11=DCL-
- 13=FEPS - Programming PCM voltage
- Chrysler
- BMW
- 8=second K-line for non OBD-II (Body/Chassis/Infotainment) systems (many BMWs)
- 9=RPM signal
- Diagnostics over IP
- 3=Ethernet Tx+
- 8=Activate Ethernet
- 11=Ethernet Tx-
- 12=Ethernet Rx+
- 13=Ethernet Rx-
CAN
ISO 15765-4 - CANH/CANL
"K-line"
ISO 9141-2, ISO 14230 - K-line/L-line
- K-line and L-line form balanced pair
- L-line is optional
- K-line pulled up via 510 ohm to Vbatt, dominant bit signalled by open-collector pulldown
- UART signaling
- single bidirectional line
- 10.4 kbps rate (ISO 9141), or 1.2..10.4 kbps (ISO 14230, using KWP2000, Keyword Protocol 2000)
- messages up to 255 bytes payload
Computer interfaces
- SocketCAN - linux kernel CAN drivers, PF_CAN packets (cf. eg. PF_INET); candump shows traffic (cf. tcpdump)
- can4linux - linux kernel drivers, expose devices as /dev/canX
SocketCAN on raspi
sudo /sbin/ip link set can0 up type can bitrate 500000
...or, add to /etc/network/interfacesd/can0:
auto can0
iface can0 inet manual
pre-up /sbin/ip link set can0 type can bitrate 500000 triple-sampling on restart-ms 100
up /sbin/ifconfig can0 up
down /sbin/ifconfig can0 down
ELM327 on raspi
ELM327 is a microcontroller interface for the OBD-II port on not-so-ancient cars.
On one side it communicates via several protocols. On the other there is a serial port.
Multiple ELM327 device flavors exist:
- RS232
- USB - usually with a common USB-serial adapter
- Bluetooth - usually uses a cheap Bluetooth-UART dongle
Raspberry Pi 3B, internal bluetooth used
caution: Raspi 3B's bluetooth module uses the same serial port as the serial console. Make sure the console is disabled.
if there are problems with bluetooth, make sure the login terminal is not interfering; typically agetty is doing that.
Make sure there is no console=ttyAMA0,115200 in /boot/cmdline.txt
To /boot/config.txt put:
enable_uart=1
dtoverlay=pi3-miniuart-bt
Reboot and things should work like a charm.
dongle interface hacking thoughts
The ELM327 chip that gives the dongle its name has a plain UART output. The conversion to USB or Bluetooth is handled by another chip.
It should be possible to tap the circuitboard and mix and match interfaces as needed, without having to source a different dongle
for each interface.
dongle LEDs
- power (red) - 12V present
- Tx OBD (yellow) - data sent to vehicle
- Rx OBD (green) - data received from vehicle
- Tx computer (yellow): - data sent from computer
- Rx computer (green): - data sent to computer
dongle bluetooth parameters
info via bluetoothctl:
[bluetooth]# info 00:00:00:33:33:33
Device 00:00:00:33:33:33 (public)
Name: OBDII
Alias: OBDII
Class: 0x00001f00
Paired: no
Trusted: no
Blocked: no
Connected: no
LegacyPairing: no
UUID: PnP Information (00001200-0000-1000-8000-00805f9b34fb)
UUID: L2CAP (00000100-0000-1000-8000-00805f9b34fb)
UUID: SDP (00000001-0000-1000-8000-00805f9b34fb)
UUID: Serial Port (00001101-0000-1000-8000-00805f9b34fb)
UUID: RFCOMM (00000003-0000-1000-8000-00805f9b34fb)
RSSI: -70
connect
bt-device -c 00:00:00:33:33:33
Connecting to: 00:00:00:33:33:33
Device: OBDII (00:00:00:33:33:33)
Enter passkey: 1234
Done
attach
rfcomm bind /dev/rfcomm0 00:00:00:33:33:33
...voila, rfcomm0 appears in /dev
rfcomm0 is an ordinary serial communication device, through which the dongle operates.
access
run picocom
picocom /dev/rfcomm0
ATI
ELM327 v2.1
some dump during putzing with ELM
what the dongle apparently sent to the bus (protocol #7)
can0 0C08A7F0 [8] 00 7D 00 00 1A 27 93 31
can0 0C09A7F0 [8] 6E 37 38 38 1A 27 00 00
can0 0C09A7F0 [8] 6E 37 38 38 1A 27 00 00
can0 0C0BA7F0 [8] 78 2D F4 01 00 00 00 00
can0 0C19F0A7 [8] 00 7D FF FF FF FF C0 2C
can0 0C0BA7F0 [8] 78 2D F4 01 00 00 00 00
can0 0C19F0A7 [8] 00 7D FF FF FF FF C0 2C
can0 0C08A7F0 [8] 00 7D 00 00 1A 27 93 32
can0 0C08A7F0 [8] 00 7D 00 00 1A 27 93 32
can0 0C09A7F0 [8] 6E 37 38 38 1A 27 00 00
can0 0C09A7F0 [8] 6E 37 38 38 1A 27 00 00
AT commands
- ATI
- identify yourself == ELM327 v2.1
- AT@1
- show device description == OBDII to RS232 Interpreter
- ATE0/ATE1
- ATL0/ATL1
- ATD
- ATDP,ATDPN
- describe current protocol/get number of current protocol
- ATFE
- ATH0/ATH1
- headers off/on - show all data transmitted
- ATIGN
- ignition status (voltage at pin 15)
- ATCSM0/ATCSM1
- silent mode - send or not send ACK bits
- atcms0 - allows canplayer without "sendto: no buffer space available" error
- ATMA
- ATAL/ATNL
- allow long messages/force 7byte data limit
- ATR0/ATR1
- auto-receive of responses off/on
- ATRTR
- send Remote Frame CAN message (error?)
- ATRV
- ATS0/ATS1
- spaces in ECU responses hide/show
- ATSPx
- set protocol
- 1=SAE J1850 PWM (41.6 kbps)
- 2=SAE J1850 VPW (10.4 kbps)
- 3=ISO 9141-2 (5-baud init, 10.4 kbps)
- 4=ISO 14230-4 KWP (5-baud init, 10.4 kbps)
- 5=ISO 14230-4 KWP (fast init, 10.4 kbps)
- 6=ISO 15765-4 CAN (11 bit ID, 500 kbps)
- 7=ISO 15765-4 CAN (29 bit ID, 500 kbps)
- 8=ISO 15765-4 CAN (11 bit ID, 250 kbps)
- 9=ISO 15765-4 CAN (29 bit ID, 250 kbps)
- error: A=SAE J1939 CAN (29 bit ID, 250(default) kbps)
- error: B=USER1 CAN (11(default) bit ID, 125(default) kbps)
- error: C=USER2 CAN (11(default) bit ID, 50(default) kbps)
- ATWS/ATZ
- soft reset/complete reset
- ATV0/ATV1
- variable length data disabled/enabled
mode 03 request:
03
UNABLE TO CONNECT
on CAN:
can0 18DB33F1 [8] 01 03 00 00 00 00 00 00
can0 18DB33F1 [8] 01 03 00 00 00 00 00 00
mode 01 PID 01 request
01 01
UNABLE TO CONNECT
can0 18DB33F1 [8] 01 01 00 00 00 00 00 00
can0 18DB33F1 [8] 01 03 00 00 00 00 00 00
can0 18DB33F1 [8] 02 01 01 00 00 00 00 00
can0 18DB33F1 [8] 02 01 01 00 00 00 00 00
Tools
https://pypi.org/project/cantools/
- uses CAN bus via python-can (socketcan...)
- encodes/decodes messages, uses DBC files
- provides candecode for decoding candump output via dbc files
https://github.com/ebroecker/canmatrix
- Python; read/convert several CAN DB formats (dbc, arxml, dbf, kcd, sym, xls/xlsx, xml fibex)
https://github.com/linklayer/pyvit - Python Vehicle Interface Toolkit
https://github.com/brendan-w/python-OBD
https://github.com/Ircama/ELM327-emulator
- makes a virtual serial interface that behaves like ELM327 with attached car
https://github.com/zombieCraig/UDSim
- C++/C#, GUI, simulator of a vehicle on SocketCAN
https://github.com/cedricp/ddt4all
https://github.com/educampos28/OBD2_HACK
- python, configures ELM327 into monitor mode to listen on all traffic on the bus ("ATMA" command)
https://github.com/EricSmekens/node-bluetooth-obd
- node.js, ELM327/bluetooth
https://github.com/jgamblin/CarHackingTools
- collection of bash and python scripts and tools
Wireshark
- listeners/decoders can be written in LUA
- support for CAN packets (sometimes wrapped as payload in UDP, by default port 3333)
If you have any comments or questions about the topic, please let me know here: |