Zynq-7000双CAN控制器开发实战:时钟配置与波特率计算全解析
在嵌入式系统开发中,CAN总线因其高可靠性和实时性被广泛应用于工业控制、汽车电子等领域。Xilinx Zynq-7000系列SoC因其独特的PS(Processing System)和PL(Programmable Logic)架构,为开发者提供了灵活的双CAN控制器实现方案。本文将深入探讨如何在Zynq-7000平台上同时配置PS端和PL端的CAN控制器,重点解决时钟配置差异带来的波特率计算难题。
1. Zynq-7000双CAN架构概述
Zynq-7000的PS端内置了CAN控制器,而PL端可以通过IP核实现额外的CAN功能。这种双CAN架构为复杂系统设计提供了更多可能性,但也带来了配置上的挑战:
- PS端CAN控制器:集成在ARM处理器子系统内,时钟固定为100MHz
- PL端CAN控制器:通过AXI接口连接,时钟频率由PL设计决定
- 共享特性:两者都支持标准CAN 2.0B协议,但寄存器配置方式不同
提示:在实际项目中同时使用PS和PL CAN时,建议为每个控制器分配不同的消息ID范围,避免总线冲突。
2. 开发环境准备与例程导入
开始双CAN开发前,需要确保开发环境正确配置:
硬件准备:
- Zynq-7000开发板(如ZC702、Zybo等)
- CAN收发器(如TJA1050)
- USB-CAN适配器(用于调试)
软件工具:
- Vivado设计套件(版本建议2018.3或更新)
- Xilinx SDK或Vitis统一开发环境
- CAN总线分析工具(如PCAN-View)
导入基础例程:
# 在Vivado中创建Zynq硬件平台后 # 导出硬件到SDK/Vitis # 在BSP中启用CAN驱动支持
在SDK中导入polled例程的步骤如下:
- 打开
system.mss文件 - 选择"Import Examples"
- 勾选"CAN Polled Mode Example"
- 为PS和PL CAN分别创建工程实例
3. PS端CAN控制器配置详解
PS端CAN控制器的时钟固定为100MHz,这简化了波特率计算过程。以下是关键配置步骤:
3.1 波特率计算原理
CAN波特率计算公式为:
波特率 = 时钟频率 / (BRP × (1 + TSEG1 + TSEG2))其中:
- BRP:波特率预分频值(BRPR寄存器)
- TSEG1:时间段1(BTR寄存器位16-20)
- TSEG2:时间段2(BTR寄存器位20-23)
典型100Kbps配置参数:
| 参数名 | 值 | 说明 |
|---|---|---|
| BRP | 49 | 预分频系数 |
| TSEG1 | 15 | 时间段1 |
| TSEG2 | 3 | 时间段2 |
| SJW | 2 | 同步跳转宽度 |
计算验证:
100MHz / ((49+1) × (1+15+3)) = 100,000 bps3.2 SDK中的配置实现
在SDK中通过以下API完成配置:
// 初始化CAN控制器 XCanPs_Config *ConfigPtr = XCanPs_LookupConfig(DEVICE_ID); XCanPs_CfgInitialize(&CanInstance, ConfigPtr, ConfigPtr->BaseAddr); // 进入配置模式 XCanPs_EnterMode(&CanInstance, XCANPS_MODE_CONFIG); // 设置波特率参数 XCanPs_SetBaudRatePrescaler(&CanInstance, 49); XCanPs_SetBitTiming(&CanInstance, 2, 15, 3); // 进入回环测试模式 XCanPs_EnterMode(&CanInstance, XCANPS_MODE_LOOPBACK);注意:在修改波特率参数前,必须确保CAN控制器处于配置模式(CONFIG mode)。
4. PL端CAN控制器特殊配置
PL端CAN控制器的配置流程与PS端类似,但时钟频率可能不同,这是最大的差异点。
4.1 确定PL CAN时钟频率
PL端CAN控制器的时钟通常由以下方式提供:
通过AXI总线时钟分频:
// 在Vivado Block Design中 // 使用Clock Wizard生成所需频率外部晶振直接输入:
- 需要检查原理图确认时钟频率
- 常见值为20MHz、40MHz等
通过PL逻辑分频:
// 使用Verilog代码实现时钟分频 reg [7:0] counter; always @(posedge clk100m) begin counter <= counter + 1; can_clk <= counter[7]; // 产生约390KHz时钟 end
4.2 PL CAN波特率计算示例
假设PL CAN时钟为50MHz,计算125Kbps配置:
- 选择BRP=19,TSEG1=15,TSEG2=4
- 计算验证:
50MHz / ((19+1) × (1+15+4)) = 125,000 bps
对应的SDK配置代码:
// PL CAN初始化(与PS API相同) XCanPs_Config *PlConfig = XCanPs_LookupConfig(PL_CAN_DEVICE_ID); XCanPs_CfgInitialize(&PlCanInstance, PlConfig, PlConfig->BaseAddr); // 设置PL特有波特率参数 XCanPs_SetBaudRatePrescaler(&PlCanInstance, 19); XCanPs_SetBitTiming(&PlCanInstance, 2, 15, 4);5. 双CAN协同工作与调试技巧
在实际项目中同时使用PS和PL CAN控制器时,需要注意以下要点:
5.1 消息ID分配策略
为避免总线冲突,建议采用分层ID分配方案:
- PS CAN:0x000-0x3FF(高优先级控制消息)
- PL CAN:0x400-0x7FF(数据采集消息)
- 广播消息:0x7FF(系统状态通知)
5.2 常见调试问题排查
CAN总线无通信:
- 检查收发器供电
- 测量CANH/CANL差分电压(正常约2V)
- 确认终端电阻(通常为120Ω)
波特率不匹配:
- 使用示波器测量实际波特率
- 检查时钟源配置是否正确
- 验证BRPR/BTR寄存器值
数据帧错误:
- 确认发送/接收ID匹配
- 检查数据长度码(DLC)
- 验证CRC校验
5.3 性能优化建议
中断与DMA配置:
// 启用CAN接收中断 XCanPs_SetHandler(&CanInstance, XCANPS_HANDLER_RECV, (void *)CanRecvHandler, &CanInstance); XCanPs_IntEnable(&CanInstance, XCANPS_IXR_RXNEMP_MASK);总线负载监控:
- 定期检查错误计数器
- 实现简单的总线负载统计
uint32_t calc_bus_load(uint32_t msg_count, uint32_t msg_size) { // 标准CAN帧:47位仲裁 + 数据位 + 15位帧间空间 uint32_t bit_per_frame = 47 + (msg_size * 8) + 15; return (msg_count * bit_per_frame) / (baudrate / 10); }
6. 进阶应用:CAN FD兼容性设计
虽然Zynq-7000原生不支持CAN FD,但可以通过PL实现兼容方案:
软核实现:
- 使用开源CAN FD IP核
- 配合DMA提高吞吐量
时钟要求:
- CAN FD需要更高频率时钟(通常≥80MHz)
- 在PL中需使用MMCM/PLL生成
数据场处理:
// 扩展帧处理示例 if (RxFrame.Identifier & XCANPS_IDR_IDE_MASK) { // 处理扩展帧 uint32_t ext_id = RxFrame.Identifier & 0x1FFFFFFF; }
在最近的一个工业控制器项目中,我们同时使用了PS CAN和PL CAN,PS端处理关键控制命令(100Kbps),PL端负责传感器数据采集(500Kbps)。这种架构既保证了控制指令的实时性,又满足了大数据量的传输需求。实际调试中发现,PL CAN的时钟稳定性对通信质量影响很大,最终我们选择了独立的40MHz振荡器作为时钟源,通信误码率显著降低。