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_i | in | 1 bit | Clock |
rst_i | in | 1 bit | Synchronous reset (active high) |
start_i | in | 1 bit | Begin one arbitration attempt |
id_i | in | 11-bit vector | Message identifier |
can_rx_i | in | 1 bit | Bus level seen by the transceiver |
can_tx_o | out | 1 bit | Transceiver drive level, dominant 0, recessive 1 |
busy_o | out | 1 bit | Arbitration attempt is active |
won_o | out | 1 bit | Arbitration won (one-clock pulse) |
lost_o | out | 1 bit | Arbitration lost (one-clock pulse) |
handoff_o | out | 1 bit | Won field complete (one-clock pulse) |
Behavior
- While idle,
can_tx_ois recessive high, andbusy_o,won_o,lost_o, andhandoff_oare low start_iis sampled only while idle, andid_iis captured on the accepting rising edge- The attempt begins on the following rising edge:
busy_orises and the SOF bit begins - Changes to
id_iafter acceptance do not affect the running attempt start_iwhilebusy_ois high is ignored- Every transmitted bit lasts exactly four clocks
can_tx_ochanges only at a bit boundary and holds the same value for all four clocks of that bitcan_rx_iis 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_rx_iis dominant at its sample point - At that sample edge,
lost_opulses for one clock andbusy_ofalls - After a loss,
can_tx_ois 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,
won_opulses at the final bit's sample point handoff_opulses on the following clock, withbusy_ostill high andwon_olow- On the next clock,
busy_ofalls andcan_tx_ois recessive won_o,lost_o, andhandoff_oare each high for exactly one clockrst_ihigh at any rising edge cancels the attempt and returns the unit to idle- After reset,
can_tx_ois recessive and every other output is low
What the bench checks
- The testbench checks idle, reset,
start_iacceptance, capturedid_i, 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_o,handoff_o, andbusy_osequence after a complete field - It asserts reset at several bit phases and checks an immediate registered return to idle
Constraints
TIMING: everything is synchronous to
clk_i; all outputs are registered.can_tx_omay change only at bit boundaries, andcan_rx_iis sampled on each bit's third clock.
SCOPE: 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_oandcan_rx_iare 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.