2. 系统架构设计:ARM与FPGA的通信架构与数据流设计
好,咱们进入第二章。这一章我打算聊聊系统架构设计,说白了就是ARM和FPGA之间怎么“说话”,数据怎么“流动”。
很多刚入行的朋友,一上来就急着写代码,结果后面发现ARM和FPGA各干各的,数据传不过去,或者传得慢得要命。我早年就踩过这个坑,一个运动控制项目,ARM算好了轨迹,FPGA死活收不到,最后查出来是总线配置错了。嗯,咱们今天就把这个事彻底讲清楚。
2.1 通信架构选型:AXI4-Lite vs AXI4-Stream
ARM和FPGA通信,在Zynq或者STM32MP1这类异构芯片里,最常用的就是AXI总线。我个人习惯把AXI分成两类来理解:
- AXI4-Lite:轻量级,适合传控制指令、寄存器配置。一次传一个数据,简单可靠。
- AXI4-Stream:流式接口,适合传大批量数据,比如位置指令流、编码器反馈流。没有地址概念,只管往管道里灌数据。
你想想看,运动控制里,ARM下发“目标位置”、“速度模式”这种指令,用AXI4-Lite就够。但如果是连续轨迹插补,每毫秒要传几百个位置点,那就得上AXI4-Stream了。
核心原则:控制走Lite,数据走Stream。别混着用,否则调试起来你会想哭。
2.2 数据流设计:从ARM到FPGA的路径
我一般把数据流分成三个环节:
- ARM端:应用程序计算轨迹,通过Linux驱动或裸机程序,把数据写到AXI总线。
- 总线传输:数据经过AXI互联,到达FPGA的IP核。
- FPGA端:IP核解析数据,驱动电机控制逻辑。
这里有个关键点:数据一致性。ARM是32位或64位处理器,FPGA是并行逻辑,两边时钟域不同。我曾经遇到过ARM写了一半数据,FPGA就读走了,结果读到个半残废的数据,电机直接抖了一下。解决办法就是加握手信号,或者用双缓冲。
我的小技巧:在FPGA里做一个“数据有效”寄存器。ARM先写数据,再写“有效位”。FPGA检测到有效位为1,才去读数据。读完后清掉有效位。这样永远不会读到脏数据。
2.3 系统架构图
下面这张图是我自己画的,展示了ARM和FPGA之间的通信架构。你可以看到数据流和控制流是分开走的。
从图里你能看到,ARM端跑应用和驱动,通过AXI总线把控制指令和数据分别送到FPGA。FPGA这边有专门的接口模块来接收,然后转给电机控制逻辑。我个人习惯在FPGA里做一个寄存器映射表,ARM直接读写这些寄存器,就像操作内存一样简单。
2.4 寄存器映射表设计
这是实际项目中我常用的寄存器映射表。你设计的时候可以直接参考:
| 地址偏移 | 寄存器名称 | 位宽 | 读写属性 | 描述 |
|---|---|---|---|---|
| 0x00 | CTRL_REG | 32 | R/W | 控制寄存器(使能、复位、模式选择) |
| 0x04 | STATUS_REG | 32 | R | 状态寄存器(忙、错误、完成标志) |
| 0x08 | TARGET_POS_L | 32 | W | 目标位置低32位 |
| 0x0C | TARGET_POS_H | 32 | W | 目标位置高32位(64位位置指令) |
| 0x10 | CURRENT_POS_L | 32 | R | 当前位置低32位(编码器反馈) |
| 0x14 | CURRENT_POS_H | 32 | R | 当前位置高32位 |
| 0x18 | SPEED_CMD | 32 | W | 速度指令(浮点数格式) |
| 0x1C | DATA_VALID | 1 | W | 数据有效标志(写1触发FPGA读取) |
注意:地址偏移必须是4字节对齐,因为AXI4-Lite的最小传输单位是32位。我曾经图省事把偏移设成0x01,结果仿真没问题,上板子死活读不对。后来查了三天手册才发现这个坑。
2.5 数据流时序设计
数据流设计里,时序是最容易出问题的。我一般遵循这个流程:
- ARM写数据:先写TARGET_POS_L和TARGET_POS_H,再写SPEED_CMD,最后写DATA_VALID为1。
- FPGA检测:每个时钟周期检查DATA_VALID寄存器。如果为1,锁存所有数据,然后清DATA_VALID。
- FPGA执行:把锁存的数据送入电机控制状态机,开始运动。
- ARM查询:轮询STATUS_REG,等FPGA执行完,再发下一组指令。
这里有个性能问题:轮询太浪费CPU了。我建议用中断方式——FPGA执行完一个指令后,拉高一个中断信号给ARM。ARM收到中断再发下一条。这样CPU利用率能提高不少。
我的经验:如果运动控制周期要求很严(比如1ms以内),建议用AXI4-Stream + DMA。ARM配置好DMA,让数据自己流过去,CPU完全解放。我在一个六轴机器人项目里就是这么干的,效果非常好。
2.6 避坑指南
最后,我总结几个实际项目中容易踩的坑:
- 跨时钟域问题:ARM和FPGA可能跑在不同时钟下。所有跨时钟域的信号,必须做同步处理。我一般用两级触发器同步,或者用异步FIFO。
- 数据溢出:FPGA处理速度跟不上ARM发送速度时,数据会丢。解决办法是在FPGA里加FIFO,深度根据你的数据量来定。我一般设256深度,够用。
- 总线死锁:AXI协议有严格的握手要求。如果FPGA的从接口没按协议回复,总线可能卡死。建议用Xilinx或ST官方的AXI IP核,别自己从头写,除非你真的很闲。
嗯,这一章的内容差不多就这些。系统架构设计是运动控制的基础,架构没想好,后面写再多代码也是白搭。你先把ARM和FPGA怎么通信、数据怎么流搞清楚,后面章节咱们再深入具体的实现细节。