1. 项目概述:FPGA CAN控制器设计的意义
在嵌入式系统和工业控制领域,CAN总线因其高可靠性和实时性被广泛应用。传统方案需要外挂独立的CAN控制器芯片(如MCP2515、SJA1000等),这不仅占用宝贵的PCB面积,还增加了BOM成本和布线复杂度。而采用FPGA实现CAN控制器IP核,可以将整个CAN协议栈集成到FPGA内部,实现真正的单芯片解决方案。
我最近在Altera(现Intel)和Xilinx平台上完成了CAN控制器Verilog实现,实测在Cyclone IV EP4CE10上仅消耗800个LE(逻辑单元),相当于用不到10%的芯片资源替代了独立CAN控制器。这个方案特别适合空间受限的工业设备、车载电子等场景。
2. 核心设计思路与技术选型
2.1 CAN协议栈的FPGA实现架构
完整的CAN控制器包含以下关键模块:
- 位时序处理单元:负责标定位时间(Bit Time)的同步段、传播段、相位缓冲段
- 报文收发引擎:处理CAN帧的组装与解析,包括仲裁场、控制场、数据场等
- 验收滤波器:根据ID过滤无关报文,降低主机处理负担
- 错误管理单元:实现错误检测、错误计数及总线状态机(主动错误/被动错误/总线关闭)
在Verilog实现时,我采用三级流水线结构:
- 位流处理级(同步、采样点检测)
- 协议解析级(帧类型识别、CRC校验)
- 接口适配级(寄存器映射、主机交互)
2.2 FPGA平台适配策略
针对Altera和Xilinx的差异,主要做了以下适配:
- 时钟管理:Xilinx使用MMCM,Altera用PLL生成精确的时序基准
- 存储器实现:Xilinx用Block RAM,Altera用M9K存储报文缓冲
- 跨时钟域同步:两种平台均采用双触发器同步链处理异步信号
关键参数配置示例:
verilog复制// CAN总线波特率设置(以1MHz为例)
parameter CLK_FREQ = 50_000_000; // FPGA主时钟50MHz
parameter BAUD_RATE = 1_000_000;
parameter TQ_NUM = 10; // 每个位时间的时间份额数
localparam PRESCALER = CLK_FREQ / (BAUD_RATE * TQ_NUM);
3. 详细实现过程与核心代码解析
3.1 位时序生成器设计
这是CAN控制器的核心难点,需要精确控制采样点位置。我采用可编程的位时序参数:
verilog复制module bit_timing (
input clk,
input reset,
input [3:0] tseg1, // 相位缓冲段1
input [3:0] tseg2, // 相位缓冲段2
input [2:0] sjw, // 同步跳转宽度
output sample_point
);
reg [3:0] tq_counter;
reg sample;
always @(posedge clk or posedge reset) begin
if (reset) begin
tq_counter <= 0;
sample <= 0;
end else begin
if (tq_counter == tseg1)
sample <= 1'b1; // 采样点位于相位缓冲段1结束
else
sample <= 1'b0;
tq_counter <= (tq_counter == (tseg1 + tseg2)) ? 0 : tq_counter + 1;
end
end
assign sample_point = sample;
endmodule
3.2 报文收发状态机
采用三段式状态机实现帧处理:
verilog复制localparam IDLE = 3'd0;
localparam RECEIVE = 3'd1;
localparam TRANSMIT = 3'd2;
always @(posedge clk) begin
case(state)
IDLE:
if (tx_request) state <= TRANSMIT;
else if (start_bit) state <= RECEIVE;
RECEIVE: begin
// 实现位填充去除、CRC校验等
if (eof_detected) state <= IDLE;
end
TRANSMIT: begin
// 处理位填充、ACK等待
if (tx_complete || error) state <= IDLE;
end
endcase
end
4. 工程实现与优化技巧
4.1 资源优化实践
通过以下方法显著减少资源占用:
- 时分复用技术:让发送和接收共享CRC计算模块
- 动态滤波器:只实例化必要数量的滤波比较器
- 寄存器压缩:将多个状态标志位合并为位域
实测资源对比:
| 模块 | 独立方案 | FPGA实现 | 节省比例 |
|---|---|---|---|
| CAN控制器 | 1芯片 | 800LE | 100% |
| PCB面积 | 50mm² | 0mm² | 100% |
| 信号线 | 20根 | 2根 | 90% |
4.2 时序收敛技巧
在高速CAN(1Mbps)实现时需特别注意:
- 为位时序模块单独分配全局时钟网络
- 对跨时钟域信号添加约束:
code复制set_false_path -from [get_clocks sys_clk] -to [get_clocks can_clk]
- 关键路径采用寄存器重定时(Retiming)
5. 常见问题与调试方法
5.1 典型故障排查表
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
| 无法接收到任何报文 | 验收滤波器设置过严 | 检查ACR/AMR寄存器配置 |
| CRC校验持续失败 | 采样点位置偏差 | 调整TSEG1/TSEG2参数 |
| 发送时总线无响应 | 终端电阻缺失 | 在总线两端添加120Ω电阻 |
| 偶尔出现帧错误 | 时钟抖动过大 | 优化时钟布局,缩短走线长度 |
5.2 在线调试技巧
- SignalTap/ChipScope使用:抓取关键信号如sample_point、state等
- 环回测试模式:通过设置自测寄存器验证基本功能
- 错误注入测试:人为制造位错误验证恢复机制
重要提示:在调试CAN总线时,务必使用差分探头测量CANH/CANL信号,单端测量会掩盖信号完整性问题。
6. 跨平台部署指南
6.1 Altera Quartus工程配置
- 创建新工程时选择正确的器件系列(如Cyclone IV)
- 在Assignment Editor中设置:
- 保留足够的I/O引脚(至少需要CAN_TX/CAN_RX)
- 为CAN时钟分配专用PLL
- 编译后检查时序报告,确保Fmax满足要求
6.2 Xilinx Vivado适配要点
- 在IP Integrator中添加AXI接口包装器:
tcl复制create_ip -name can_controller -vendor user.org -library user -version 1.0
- 约束文件示例:
xdc复制set_property PACKAGE_PIN F12 [get_ports can_tx]
set_property IOSTANDARD LVCMOS33 [get_ports can_*]
7. 实际应用案例
在某车载控制单元中,采用本方案实现了:
- PCB面积减少30%(去除了独立CAN控制器和隔离电路)
- BOM成本降低$4.2/台
- 通过ISO 11898-2合规性测试
关键改进包括:
- 添加了总线唤醒功能(通过显性超时检测)
- 支持FD模式(可变速率,最高5Mbps)
- 集成ESD保护(利用FPGA的片上钳位二极管)
这个项目让我深刻体会到FPGA在协议处理方面的灵活性——通过调整Verilog代码,我们仅用两周就实现了客户定制的时间触发CAN(TTCAN)扩展,而这在传统方案中需要更换硬件才能实现。