Practice
Forklift CAN Arbitration
Two forklift controllers at Halewick Cold Store share one CAN pair. On CAN, a 0 bit is dominant, so a sender that drives 0 wins the wire.
Each sender must read the bus while it writes.
When both controllers began a message together, the one with the higher identifier kept driving after it had lost. Both messages died.
Each collision caused a storm of resends. Forklifts froze beneath flashing amber beacons while a milk lorry waited at Bay 4.
The fix is a front end that sends the arbitration field and listens to every bit. It must go silent as soon as it loses. If it wins, it hands the bus to the block that sends the data.
Your task: build that arbitration front end. Send SOF, the 11-bit identifier, RTR, and any needed stuff bits. Check the bus at each sample point and report whether the attempt won or lost.
Interface
| Port | Direction | Type | Description |
|---|---|---|---|
clk | in | 1 bit | Clock |
rst | in | 1 bit | Synchronous reset (active high) |
start | in | 1 bit | Begin one arbitration attempt |
id | in | 11-bit vector | Message identifier |
can_rx | in | 1 bit | Bus level seen by the transceiver |
can_tx | out | 1 bit | Transceiver drive level, dominant 0, recessive 1 |
busy | out | 1 bit | Arbitration attempt is active |
won | out | 1 bit | Arbitration won (one-clock pulse) |
lost | out | 1 bit | Arbitration lost (one-clock pulse) |
handoff | out | 1 bit | Won field complete (one-clock pulse) |
Behavior
- While idle,
can_txis recessive high, andbusy,won,lost, andhandoffare low startis sampled only while idle, andidis captured on the accepting rising edge- The attempt begins on the following rising edge:
busyrises and the SOF bit begins - Changes to
idafter acceptance do not affect the running attempt startwhilebusyis high is ignored- Every transmitted bit lasts exactly four clocks
can_txchanges only at a bit boundary and holds the same value for all four clocks of that bitcan_rxis sampled at the third clock of every bit- The field contains one dominant SOF bit, the 11 captured identifier bits MSB first, then one recessive RTR bit
- Bit stuffing starts with SOF and tracks every sent bit
- After five identical consecutive sent bits, one opposite-level stuff bit is inserted before the next field bit
- Inserted stuff bits join the run count and are subject to the same arbitration rule as all other bits
- A recessive transmitted bit loses arbitration if
can_rxis dominant at its sample point - At that sample edge,
lostpulses for one clock andbusyfalls - After a loss,
can_txis recessive from the next bit boundary and no more field bits are sent - Sampling dominant while transmitting dominant is normal and does not lose arbitration
- If the complete stuffed field finishes without a loss,
wonpulses at the final bit's sample point handoffpulses on the following clock, withbusystill high andwonlow- On the next clock,
busyfalls andcan_txis recessive won,lost, andhandoffare each high for exactly one clockrsthigh at any rising edge cancels the attempt and returns the unit to idle- After reset,
can_txis recessive and every other output is low
What the bench checks
- The testbench checks idle, reset,
startacceptance, capturedid, and ignored requests while busy - It checks every bit boundary, all four clocks per bit, and the third-clock sample point
- It compares the transmitted field against SOF, MSB-first identifier, RTR, and required stuff bits
- It forces dominant bus levels during recessive identifier, RTR, and stuff bits to check immediate loss reporting
- It checks that dominant transmitted bits never lose when the sampled bus is dominant
- It checks the exact
won,handoff, andbusysequence after a complete field - It asserts reset at several bit phases and checks an immediate registered return to idle
Constraints
everything is synchronous to clk; all outputs are registered. can_tx may change only at bit boundaries, and can_rx is sampled on each bit's third clock.
this is an arbitration-field front end, not a CAN controller. CRC, ACK, error frames, resynchronization, and the data frame are out of scope. can_tx and can_rx are the transceiver's logic pins. The wired-AND bus lives in the transceiver and external wiring.
Do not add ports.
Click Run to execute your code. Output will appear here.