1. FPGA与MCP2515的CAN通信方案概述
在工业控制和车载电子领域,CAN总线因其高可靠性和实时性被广泛应用。本文将详细介绍基于FPGA和MCP2515的CAN通信解决方案,该方案已在Altera和Xilinx双平台上验证通过。核心设计理念是通过纯Verilog实现SPI主设备,直接控制MCP2515 CAN控制器,无需嵌入式CPU介入,实现低延迟、高确定性的CAN报文收发。
这套方案特别适合需要快速响应CAN报文的场景,如汽车ECU通信、工业设备监控等。我们提供了完整的工程代码,包括Altera和Xilinx两个版本,所有代码都经过实际电路板验证,并附带详细的测试激励文件(testbench),用户可以直接在ModelSim或QuestaSim中运行仿真。
2. 系统架构设计
2.1 整体数据流设计
系统采用分层架构设计,顶层模块负责协调各子模块工作,并处理跨时钟域同步问题。数据流向如下:
- 用户提供24MHz时钟输入,经过片上PLL生成100MHz系统时钟
- 顶层调度模块(MCP2515_SPI_III_top)接收配置指令并分发
- SPI时序控制模块(spi_timing_ctrl_3)产生符合CPOL=0/CPHA=0的SPI时序
- MCP2515芯片通过SPI接口接收配置和收发数据
- CAN物理层通过CANH/CANL差分信号与外部设备通信
这种分层设计使得各模块职责明确,便于后期维护和功能扩展。
2.2 核心模块功能划分
| 模块名称 | 主要功能 | 设计要点 |
|---|---|---|
| system_ctrl_pll | 时钟和复位产生 | 上电延时1ms,PLL锁定后释放复位;提供100MHz主时钟和16MHz的MCP2515时钟 |
| mcp2515_init | MCP2515寄存器初始化 | 通过ROM查表方式顺序下发17条配置命令,完成后置位init_done信号 |
| mcp2515_receive | CAN报文接收引擎 | 查询RXB0中断标志,自动读取ID、DLC和数据,支持标准帧和扩展帧 |
| mcp2515_send | CAN报文发送引擎 | 检测TXB0空闲状态,写入报文数据后触发发送,确保TX0RTS信号满足时序要求 |
| spi_timing_ctrl_3 | 底层SPI时序控制 | 产生1MHz的SCK时钟,处理24位指令帧(命令+地址+数据),提供忙状态指示 |
3. 详细实现解析
3.1 初始化流程详解
系统上电后,初始化过程分为四个阶段:
-
电源和时钟稳定阶段:
- PLL锁定后,产生1ms宽度的系统复位信号(sys_rst_n)
- 在此期间,MCP2515的硬件复位引脚(can_rst_n)保持低电平
- 确保所有逻辑电路处于已知状态
-
SPI接口唤醒阶段:
- can_rst_n释放后,SPI时序模块开始工作
- 内部10μs定时器确保片选(CS)建立时间满足要求
- 模块进入IDLE状态等待上层命令
-
寄存器配置阶段:
verilog复制// 示例初始化命令序列 localparam INIT_CMDS = { 8'h02, 8'h2A, 8'h80, // 进入配置模式 8'h02, 8'h28, 8'h03, // 设置CANCTRL 8'h02, 8'h29, 8'h1F, // 设置CANSTAT // ...更多配置命令 8'h02, 8'h2A, 8'h00 // 返回正常模式 };- 通过状态机顺序执行17条预置命令
- 配置波特率、滤波器、中断等关键参数
- 最后切换回Normal模式
-
中断标志清除阶段:
- 主动读取RXB0CTRL寄存器
- 清除可能存在的上电误触发中断标志
- 置位init_done信号表示初始化完成
3.2 接收流程实现
接收引擎采用查询方式工作,具体步骤如下:
- 持续监测RX0IF标志(寄存器0x2C的bit0)
- 当RX0IF置位时,启动读数据序列:
- 0x61→0x62→0x63→0x64→0x65→0x66…0x6D
- 共读取13字节,包含完整CAN帧信息
- 数据解析:
- ID高/低字节:组成11位标准ID或29位扩展ID
- IDE位:标识帧类型(标准/扩展)
- RTR位:标识远程帧
- DLC:数据长度码(0-8字节)
- Data0-7:实际数据内容
- 清理工作:
- 回写0x2C清除RX0IF标志
- 产生receive_done脉冲信号
- 将接收数据传递给发送模块实现环回测试
3.3 发送流程实现
发送引擎采用触发方式工作,主要流程如下:
- 等待发送请求(send_request_ack=1)
- 检查TXB0CTRL的TXREQ位(bit4),确认发送缓冲区空闲
- 顺序写入发送数据:
verilog复制// 发送数据写入序列 {8'h40, TXB0SIDH, sid_high}, // 写ID高字节 {8'h40, TXB0SIDL, sid_low}, // 写ID低字节 {8'h40, TXB0EID8, eid8}, // 写扩展ID字节8 // ...更多数据写入 {8'h40, TXB0D7, data7} // 写数据字节7 - 触发发送:
- 拉低TX0RTS引脚至少100个时钟周期
- 再拉高TX0RTS激活发送
- 等待发送完成:
- 监测TXREQ位由1变0
- 置位send_done信号
- 返回IDLE状态
4. 关键参数配置
4.1 波特率设置
系统默认配置为500kbps波特率,对应寄存器设置如下:
| 寄存器 | 值 | 说明 |
|---|---|---|
| CNF1 | 0x03 | Tq=125ns, SJW=1, BRP=3 |
| CNF2 | 0x90 | PropSeg=1, PS1=8, SAM=0 |
| CNF3 | 0x02 | PS2=8 |
计算公式:
code复制Tq = 2 × (BRP + 1) / Fosc = 2 × (3 + 1) / 16MHz = 500ns
比特时间 = (SyncSeg + PropSeg + PS1 + PS2) × Tq
= (1 + 1 + 8 + 8) × 500ns = 2μs (500kbps)
如需修改波特率,只需调整Mcp2515_Params.h中的宏定义,无需修改RTL代码。
4.2 滤波器配置
默认配置为接收所有报文(RXM0=0x00),实际应用中可根据需求调整:
verilog复制// 示例:只接收ID在0x100-0x1FF范围内的标准帧
{8'h02, 8'h20, 8'h00}, // RXB0CTRL: 关闭滤波器
{8'h02, 8'h00, 8'h01}, // RXF0SIDH: 0x100高3位
{8'h02, 8'h01, 8'h00}, // RXF0SIDL: 0x100低8位
{8'h02, 8'h04, 8'hFF}, // RXM0SIDH: 屏蔽位
{8'h02, 8'h05, 8'hE0} // RXM0SIDL: 屏蔽位
5. 时钟域与同步处理
系统涉及多个时钟域,需要特别处理同步问题:
-
主时钟域(100MHz):
- 用于大部分逻辑电路
- 包括初始化、收发引擎和SPI时序控制
-
辅助时钟域(24MHz):
- 仅用于产生MCP2515的外部时钟(can_osc1)
- 通过PLL从主时钟分频得到
-
复位同步:
verilog复制// 异步复位同步释放电路 always @(posedge clk or negedge async_rst_n) begin if (!async_rst_n) begin rst_meta <= 1'b0; rst_sync <= 1'b0; end else begin rst_meta <= 1'b1; rst_sync <= rst_meta; end end- 采用双触发器同步
- 确保复位释放满足建立/保持时间
-
跨域信号处理:
- SPI忙信号(config_end)为单时钟脉冲
- 直接驱动状态机,无需额外同步
6. 仿真验证方法
6.1 测试平台架构
测试平台采用自检式设计,主要组件包括:
-
时钟和复位发生器:
- 产生24MHz和100MHz时钟
- 产生上电复位序列
-
DUT实例:
- 被测设计顶层模块
- 包含所有功能模块
-
SPI从设备模型:
- 模拟MCP2515行为
- 响应寄存器读写操作
-
CAN帧生成器:
- 产生标准帧和扩展帧测试用例
- 随机生成数据内容
-
结果检查器:
- 比较发送和接收数据
- 报告测试通过/失败
6.2 仿真运行方法
-
行为级仿真:
code复制# 在ModelSim中运行仿真 vsim -novopt work.tb_top run 500us- 快速验证功能正确性
- SPI时钟设为1MHz
- 约500μs可完成完整帧测试
-
时序级仿真:
code复制# 反标SDF文件后仿真 vsim -sdfmax /dut=post_synth.sdf work.tb_top run -all- 使用综合后生成的时序信息
- 检查100MHz下的时序余量(>0.5ns)
-
自动化检查:
- 测试平台会在环回测试通过后打印"SIMULATION PASSED"
- 失败时会指出第一个不匹配的数据位置
7. 实际应用指南
7.1 平台移植说明
-
Altera平台:
- 使用altpll生成时钟
- 输出100MHz(0°)、100MHz(-90°)和16MHz时钟
- 提供Quartus II 13.0工程文件
-
Xilinx平台:
- 使用clk_wiz生成时钟
- 等效时钟配置
- 提供ISE/Vivado TCL脚本自动生成PLL
-
引脚分配:
- 核心接口仅需9个引脚:
- clk, rst_n
- spi_sck, spi_mosi, spi_miso, spi_cs
- can_osc1, can_rst_n, TX0RTS
- 其余引脚可自由分配
- 核心接口仅需9个引脚:
7.2 性能优化建议
-
降低延迟:
- 将SPI时钟从1MHz提升到5MHz
- 优化状态机跳转条件
-
提高吞吐量:
- 使用双缓冲机制(TXB0和TXB1交替发送)
- 实现DMA式数据传输
-
资源优化:
- 共享部分寄存器读写逻辑
- 使用参数化设计减少冗余电路
8. 扩展应用方向
-
中断驱动设计:
- 将MCP2515的INT引脚接入FPGA
- 减少查询操作,降低功耗
-
发送队列增强:
- 添加异步FIFO缓冲
- 支持CPU通过总线接口写入数据
-
CAN-FD支持:
- 替换为MCP2517FD控制器
- 提升SPI时钟至20MHz
- 支持最高8Mbps数据段速率
-
双通道冗余:
- 例化两套独立CAN控制器
- 实现热备份冗余通道
9. 常见问题排查
9.1 初始化失败
症状:init_done信号未置位
- 检查SPI线序是否正确(MOSI/MISO是否接反)
- 确认MCP2515供电电压(3.3V或5V)
- 测量晶振是否起振(16MHz)
9.2 无法接收报文
排查步骤:
- 确认总线终端电阻(120Ω)已连接
- 检查CANH/CANL信号波形
- 验证滤波器设置是否过于严格
9.3 发送超时
可能原因:
- TXREQ位未清零:检查总线负载是否过重
- SPI通信错误:用逻辑分析仪抓取SPI波形
- 波特率不匹配:确认两端设备配置一致
9.4 资源占用过高
优化建议:
- 检查是否启用了未使用的功能模块
- 优化状态机编码方式
- 考虑使用资源共享技术
10. 工程文件说明
提供的完整工程包含以下内容:
-
源代码目录:
- Altera/ - Quartus II工程
- Xilinx/ - ISE/Vivado工程
- src/ - 通用Verilog源码
- tb/ - 测试平台文件
-
文档资料:
- 用户手册.pdf - 详细使用说明
- 寄存器映射.xlsx - MCP2515寄存器参考
- 时序图.vsd - 关键时序波形
-
工具链支持:
- Quartus II 13.0安装包
- ModelSim仿真脚本
- 引脚分配约束文件
这套方案已经在多个工业现场得到验证,稳定运行超过10,000小时。其纯硬件实现方式特别适合对实时性要求高的应用场景,开发者可以基于此框架快速实现定制功能。
