
简介一套基于Xilinx ZC706平台与ADI ADRV9009高性能收发器的完整HDL与no-os SDK工程适用于有意深入研究FPGA与高速数据转换器协同设计的工程师、研究生及嵌入式开发者。压缩包内共2000个文件约201MB核心文件涵盖Verilog/VHDL逻辑源码、SystemVerilog仿真测试平台、Vivado工程与IP配置xpr/xci、XDC/SDC时序约束以及用于裸机开发的C语言驱动与Makefile构建脚本目录结构清晰便于按功能模块检索。HDL设计围绕JESD204B高速接口、时钟管理、数据同步与回环测试展开SDK部分则包含寄存器映射配置、DMA读写及底层硬件抽象代码直接反映了从FPGA逻辑到软件驱动的完整信号链。目前已有3825人学习下载。借助这套工程开发者可快速搭建基于ZC706与ADRV9009的原型验证系统理解高速ADC集成中的关键技术点并在此基础上进行无线通信、雷达与测试测量等方向的二次开发。 拿到这个zc706_adrv9009.rar时我第一反应是松了口气——ZC706 和 ADRV9009 这对组合在无线通信原型验证里实在太常见了。常见到什么程度呢凡是做软件无线电、做基站算法验证、做射频前端自动测试的实验室多多少少都有一套 ZC706 配 ADRV9009 的板子躺在防静电台面上。但紧接着我就提醒自己文件名干净不代表里面的工程能一把跑通。Zynq SoC 的 PS 端要跑 LinuxPL 端要布局 JESD204B 高速串行接口射频端还得伺候 ADRV9009 的时钟、校准和链路对齐任何一个环节没对齐最后都会反映成dmesg里的一片错误日志。这篇我重点聊三个层面的东西这个压缩包背后到底是什么、怎么样让它按部就班地转起来、以及我折腾大半个月之后最想留给自己也留给别人的几条经验。如果你手头正好有一块 ZC706 加一块 ADRV9009或者你只是好奇一个.rar工程为什么能在实验室里引发这么多故事这篇都值得看完。1. 解压之前先搞清楚这个组合是什么1.1 ZC706 和 ADRV9009 各自扮演什么角色先把两个芯的身份摆清楚。ZC706 是 Xilinx Zynq-7000 系列里的中高端评估板核心是一片 XC7Z045 SoC。它最讨人喜欢的地方在于芯片里同时装了一颗双核 ARM Cortex-A9PS和一大片可编程逻辑PL。这意味着你可以把任务拆成两部分ARM 上跑 Linux 做管理、控制和参数下发FPGA 里做高速数据搬运、协议处理和实时逻辑这个架构和真实基站里“主控 基带”的分工非常接近。ADRV9009 则来自 ADI 的 RadioVerse 收发器家族它把两个接收通道、两个发射通道、两个观察接收通道集成在一个封装里频率范围能覆盖 75MHz 到 6GHz瞬时带宽可以做到 200MHz 这个量级。换句话说一台仪器想覆盖从短波到 Sub-6G 的频段它一个人就能扛下来而且它内部还自带数字预失真DPD相关处理这在做 4G/5G 类应用时特别有价值。用这套组合做开发典型场景包括5G/4G 基站算法的原型验证、宽带频谱监测、无线信号采集与回放、以及一些测试测量设备里的射频前端。它的价值在于你不需要在项目早期就画完整 PCB而是先在 ZC706 的 FPGA 里搭基带在 ADRV9009 上验证射频性能等算法和指标都确认了再去定制硬件。这也是为什么很多学校实验室和公司预研团队都愿意囤一块的原因。这两个家伙之间通过 FMC 连接器对接。ZC706 上的 FMC HPC 接口把 PS/PL 的高速引脚引给了外部板卡ADRV9009 的射频子卡就插在这个接口上。所以zc706_adrv9009这个命名其实是告诉你这不是一个纯软件项目而是一套包含 FPGA、射频、Linux 驱动和时钟树的软硬协同系统。任何一个层级的“想当然”都会在联调阶段变成实打实的加班。1.2 一个 .rar 背后通常隐藏了什么很多人从同事那里拷来一个.rar第一反应就是鼠标右键解压。我做项目这几年攒下的习惯是解压之前先看压缩包里的目录级数、文件数量和有没有 README。因为这种工程打包极少是某一个人从头写起的它更可能是 ADI 官方 HDL/驱动仓库的一个快照加上本地的修改痕迹再塞进一些已编译好的启动镜像。还原它的来源往往比立刻执行make更有价值。典型的zc706_adrv9009.rar里面应该能拆出这几块HDL 工程Vivado 工程文件、约束文件、AXI IPLinux 相关的内核补丁、设备树源文件和内核镜像no-OS 驱动如果要用裸机流程以及 U-Boot、BOOT.BIN、image.ub 这类已经能对着 SD 卡用的启动材料。如果你解压后一个 hdl 目录都没有或者在 docs 里找不到任何版本说明那这个包大概率不是完整参考设计只是某个同事从工作目录里打包了一半后面有你罪受。有些讲究的同事会在包名里加上日期或 git short hash比如zc706_adrv9009_20231026_3a9f2c1.rar遇到这种命名要先赞美他。如果只有光秃秃的zc706_adrv9009.rar那就多留个心眼包里没有版本信息的时候宁可先从 ADI 的官方仓库拉一版对应分支也不要直接拿里面的 BOOT.BIN 去烧。因为这类 BSP 镜像能用是运气不能用才是常态。2. 参考工程的标准骨架以及为什么它长这样2.1 一份典型目录树我在公司里接到过很多份类似打包虽然细节各不相同但骨架大体逃不开下面这个样子zc706_adrv9009/ ├── hdl/ │ ├── hdl_prj/ │ │ └── zc706/ │ │ └── adrv9009/ │ │ ├── system_top.v │ │ ├── system_project.tcl │ │ └── constraints/system_constr.xdc │ └── libraries/ # AXI 通用库 ├── linux/ │ ├── kernel/ # 内核源码或补丁 │ └── dts/ # 设备树源文件 ├── no-OS/ # 裸机驱动 ├── images/ │ ├── BOOT.BIN │ ├── image.ub │ └── boot.scr └── docs/ └── README.md这不是唯一标准但每个目录都有明确分工。HDL 目录解决的是“PL 侧的数据通路”具体包括 JESD204B 物理层 IP、DMA 引擎、AXI 接口linux 目录解决的是“驱动程序怎么认识这块板子”核心是 device tree 里那段 adrv9009 节点描述images 是别人已经编好的启动产物如果你信得过版本匹配可以直接拿来用。docs 往往是最先被忽略、又最值钱的部分。另外如果解压后发现缺少某个目录别急着骂上一位同事。ADI 把这些东西分开维护是有原因的不同用户需求差别很大有人只在 Linux 上用 IIO 工具做测试根本不关心 HDL有人只想做 no-OS 的裸机射频控制还有人专门改 PL 逻辑做自定义协议。把 HDL、驱动、镜像分开才能让不同类型的人各取所需。这也解释了你手上的.rar为什么可能缺目录——上一位使用者可能只跑了 Linux 流程就把 no-OS 文件夹删了。这对他的工作没有影响但传给你之后就成了坑。2.2 为什么这套设计要拆成这么多层可能有人问为什么不能像普通单片机和驱动那样一套代码全搞定原因在于 ADRV9009 的数据速率太高了。它和 FPGA 之间走的是 JESD204B 高速串行协议单通道速率可以到 Gbps 级别这种数据流不适合再往 ARM 总线上压也不适合用 GPIO 慢慢读。PS 端 Linux 的价值在于控制——配置频率、增益、校准状态但从天线上下来的流量必须由 PL 里的 DMA 直接接管。所以 HDL、Linux 驱动、设备树这三者必须作为一个整体发布设备树告诉内核哪里去找设备内核驱动负责对 ADRV9009 的 SPI 和中断进行操作HDL 则保证数据从芯片到内存的路径是通的。任何一个层级和另外两个的版本不匹配表现出来就是“设备没枚举出来”或者“枚举出来了却收不到数据”。这也是后面所有排查的出发点。3. 让 ZC706 ADRV9009 真正跑起来从 SD 卡到 IIO 设备出现3.1 启动前的物料和检查清单很多人第一步就栽在准备上。跑这套工程你至少要有一根串口线、一张 SD 卡、一条网线如果你希望用网络挂载文件系统以及一把好的 FMC 拆卸工具。跟 ZC706 打交道我建议按这个顺序检查SD 卡分两个区第一个区 FAT32 放 BOOT.BIN、image.ub、boot.scr第二个区 ext4 放根文件系统。ADI 官方镜像通常就是这么排的不要自己发明单分区。串口连到板上的 USB-UART速率 115200开始上电前就要进终端程序。FMC 连接器插到位。ADRV9009 板卡的插针很密插偏一两个引脚能带出很多诡异问题一定要确认卡扣已经压紧。板卡电源。ZC706 自身供电没问题但有的 FMC 子卡需要额外的外部电源具体看子卡丝印和官方说明。供电不稳时最容易出现“有时候能启动、有时候不能”的随机故障。把这些准备做好再上电看串口日志。另外很多人在第一次启动时喜欢用 JTAG 挂着看波形其实没必要。先通过串口把系统带起来确认软件链通了再上 JTAG 调试 PL 逻辑问题能定位得更干净。否则你会在一种混合了“Linux 驱动没起来”和“FPGA 时序没跑对”的复杂状态里来回打转非常消耗耐心。3.2 启动后判断系统是否“活了”上电后你会在串口里依次看到 U-Boot 打印、内核解压信息、然后进入 Linux。驱动是否正常不能只看有没有登录提示符。我一般会执行三个命令确认dmesg | grep -i -e adrv9009 -e hmc7044 iio_info | grep adrv9009 ls /dev/iio:device*iio_info里出现adrv9009-phy是最低目标。这代表内核已经成功通过 SPI 和 ADRV9009 握手设备树里的节点也匹配上了。不过这只是第一步我见过很多次adrv9009-phy正常列出但链路没有锁定读取的 IQ 数据完全不可用。所以看到设备节点别急着庆祝接下来要检查 JESD204B 那层。如果iio_info里什么都没出现先别急着重新编译内核。绝大多数情况出在三个地方FMC 没插好、HMC7044 时钟没有初始化、设备树节点被status属性关掉了。这三个问题都可以在上电日志里找到蛛丝马迹所以保存完整dmesg不是洁癖是救命。4. JESD204B 链路没锁定最折磨人的排查现场4.1 链路为什么值得单独开一章JESD204B 是 ADC/DAC 和 FPGA 之间最关键也最脆弱的传送带。它把原来并行的 LVDS 数据线收敛成几对高速串行线好处是引脚少、速率高坏处是任何一端参数没对齐数据就乱掉。ADRV9009 在和 FPGA 通信时需要同时满足几个条件参考时钟存在且频率正确SYSREF 按照本地多帧时钟LMFC周期稳定送过来lane rate 和 SerDes 的线速率一致链路层参数与 FPGA 里的 JESD204B IP 配置一致。这里头任何一个不对寄存器里看到的都是同一个结果链路未锁定。用类比来理解device clock 是工厂的流水线节拍SYSREF 是每天早上对表的广播时间lane 是一条条传送带。节拍不对传送带速度就不对对表频率不对多芯片之间的相位就对不齐传送带数量或宽度与后端不匹配箱子到了终点也没人接。JESD204B 的调试本质上就是把这几个“对不齐”逐个找出来。4.2 一次真实排查的记录我最近调一块板子时遇到的现象是完全按参考工程的镜像启动adrv9009-phy就是不出来dmesg 最后一行停在某个校准或者 SPI 读写的重试上。我第一件事不是去翻 HDL而是把时钟芯片 HMC7044 的 probe 日志和 devicetree 里 adrv9009 节点的 status、compatible、interrupt 都对照了一遍——很多所谓“驱动不起来”其实是中断号写错或者时钟树初始化失败。确认时钟芯片正常工作后我用devmem读 PL 侧 AXI JESD204B 核的状态寄存器发现 RX 状态一直停在 PLL 未锁定。到这里才把目光集中到 lane rate 上。我把设备树里 adrv9009 的 lane rate 配置和 HDL 工程里的约束逐项比对发现启动镜像用的设备树和 HDL 不是同一个版本lane rate 差了一档。修正后重启链路从 PLL lock 到 link ready 一路变绿。这类问题之所以折磨人不是因为它难而是因为现象不唯一。同样的报错可能是电源、时钟、SPI、中断、HDL 版本五个原因里的任何一个。我的经验是不要上来就动焊台或者改 IP先按“电源→时钟→链路参数→上层配置”的顺序排查每一层都有明确证据再往下走。4.3 最容易踩的三处配置如果让我给新手划重点JESD204B 相关的坑可以浓缩成三句话SYSREF 不是想给就给。它在 LMFC 边界附近有效频率和极性必须与 JESD204B 核一致否则多芯片同步永远成功不了。lane rate 必须三方一致。HDL 工程、ADRV9009 配置、设备树里的数值是三份文档必须互相咬合。链路锁定不等于数据正确。即使 link readyI/Q 顺序、采样位宽、通道映射错一位抓出来的频谱就是乱的这类问题不显示在寄存器里的。确认数据正确性的唯一办法是抓一段数据做频域分析。这部分我在后面还会提到。但先把结论放在这里JESD204B 是这套系统里最没有商量余地的地方也是你拿到陌生.rar后最应该先验证的部分。5. 收发链路验证从“能看到设备”到“看到信号”5.1 用 libiio 工具做一次最基本的自环等链路锁定后下一步就是用数据证明链路是通的。最简单可靠的办法就是射频自环拿一根射频线把 ADRV9009 的 TX1 输出连到 RX1 输入。切记在 TX 和 RX 之间串一个 20~30dB 的衰减器。发射端输出功率再温柔也可能超出接收链路的耐受范围衰减器是保命用的。然后打开终端用 Linux 下常见的 IIO 命令折腾几个参数# 把收发本振设到一样的位置 iio_attr -c adrv9009-phy tx0 TX_LO frequency 2400000000 iio_attr -c adrv9009-phy rx0 RX_LO frequency 2400000000 # 配置发射通道使能和接收通道使能 iio_attr -c adrv9009-phy tx0 TX1_ENABLE 1 iio_attr -c adrv9009-phy rx0 RX1_ENABLE 1不同版本的驱动和 API 在属性名上会有差异有的版本叫TX_LO有的环境里更喜欢用 pyadi-iio 直接写脚本。条条大路通罗马核心动作就三件事设 LO、开通道、设置增益或衰减。抓数据我一般用iio_readdev或写一段 Python 调用 pylibiio把 RX 的样本流读出来再扔给 numpy 做 FFT。如果你在中心频点上看到一个干净的峰值说明整条链路——从 PS 到 PL、再到 JESD204B、再到 ADRV9009 的模拟收发——已经全通了。这个测试虽然简单却是我换任何一块新板子时必做的项目。5.2 校准、增益和那些不在文档里的延迟ADRV9009 毕竟不是一颗简单 ADC它在驱动加载时或者运行时要做不少校准。初始化校准时需要参考时钟稳定而且可能要持续几秒钟。如果你发现驱动 probe 之后系统卡顿或iio_attr响应很慢先别急着下结论等校准完成再说。温度变化、电源纹波过大、LO 泄漏都会让自环结果变得不干净。我看到过一个现象自环频谱在基带附近有几根毛刺查了很久发现是 FMC 插座的接触不良导致的。这种问题不在软件控制范围内只能靠重新插拔和检查电源来排除。另一个建议是正式做射频指标验证时别把 libiio 的软件校准和仪器测试混在一起。自环只是证明通路天线口的真正性能还是要用频谱仪和信号源去量。6. 折腾完这一圈我最想留下的几条经验6.1 时刻盯着“版本组合”这个隐形变量我踩过最深的一个坑压缩包里的镜像其实是别人对着一个旧版 HDL 编出来的而我用的是新版的 device tree。结果表现出来的症状就像拉肚子一样毫无规律——有时候重启两次能好有时候完全不行。后来我养成了习惯先花十分钟确认 Vivado 版本、HDL 分支、Linux 分支和 device tree 是不是同一套发布组合再花十分钟去解压。这里放一张我常用的对照思路表不是死数据但可以帮助你建立版本意识配置项影响范围不匹配时的常见现象Vivado 版本HDL 综合与 IP 核生成bitstream 生成失败或者 IP 行为异常HDL 分支 / commitPL 侧 JESD204B 硬逻辑链路无法锁定DMA 无数据Linux 内核版本adrv9009 驱动与 jesd204 框架设备不枚举属性缺失设备树文件资源映射、中断号、lane rateprobe 失败或者频率参数错乱U-Boot / BOOT.BIN启动硬件的初始配置起不来或者 PL 配置不生效看到这张表你就明白“为什么我跑别人的镜像不行”很多时候根本不是硬件问题而是这套软硬件组合的水土不服。6.2 先跑通原厂默认再谈自由发挥ADRV9009 的寄存器配置量相当大滤波器系数、校准矩阵、DPD 参数、射频配置全靠一套初始化序列。官方默认配置不一定是最优的但它一定是在参考硬件的约束下验证过的组合。我见过同事上来就把 DTS 里发射通道的频段和增益表改了一通结果自环收不到信号折腾三天后改回默认配置所有问题当场消失。这不是说不能改而是说改之前你得有工具能对比原厂校准值和修改后的差异纯靠手敲驱动属性去试错效率太低。想验证自定义参数常规路线是用 ADI 的 TESTransceiver Evaluation Software这类工具把工程配置导出来再烧进板子而不是在 Linux 命令行里东改一下西改一下。命令行适合验证通路不适合做量产级射频参数调试。6.3 拿到.rar之后动手之前先做这五件事用sha256sum做完整性校验避免拿到半截压缩包。在 Linux 环境下解压Windows 自带的解压工具经常会丢符号链接、可执行权限和长文件名。找版本说明。README、version.txt、.git目录里的 log任何一行版本记录都比凭空猜强。对照 ADI 官方的 HDL / linux wiki 页面确认目录结构没有缺项。缺了 HDL 还能靠官方仓库补缺了文档就只能靠猜。上电前连接好串口上电后第一时间保存dmesg完整日志。等到出了问题再回看日志很多东西已经被你冲掉了。如果以上这些都做完了那你已经比这个.rar的上一任使用者更了解这套系统了。本文还有配套的精品资源点击获取