
This is the decision/relay core of a robot-arm reflex system (AgileX Piper 6-DOF arm). The chip is the only transmitter on the CAN bus: it forwards the host's normal joint commands to the robot via an external MCP2515 (SPI↔CAN controller), and when a danger trigger fires it blocks the normal stream and injects a reflex pose instead. Because the chip is the sole sender, the "gate" is not a cross-module signal — it is a single internal mux.
Two SPI ports:
uio[0:3] = SPI slave (the FPGA's PL writes config registers + relays normal CAN frames into the chip).uio[4:6] + ui[3] = SPI master that drives the MCP2515 directly (init, transmit, read-back).Data path:
0x50–0x55) → mux(normal) → MCP2515 → CAN.reflex_core_c (rule table + priority + debounce)
→ reflex_pose_gen / reflex_tx_src → mux(reflex, gate closed) → MCP2515 → CAN.mcp_rx_recv (decodes feedback 0x2A5–7 current pose) → used by the
"flinch-from-current-pose" reflex.Reflex actions (action_id):
FLINCH_TICKS, then auto-release (re-arm on sensor release).Programmable reflex (rule encoding, register 0x10–0x13): each 16-bit rule is
[2:0]=action [3]=enable [5:4]=priority [6]=source(0=digital pin / 1=XADC threshold).
The danger source is xadc_val >= threshold (FSR) or a digital pin. Highest-priority active rule wins.
A debounce (0x49) rejects noise. MCP2515 read-back (regs 0x21–0x28: CANSTAT/CNF/TEC/REC/…) is
exposed so the host can see how the chip configured/drove the CAN controller (black-box-free debugging).
Note: timing constants (MCP oscillator-settle delay, SPI pacing, flinch ticks) are sized for the 20 MHz clock via the module's default parameters. Run the design at ~20 MHz.
The chip is a clock-synchronous SPI peripheral that also masters an MCP2515. To exercise it:
clk at ~20 MHz, pulse rst_n low then high, keep ena=1, ui[7](arm_enable)=1.0xC0,
oscillator-settle delay, CNF1/2/3=00/C0/80 for 1 Mbps, normal mode). STATUS(0x20) init_done goes high.uio[0:2], 24-bit txn = 8-bit cmd {rw,addr[6:0]} + 16-bit data):
set a rule (e.g. 0x12=FSR rule), threshold (0x1A), flinch ticks (0x46/0x47), speed (0x48), debounce (0x49).0x50(id) + 0x51–0x54(8 bytes) then 0x55 (send) → appears on CAN.ui[0](DIP) or drive the XADC input above threshold → uo[5](reflex_active)
goes high, the normal frame is blocked, and the reflex pose (0x150/0x155–7) goes out on CAN instead.uo[7]=heartbeat, uo[4:2]=action_id, uo[1]=fire; MCP regs read-back via SPI 0x21–0x28.A full reference Verilog integration test (chip + an MCP2515 model, exercising pass-through + the
current-pose flinch) is in test/tb_reference_full.v (+ mcp2515_model_v2.v). The test/ cocotb
harness runs a minimal reset/heartbeat sanity check for the GDS CI.
uio[4:6] (SCLK/MOSI/CSn) + ui[3] (MISO) + ui[2] (INT).ui[0] (estop/freeze trigger).| # | Input | Output | Bidirectional |
|---|---|---|---|
| 0 | dip estop trigger | valid | SPI slave SCLK in |
| 1 | danger1 soft trigger | fire | SPI slave MOSI in |
| 2 | mcp_int | action_id0 | SPI slave CSn in |
| 3 | mcp_miso | action_id1 | SPI slave MISO out |
| 4 | action_id2 | SPI master SCLK out | |
| 5 | reflex_active gate | SPI master MOSI out | |
| 6 | mcp_rst | SPI master CSn out | |
| 7 | arm_enable | heartbeat |