ZYNQ-双核AMP实战:基于OCM与软件中断的数据接力通信

张开发
2026/4/17 11:56:42 15 分钟阅读

分享文章

ZYNQ-双核AMP实战:基于OCM与软件中断的数据接力通信
1. ZYNQ双核AMP通信基础解析第一次接触ZYNQ双核通信的朋友可能会觉得有点懵这玩意儿到底是个啥简单来说就是让ZYNQ芯片里的两个ARM核CPU0和CPU1能够互相配合干活。想象一下就像两个工人在流水线上协作一个负责接收原材料CPU0接收串口数据一个负责加工成品CPU1处理数据并输出中间通过传送带OCM共享内存传递半成品。这种架构在工业控制领域特别常见比如一个核负责实时采集传感器数据另一个核负责复杂算法处理。我去年做过一个智能电表项目就是用CPU0采集电压电流CPU1进行FFT谐波分析效果相当不错。关键点在于双核通信需要解决三个核心问题内存共享OCMOn-Chip Memory是片上存储访问速度快适合做数据中转站中断同步软件中断就像两个工人之间的对讲机一个干完活了就呼叫另一个缓存一致性必须处理好Cache否则会出现看到的数据不是最新值的灵异现象2. 硬件平台搭建实战2.1 Vivado工程创建打开Vivado 2018.3其他版本操作类似新建工程时有个坑要注意工程路径绝对不能有中文我吃过亏编译时会报各种莫名其妙的错误。具体步骤如下创建Block Design后添加ZYNQ7 Processing System IP核双击IP核配置在PS-PL Configuration里确保两个CPU都启用Peripheral I/O Pins里勾选UART1用于调试输出Clock Configuration里保持默认的33.33MHz即可有个实用技巧配置完成后建议先Validate Design检查下有时候Vivado会漏报一些配置冲突。曾经有个项目因为没检查烧录后串口死活不工作折腾了一整天。2.2 地址空间规划ZYNQ的内存映射是双核通信的基础必须搞清楚几个关键地址DDR内存默认0x00100000~0x1FFFFFFFOCM区域0xFFFF0000~0xFFFFFFFFCPU1启动地址0x10000000这个要记牢后面会反复用到在lscript.ld链接脚本里修改时要注意地址对齐问题。有次我把CPU0的DDR空间设为0x0FF12345结果程序直接跑飞。后来发现必须按1MB对齐改成0x0FF00000就正常了。3. 软件中断机制剖析3.1 中断控制器配置ZYNQ的GICGeneric Interrupt Controller支持多种中断类型我们这个项目用的是软件触发中断Software Generated Interrupt。配置时要注意// 中断ID定义必须和硬件一致 #define SOFT_INTR_ID_TO_CPU0 0 #define SOFT_INTR_ID_TO_CPU1 1 // 初始化代码模板 XScuGic_Config *intc_cfg_ptr XScuGic_LookupConfig(INTC_DEVICE_ID); XScuGic_CfgInitialize(Intc, intc_cfg_ptr, intc_cfg_ptr-CpuBaseAddress);实测发现中断优先级设置不当会导致丢失中断。建议保持默认优先级除非有特殊需求。我在一个电机控制项目里就因为把通信中断优先级设得太低导致数据包丢失率高达30%。3.2 中断服务程序中断处理函数要遵循快进快出原则千万别在里面做复杂运算。下面是经过优化的处理函数void soft_intr_handler(void *CallbackRef) { // 仅设置标志位主循环中处理实际任务 soft_intr_flag 1; // 清除中断状态关键 XScuGic_ACK_INT(Intc, SOFT_INTR_ID_TO_CPU1); }曾经有个bug让我debug了两天忘记清除中断状态位结果中断只触发一次就再也不响应了。后来加上ACK操作立马解决。4. OCM共享内存使用技巧4.1 Cache一致性处理OCM默认是带Cache的这会导致双核看到的数据不一致。必须通过MMU修改属性// 关键参数说明 // TEX100, S1 → 共享设备内存 // AP11 → 全权限访问 // CB0 → 禁用Cache和Buffer Xil_SetTlbAttributes(SHARE_BASE, 0x14de2);有个性能优化技巧如果通信数据量大可以启用Cache但需要配合使用Xil_DCacheFlush()和Xil_DCacheInvalidate()来手动维护一致性。我在视频处理项目中这样做吞吐量提升了8倍。4.2 数据校验机制工业级应用必须考虑数据可靠性。建议在OCM通信时添加CRC校验// 数据结构定义 typedef struct { char payload; uint8_t crc; } SafeData; // CRC8计算简单实现 uint8_t calc_crc(char data) { return (data ^ 0xFF) 1; }去年有个风电项目就因为没加校验强电磁干扰导致数据位翻转造成控制系统误动作。加上CRC后问题彻底解决。5. 双核程序固化指南5.1 FSBL定制生成FSBL时要注意勾选Initialize OCM选项否则CPU1可能无法正常启动。具体操作创建FSBL工程时在bsp设置里添加-DOCM_INIT标志修改fsbl_hooks.c中的OcmInit()函数确保FSBL正确初始化了0xFFFFFFF0地址的内容5.2 多核镜像打包SDK生成BOOT.bin时顺序很重要FSBL.elfsystem.bitPL配置cpu0_app.elfcpu1_app.elf有个常见错误是把cpu1程序放在bit文件前面导致启动失败。建议使用批处理脚本自动打包bootgen -image boot.bif -arch zynq -o BOOT.bin -w on6. 调试经验分享6.1 常见问题排查双核不同步先用Xilinx SDK的Debug视图检查两个核是否都在运行数据不一致在OCM访问前后添加printf打印地址和值中断不触发用XSCT命令查看GIC寄存器状态# XSCT调试命令示例 connect targets -set -filter {name ~ Cortex-A9 #1} rst -processor6.2 性能优化通过实测发现几个优化点将OCM通信缓冲区改为32位对齐速度提升40%使用DMB指令保证内存访问顺序稳定性大幅提高中断处理延迟控制在100个时钟周期内在智能网关项目中经过这些优化后双核通信延迟从1.2ms降到了200μs以内。

更多文章