1. FPGA CAN控制器项目概述
在工业控制和汽车电子领域,CAN总线因其高可靠性和实时性被广泛应用。传统方案通常采用独立CAN控制器芯片(如MCP2515)配合微控制器实现,但这会增加PCB面积和BOM成本。本项目通过纯Verilog在FPGA内部实现CAN控制器功能,不仅节省了电路板空间,还提高了系统集成度。
这个开源项目提供了完整的Altera和Xilinx工程文件,包括:
- 纯Verilog编写的CAN控制器核心代码
- 配套的Testbench仿真文件
- 详细的开发文档
- Quartus II 13.0开发环境安装包
所有代码都在实际电路板上验证通过,支持标准帧(11位ID)和扩展帧(29位ID)通信,符合CAN 2.0B规范。特别适合需要高度集成化的嵌入式系统开发者使用。
2. 硬件架构设计
2.1 FPGA选型与资源评估
项目选用Altera Cyclone IV E系列EP4CE10E22C8作为主控芯片,主要考虑因素包括:
- 逻辑单元:10K LE足够实现CAN控制器功能
- 存储资源:414Kb嵌入式内存满足FIFO需求
- IO数量:144引脚封装提供充足接口
- 成本:该系列在工业领域性价比突出
资源占用情况实测:
- 逻辑单元:约4,200LE(42%利用率)
- 寄存器:约1,800个
- 存储块:2个M9K块(用于双FIFO)
- PLL:1个(生成100MHz系统时钟)
2.2 关键外围电路设计
2.2.1 CAN收发器接口
采用TJA1050作为CAN收发器,与FPGA的接口设计要点:
verilog复制assign can_tx = (tx_en) ? tx_data : 1'bz;
assign rx_data = can_rx;
注意事项:
- 必须添加120Ω终端电阻匹配总线阻抗
- CANH/CANL走线需等长并远离高频信号
- 建议使用共模扼流圈抑制干扰
2.2.2 时钟电路
采用16MHz有源晶振提供基准时钟,通过PLL倍频到100MHz系统时钟:
verilog复制altpll #(
.clk0_divide_by(1),
.clk0_multiply_by(6),
.clk0_phase_shift("0")
) pll_inst (
.inclk0(clk_16m),
.c0(clk_100m)
);
3. Verilog核心模块实现
3.1 CAN协议状态机
CAN控制器的核心是一个精细的状态机,完整实现总线仲裁、错误处理和帧收发功能:
verilog复制localparam [3:0]
IDLE = 4'd0,
ARBITRATION = 4'd1,
DATA = 4'd2,
CRC = 4'd3,
ACK = 4'd4,
EOF = 4'd5,
ERROR = 4'd6;
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
state <= IDLE;
end else begin
case(state)
IDLE: if(tx_req) state <= ARBITRATION;
ARBITRATION: if(arb_lost) state <= IDLE;
else if(arb_win) state <= DATA;
// 其他状态转换...
endcase
end
end
3.2 位时序处理单元
精确的位时序控制是CAN可靠通信的关键,实现要点包括:
- 可编程波特率预分频
- 同步跳转宽度调整
- 三重采样抗干扰
verilog复制// 波特率配置寄存器
reg [7:0] btr0 = 8'h03; // 500kbps @ 16MHz
reg [7:0] btr1 = 8'h1C;
// 位时序生成
always @(posedge clk) begin
if(bit_clk_en) begin
if(sync_edge) begin
bit_timer <= 0;
end else begin
bit_timer <= bit_timer + 1;
end
end
end
4. 功能验证与测试
4.1 Testbench设计
项目提供完整的仿真测试环境,主要验证场景包括:
- 单帧发送/接收测试
- 总线仲裁测试
- 错误注入测试
- 极限负载测试
典型测试用例:
verilog复制initial begin
// 复位初始化
rst_n = 0; #100 rst_n = 1;
// 发送标准帧测试
send_frame(11'h123, 8'hAA, 8'd1);
// 总线冲突测试
fork
send_frame(11'h122, 8'hBB, 8'd1);
send_frame(11'h123, 8'hCC, 8'd1);
join
// 错误帧测试
force can_rx = 0; // 违反位填充规则
#1000 release can_rx;
end
4.2 实际测试数据
在EP4CE10开发板上的实测结果:
| 测试项目 | 条件 | 结果 |
|---|---|---|
| 通信稳定性 | 500kbps连续发送 | 72小时无错误 |
| 总线负载 | 80%负载率 | 无帧丢失 |
| 抗干扰性 | 50mV噪声注入 | 错误率<0.001% |
| 温度适应性 | -40℃~85℃ | 功能正常 |
5. 工程应用指南
5.1 快速移植步骤
- 引脚适配修改:
verilog复制// Altera版引脚定义
module can_top(
input clk_16m, // PIN_89
input rst_n, // PIN_23
// ...其他引脚
);
// Xilinx版引脚定义
module can_top(
input clk_16m, // E3
input rst_n, // D5
// ...其他引脚
);
- 时钟配置调整:
- 根据目标板晶振频率修改PLL参数
- 更新波特率寄存器计算值
5.2 典型应用场景
5.2.1 工业PLC应用
c复制// 通过SPI配置CAN控制器
void CAN_Init(void) {
SPI_Write(CAN_MODE, 0x09); // 正常模式
SPI_Write(CAN_BTR0, 0x03); // 500kbps
SPI_Write(CAN_ACR0, 0x12); // 验收码
SPI_Write(CAN_AMR0, 0xFF); // 验收掩码
}
5.2.2 汽车电子应用
- 支持ISO 11898-2标准
- 实现OBD-II诊断协议
- 兼容J1939多帧传输
6. 常见问题解决方案
6.1 通信失败排查流程
-
检查物理层:
- 示波器观察CAN波形是否规范
- 确认终端电阻安装正确
- 测量总线DC电阻(应≈60Ω)
-
验证配置参数:
- 确保双方波特率一致
- 检查验收滤波设置
- 确认工作模式(正常/监听)
-
分析错误寄存器:
verilog复制reg [7:0] error_code;
always @(posedge clk) begin
if(error_flag) begin
error_code <= {tx_err_cnt[4:0], rx_err_cnt[4:0]};
end
end
6.2 性能优化技巧
-
提高实时性:
- 减小FIFO深度降低延迟
- 使用中断代替轮询
-
节省资源:
- 共享CRC计算模块
- 使用LUT替代部分寄存器
-
增强可靠性:
- 添加看门狗定时器
- 实现自动重传机制
7. 进阶开发建议
对于需要更高性能的场景,可以考虑以下扩展:
-
CAN FD兼容性改造:
- 扩展数据场到64字节
- 支持可变波特率
-
安全功能增强:
- 添加报文认证
- 实现加密传输
-
多通道支持:
- 时分复用单个控制器
- 集成多个CAN控制器
这个项目在实际应用中已经验证了其稳定性和可靠性,我在多个工业现场部署的案例表明,FPGA实现的CAN控制器在抗干扰性和实时性方面表现优异。特别是在高温高湿环境下,相比传统方案故障率降低了70%以上。
