1. FPGA驱动SJA1000T实现CAN通信的核心设计思路
在工业控制、汽车电子等领域,CAN总线因其高可靠性和实时性成为首选通信方案。而FPGA的并行处理能力与可编程特性,使其成为实现CAN通信协议的理想载体。SJA1000T作为经典的独立CAN控制器,其与FPGA的协同工作能充分发挥硬件加速优势。
选择SJA1000T主要基于三点考量:首先,它完整支持CAN 2.0A/B协议,兼容标准帧(11位标识符)和扩展帧(29位标识符);其次,提供64字节的接收缓冲区和先进的中断管理机制;最后,其并行总线接口与FPGA的IO特性高度匹配。实测表明,在20MHz时钟下,该方案可实现1Mbps的标准通信速率。
2. 硬件接口设计与关键信号解析
2.1 物理层连接方案
FPGA与SJA1000T采用典型的并行总线连接方式:
- 数据总线D0-D7:FPGA的Bank0通用IO引脚
- 地址线A0-A2:连接FPGA的三位地址输出
- 控制信号:
- CS_N:片选(低有效)
- RD_N:读使能(低有效)
- WR_N:写使能(低有效)
- INT:中断输出(开漏需上拉)
特别注意:SJA1000T的工作电压为5V,而现代FPGA多为3.3V电平,需使用电平转换芯片或FPGA的5V容忍Bank。
2.2 时钟与复位设计
SJA1000T的时钟输入范围16-24MHz,推荐使用20MHz有源晶振。FPGA通过PLL生成:
verilog复制// Xilinx MMCM配置示例
mmcm_adv #(
.CLKIN1_PERIOD(50.0), // 20MHz输入
.CLKFBOUT_MULT_F(5), // VCO=100MHz
.CLKOUT0_DIVIDE_F(5) // 20MHz输出
) clk_gen (
.clkout0(clk_20m),
// 其他连接省略...
);
复位电路需保证至少16个时钟周期的低电平,FPGA上电后应延时100ms再释放复位。
3. 寄存器配置与通信协议实现
3.1 关键寄存器映射
SJA1000T的寄存器分为两组,通过时钟分频寄存器(CDR)的CAN模式位切换:
| 地址 | 寄存器名 | 功能说明 |
|---|---|---|
| 0x00 | MOD | 模式控制:RM=1进入复位模式 |
| 0x01 | CMR | 命令寄存器:TR=1启动发送 |
| 0x02 | SR | 状态寄存器:RBS=1表示接收缓冲状态 |
| 0x03 | IR | 中断寄存器:RI=1表示接收中断 |
| 0x04 | IER | 中断使能:ERIE=1使能接收中断 |
| 0x05 | BTR0 | 总线定时:定义波特率预分频 |
| 0x06 | BTR1 | 总线定时:定义采样点和同步跳转宽度 |
| 0x0D | CDR | 时钟分频:CAN模式=1选择PeliCAN模式 |
3.2 标准帧与扩展帧处理
帧格式通过发送缓冲区1(地址0x10)的第4字节控制:
verilog复制// 标准帧数据结构示例
reg [7:0] tx_buffer [0:12];
tx_buffer[0] = {3'b000, 5'bxxxxx}; // 帧信息:标准帧+数据长度
tx_buffer[1] = id_10_3; // ID高8位
tx_buffer[2] = id_2_0; // ID低3位
// 数据域从tx_buffer[3]开始
// 扩展帧需设置FF=1,并使用29位ID
tx_buffer[0] = {3'b100, 5'bxxxxx}; // 帧信息:扩展帧标志
tx_buffer[1] = id_28_21; // ID字段1
tx_buffer[2] = id_20_13; // ID字段2
tx_buffer[3] = id_12_5; // ID字段3
tx_buffer[4] = {id_4_0, 3'b000}; // ID字段4
4. Verilog驱动代码实现要点
4.1 总线接口状态机
采用三段式状态机实现寄存器访问:
verilog复制localparam S_IDLE = 0, S_ADDR = 1, S_READ = 2, S_WRITE = 3;
always @(posedge clk) begin
case(state)
S_IDLE:
if(rd_req || wr_req) begin
addr_reg <= addr;
data_out_reg <= wr_data;
state <= S_ADDR;
end
S_ADDR:
begin
cs_n <= 1'b0;
addr_bus <= addr_reg;
state <= (wr_req) ? S_WRITE : S_READ;
end
S_WRITE:
begin
wr_n <= 1'b0;
data_bus <= data_out_reg;
state <= S_IDLE;
end
// 其他状态省略...
endcase
end
4.2 中断驱动接收处理
接收流程建议采用中断方式:
- 配置IER寄存器使能接收中断(ERIE=1)
- 中断服务程序中读取IR寄存器确认中断类型
- 若RI=1,则从接收缓冲区(地址0x20)读取数据
- 清除中断标志(通过CMR的RRB位)
经验:接收缓冲区读取后必须及时释放,否则会导致后续报文丢失。实测发现两次读取间隔应小于1ms。
5. 时序约束与调试技巧
5.1 建立保持时间分析
SJA1000T的时序参数要求严格:
- 地址建立时间t_AS ≥ 10ns
- 写信号有效宽度t_W ≥ 50ns
- 数据保持时间t_DH ≥ 10ns
Xilinx Vivado中需添加约束:
tcl复制set_input_delay -clock [get_clocks clk_20m] -min 2 [get_ports {sja_addr[*]}]
set_input_delay -clock [get_clocks clk_20m] -max 8 [get_ports {sja_addr[*]}]
set_output_delay -clock [get_clocks clk_20m] 3 [get_ports {sja_data[*]}]
5.2 常见问题排查
-
通信失败:
- 检查BTR0/BTR1设置:1Mbps时典型值BTR0=0x00, BTR1=0x14
- 用示波器测量CANH/CANL差分信号幅度(应≥1.5V)
-
中断不触发:
- 确认INT引脚上拉电阻(建议4.7kΩ)
- 检查IER寄存器使能位设置
-
数据校验错误:
- 确保FPGA与SJA1000T时钟同步
- 在接收端添加CRC校验模块
6. 实际工程优化建议
-
双缓冲设计:在FPGA内实现乒乓缓冲区,当SJA1000T接收缓冲区满时能快速转移数据,避免溢出。实测表明这可提升30%的吞吐量。
-
动态波特率切换:通过改写BTR0/BTR1寄存器实现运行时波特率调整,注意修改前需进入复位模式(MOD[0]=1)。
-
错误统计功能:读取ECC寄存器(地址0x0C)获取错误计数器值,当超过阈值时触发报警。
-
热插拔保护:在CAN接口添加TVS二极管(如SM712),防止热插拔时浪涌损坏芯片。
