04 · LIN Bus Basics¶
Not every signal in a car needs CAN's arbitration, error handling, or wiring cost. Window lifters, mirror motors, seat controllers, rain sensors — low-speed, low-criticality, cost-sensitive nodes — typically sit on LIN (Local Interconnect Network), a single-wire, master/slave bus that trades CAN's peer-to-peer arbitration for a much cheaper physical layer. This module covers LIN's frame model and the CAPL/tooling differences from the CAN work in Level 1 and this level's earlier modules.
About this module
LIN 2.x frame structure, checksum rules, and the CAPL syntax below are genuine, documented behavior (LIN Specification 2.2A). Nothing here was captured from a live LIN bus — treat every snippet as a reviewed reference and verify against your own hardware.
Master/slave, not peer-to-peer¶
CAN nodes all arbitrate for the bus independently. LIN has exactly one master node, which owns a schedule table of when every message gets sent, and one or more slave nodes that only ever respond when the master asks. There is no arbitration, no collision handling, and no node priority beyond "whatever order the master's schedule puts it in."
This has direct test consequences: you cannot "just transmit" a LIN frame the way you can a CAN frame from a test node — you either are the master (running the schedule) or you're a slave responding to a header the master sends, and CANoe's LIN interface models this distinction explicitly (Master simulation vs. Slave simulation nodes).
Frame anatomy¶
A LIN frame is two parts sent by two different roles:
- Header (always sent by the master): break field, sync byte, protected identifier (PID).
- Response (sent by whichever node — master or a slave — owns that identifier): 1–8 data bytes, then a checksum.
| Field | Sent by | Size | Purpose |
|---|---|---|---|
| Break | Master | ≥13 bit-times low | Signals start of frame |
| Sync | Master | 0x55 | Lets slaves calibrate their baud rate |
| Protected ID (PID) | Master | 6-bit ID + 2 parity bits | Identifies which frame; parity catches bit errors on the ID itself |
| Data | Header owner | 1–8 bytes | The payload |
| Checksum | Same node as data | 1 byte | Classic (data-only) or enhanced (data+PID), depending on LIN version |
Checksum: classic vs. enhanced¶
LIN 1.x used a classic checksum (sum of data bytes only). LIN 2.x introduced the enhanced checksum, which folds the protected ID into the sum as well, catching a class of errors the classic checksum missed. A LIN network with mixed-version nodes must configure each frame's checksum type individually to match what that frame's publisher/subscriber pair actually implements — a very common integration bug is one node using enhanced and another expecting classic for the same frame ID, which silently drops every frame as a checksum failure.
CAPL for LIN¶
CAPL treats LIN messages similarly to CAN messages but through
LIN-specific objects (linFrame, on linFrame, LinFrameSendRequest):
variables
{
linFrame MirrorControl mcFrame;
}
on preStart
{
// As LIN master simulation: request this frame be sent by the schedule
LinFrameSendRequest(mcFrame);
}
on linFrame MirrorControl
{
write("MirrorControl: X=%d, Y=%d, checksum_ok=%d",
this.byte(0), this.byte(1), this.CheckSumOK);
}
on linSchedulerModeChange
{
write("Schedule table changed to: %d", this.mode);
}
Key differences from the CAN handlers in Level 1 Module 5 and this level's Module 1:
this.CheckSumOKis a LIN-specific flag your test scripts should assert on directly — a frame with a bad checksum still arrives at theon linFramehandler, unlike a CAN frame that fails CRC (which is typically dropped at the controller level before your script sees it).- LIN frames are driven by a schedule table, configured separately
from the CAPL script (in the LDF — LIN Description File — and CANoe's
scheduler configuration), not by ad-hoc
output()calls at arbitrary times.
LDF vs. DBC¶
LIN's equivalent of a DBC is the LDF (LIN Description File) — similar goal (signals, frames, scaling, nodes) but LIN-specific syntax and mandatory schedule-table definitions:
LIN_description_file;
LIN_protocol_version = "2.2A";
LIN_language_version = "2.2";
LIN_speed = 19.2 kbps;
Nodes {
Master: BodyControlModule, 5 ms, 0.1 ms;
Slaves: MirrorLeft, MirrorRight;
}
Signals {
MirrorX: 8, 0, MirrorLeft, BodyControlModule;
MirrorY: 8, 0, MirrorLeft, BodyControlModule;
}
Frames {
MirrorControl: 0x10, MirrorLeft, 2 {
MirrorX, 0;
MirrorY, 8;
}
}
Schedule_tables {
Normal {
MirrorControl delay 10 ms;
}
}
A test suite that reads a DBC but ignores the corresponding LDF for a LIN sub-network will miss schedule-table timing entirely — the LDF is the source of truth for when a LIN signal actually updates, which a DBC has no concept of.
Test implications¶
| Risk | Cause | Test approach |
|---|---|---|
| Silent data drop between mismatched nodes | Classic vs. enhanced checksum mismatch | Assert CheckSumOK on every received frame in a restbus/simulation test, not just decode the bytes |
| Slave not responding | Slave not present in the active schedule table, or wrong sleep/wake state | Verify schedule table membership and node wake state before asserting on a slave's response |
| Wrong signal timing assumption | LDF schedule interval treated like a CAN cycle time | Confirm actual update interval against the LDF's schedule table, not an assumed fixed rate |
| Bus stuck after a slave error | LIN has weaker built-in error recovery than CAN | Include a wake-up/sleep-cycle test (go-to-sleep frame ID 0x3C, wake-up via bus activity) in your test plan |
Cheat sheet¶
| Concept | CAN | LIN |
|---|---|---|
| Bus access | Multi-master, arbitration | Single master, schedule-driven |
| Physical layer | 2-wire differential | 1-wire, ground-referenced |
| Frame structure | ID + DLC + data + CRC | Break/Sync/PID (master) + data + checksum (header owner) |
| Database file | DBC | LDF |
| Checksum types | Single (15-bit CRC) | Classic vs. Enhanced (version-dependent) |
| CAPL object | message |
linFrame |
How It Actually Works: how a slave finds the master's baud rate from one byte¶
LIN slaves are commonly built with cheap, imprecise RC oscillators —
part of what makes LIN nodes cost less than CAN nodes — so they cannot
be assumed to already agree with the master's bit rate the way two CAN
nodes' quartz-driven controllers roughly do. The sync byte (0x55,
binary 01010101) exists specifically to fix this every single frame,
not just at startup.
0x55 is deliberately the one byte value that produces a perfectly
alternating 0-1-0-1 bit pattern. A slave measures the time between the
falling edges of that byte on the bus — five identical, evenly spaced
edges — and from that measurement directly computes what one bit-time
actually is right now, on this frame, compensating for its own
oscillator's drift and temperature-dependent variation in real time.
This is why LIN can tolerate slave oscillators far less precise than a
CAN transceiver's clock requirement: each frame carries its own timing
calibration reference before any data arrives, rather than relying on
every node's clock staying accurate over the long run the way CAN's
per-bit resynchronization (Level 1 Module 2) does continuously.
The protected identifier immediately following sync applies a
similar defense to the 6-bit frame ID itself: two parity bits are
computed as fixed XOR combinations of the ID bits
(P0 = ID0⊕ID1⊕ID2⊕ID4, P1 = ¬(ID1⊕ID3⊕ID4⊕ID5), per the LIN
specification) and appended, so a single-bit corruption on the wire
during the ID field itself is very likely to produce a parity mismatch
a slave can detect before deciding whether to respond — since LIN,
unlike CAN, has no CRC or ACK mechanism protecting frame delivery at the
bus level, this ID-level parity is the only line of defense against a
slave mistakenly responding to (or overwriting) the wrong frame slot,
which is exactly the kind of failure mode a "half the time it drops"
field report in the exercise below could actually trace back to, if the
checksum type turns out not to be the cause.
Exercise¶
A body-control LIN network has a WindowControl frame owned by the
WindowMotor slave, LIN 2.1 enhanced checksum, on a 10 ms schedule
slot.
- Explain, in terms of header vs. response, exactly which bytes the master sends and which bytes the slave sends for this frame.
- A field report says
WindowControlvalues are read correctly about half the time and drop the rest. List two plausible causes rooted in this module (checksum type, schedule table, wake state) and how you would distinguish between them usingCheckSumOKand schedule-table inspection. - Write a CAPL
on linFrame WindowControlhandler that counts and reports the checksum failure rate over a 1000-frame sample.