CS 452/652 Winter 2026 - Lecture 3
CAN bus and Märklin protocol
Jan 13, 2026 prev next
MCP - MCP2515 Data Sheet
MRK - Märklin CAN Protocol
Controller Area Network (CAN)
- network protocol and standard
- physical specifications (Layer 1)
- low bitrate → robust against electrical noise
- 10s kbit/s to 10s Mbit/s range, compare 100s Gbit/s in modern Ethernet
- bit-synchronous encoding and transmission
- medium access control and addressing (Layer 2)
- multi-leader serial bus: each participant autonomously decides to send
- collision detection and arbitration needed (cf. original Ethernet)
- message identifier instead of source/destination addressing
- priority encoding ensures realtime capabilities
- 0-bit is dominant → lower identity number wins arbitration
- message types
- data frame: regular data frame
- remote frame: request data (with priority of requested data)
- error frame: transmitted by any node detecting an error
- overload frame: pacing, tell sender to slow down
- message format
- identifier (4 bytes), data length (1 byte), payload (up to 8 bytes)
- base/standard vs extended header format
- 11 bits vs. 29 bits identifier
- Märklin uses extended format
- wire format (vs. device format) - see MCP Page 10
- bit count - ID: 11/29, Meta: 6/8, DLC: 4, CRC: 16, EOF: 7, IFS: 3
- but stuffing done by hardware: every 6th bit must flip
- due to non-return-to-zero (NRZ) encoding
- 64 bits header/etc + 64 bits data + 3 bits IFS + stuffing = 160 bits
- 250 kbit/s → approx. 1562 frames/sec; 640 usec/frame
- network byte order: always big endian
- use
__htonl, etc. (man 3 htonl)
MCP 2515 controller
- configuration and control setup: see iotest
- no RX filtering
- no internal priorities
- 3 TX message buffers: TXB0/1/2
- control register: TXBnCTRL
- bit 3: TXREQ
- check for 0 before read, set to 1 after write
- priority & other conditions
- message registers (BCM Pages 20-22)
- SIDH: top 8 bits standard identifier
- SIDL: low 3 bits standard identifier, EXIDE, bits 17/16 of extended identifier
- EID8, EID0: extended identifier
- DLC: 4 bits data length field
- Dm: 8 registers, one data byte each
- SPI interface (MCP Section 12.5): sequential writes possible
- using TXB0 should be sufficient
- 2 RX message buffers: RXB0/1 (plus internal assembly buffer)
- control register: RXBnCTRL
- configure rollover, not used for filtering
- (interrupt) flag register: CANINTF
- bits 0,1: RX data available in respective buffer
- check for 1 before read, clear after read
- other conditions
- message registers (BCM Pages 30-32):
- SIDH: top 8 bits standard identifier
- SIDL: low 3 bits standard identifier, EXIDE, bits 17/16 of extended identifier
- EID8, EID0: extended identifier
- DLC: 4 bits data length field
- Dm: 8 registers, one data byte each
- SPI interface (MCP Section 12.3): sequential reads possible
- use RXB0, and RXB1 for overflow
- controller status instruction (MCP Section 12.8 and Figure 12-8)
- obtain RX0IF, RX1IF, TX0REQ, TX1REQ, TX2REQ
Märklin CAN protocol
- message format (MRK Page 5)
- extended identifier (29 bits)
- priority (4 bits), can be 0
- command (8 bits)
- response indicator (1 bit)
- hash value (16 bits): collision resolution, can use 0xC300
- CAN bus priority not really used/needed...
- dlc (4 bits): as needed
- data (0-8 bytes): depending on command
- CS3 responses
- same command, dlc, data
- response bit set
- different hash
- simple pacing: wait for response before sending next command
- speed (command 0x04, MRK Page 30)
- dlc = 6
- data 0-3: train number
- data 4-5: speed level 0..1000
- CS3 ↔ locomotive: 14 steps? (see Page 10)
- level = 1 + (step - 1) * 77
- direction (command 0x05, MRK Page 31)
- dlc = 5
- data 0-3: train number
- data 4: 1 forward, 2 backward, 3 reverse
- trains slow down gradually
- do not directly reverse a rolling train
- light (command 0x06, MRK Page 32)
- dlc = 6
- data 0-3: train number
- data 4: function 0 (light)
- data 5: 0 off, 1 on
- switch (command 0x0B, MRK Page 37)
- dlc = 6
- data 0-3: 0x3000 + switch number
- data 4: 0 curved, 1 straight
- data 5: 1 (engage)
- response with data 5 set to 1: response/confirm
- response with data 5 set to 0: solenoid off
- middle "double" switches
- avoid C/C state (and S/S is not very helpful either)
- if curved left (CS), and want curved right (SC)
- first set C switch to S (SS)
- then set other switch to C (SC)
- sensors (command 0x11, MRK Page 40)
- 5 banks of 16 up to 16 sensors
- banks labeled as A, B, C, D, E on track
- individual sensors labeled A13, A14
- sensors are directional: A15 →, A16 ←
- asynchronous incoming message
- response bit set
- dlc = 8
- data 0,1: ignore (unused identification)
- data 2,3: (bank - 'A') * 16 + (number - 1) + 1
- data 4,5: old, new state (0 free, 1 occupied)
- data 6,7: ignore (time stamp)
- control and configuration
- command 0x00
- data 0-3: 0 (broadcast)
- subcmd in data 4
- 0x01: go (same as button)
- 0x02: halt - set speed 0 to all
- 0x00: stop (same as button)
- other incoming messages
- command 0x18 and response bit: ping
- command 0x00, subcmd 0x00, no response: stop via button
- command 0x00, subcmd 0x01, no response: go via button
Notes
- turn on the headlights! (verify basic communication and train direction)
- initialize track & turnouts to well-defined state
- captive loop, lights on, speed zero, forward direction
- can use wireshark to observe traffic on CAN bus