1. 从一块板卡说起:为什么ZYNQ+AD9361的组合值得反复琢磨
第一次拿到璞致PZSDR系列板卡的时候,我盯着上面那颗ZYNQ和AD9361看了很久。不是因为没见过,而是因为这个组合在宽频射频圈子里实在太经典了——经典到几乎每个做软件无线电的团队都会在某个阶段绕回这套架构。ZYNQ负责逻辑与协议栈,AD9361负责射频收发,两者通过LVDS和SPI咬合在一起,形成一个从基带到天线的完整链路。
但经典不等于简单。我见过太多人在调试AD9361初始化时卡住,0x247寄存器读出来永远是0x80,CP OVRG HIGH被置位,RX PLL死活锁不上。也见过有人在ZYNQ裸机环境下折腾USB通信,翻遍文档才发现libusb的方案在裸机下根本跑不通。这些坑,璞致PZSDR系列板卡的用户大概率都会遇到,因为这套硬件把ZYNQ和AD9361的能力都拉满了,暴露出来的细节自然也更多。
这篇内容适合谁看?如果你正在评估PZSDR系列板卡是否适合你的宽频射频项目,或者已经上手但被初始化、DMA、固化烧写这些问题绊住了,那接下来的内容应该能帮你省下不少时间。我会从硬件架构的底层逻辑讲起,把ZYNQ和AD9361之间的配合关系拆开,然后落到具体的调试场景和实操步骤上。不堆砌手册里能查到的东西,重点讲那些手册不会告诉你、但实际调试中一定会碰到的细节。
2. ZYNQ与AD9361的咬合关系:异构架构到底异构在哪
2.1 为什么不是纯FPGA或纯处理器
很多人第一次接触这个架构时会问:既然AD9361是射频前端,为什么不用一颗纯FPGA来驱动,非要塞一颗ARM核进去?这个问题背后其实是对异构架构本质的理解。
纯FPGA方案的问题在于,射频链路的控制面太复杂了。AD9361有上百个寄存器需要配置,增益控制、滤波系数、采样率切换、校准流程,这些如果全部用状态机在FPGA里实现,逻辑资源消耗大不说,调试起来极其痛苦。而纯处理器方案的问题正好相反,ARM核跑Linux或裸机,处理控制面很舒服,但基带数据的实时处理根本扛不住,采样率稍微高一点就丢包。
ZYNQ的PS-PL架构恰好把这两件事分开了。PL端负责硬实时的数据通路,比如ADC/DAC接口、数字上下变频、DMA搬运;PS端负责控制面,跑协议栈、做参数计算、管理AD9361的寄存器配置。两者通过AXI总线交互,各干各擅长的事。璞致PZSDR系列板卡把这个分工做得很清晰,PL端的引脚分配和PS端的外设映射都是围绕AD9361的接口需求来设计的。
2.2 AD9361的接口时序对ZYNQ PL端提出的硬约束
AD9361和ZYNQ之间的数据接口是LVDS差分对,分为RX和TX两组。RX方向,AD9361输出12位I/Q数据,伴随帧同步信号和时钟;TX方向反过来,ZYNQ输出数据给AD9361。这个接口的时序约束非常紧,尤其是DDR模式下,数据在时钟的上下沿都要采样。
我在实际调试中发现,璞致PZSDR板卡的LVDS走线长度匹配做得不错,但如果你自己改板或者换用其他载板,一定要用示波器确认眼图。曾经有个项目因为LVDS差分对的走线差了5mm,导致RX数据偶尔出现位错误,查了两天才定位到是PCB走线问题。ZYNQ的SelectIO资源支持IDELAY和ISERDES,可以在一定程度上补偿时序偏差,但前提是你得知道怎么用。
SPI接口相对简单,但AD9361的SPI时序有个坑:它支持4线模式和3线模式,璞致板卡默认是4线。如果你在ZYNQ端配置SPI控制器时没注意模式匹配,会出现读写寄存器返回值全为0的情况。这个后面讲初始化的时候会详细说。
2.3 时钟树设计:一颗晶振如何撑起整个射频链路
AD9361需要的外部时钟只有一颗参考晶振,通常是40MHz。这颗时钟进入AD9361后,内部PLL会生成射频本振、采样时钟、数字接口时钟。但ZYNQ端也需要一个时钟来同步LVDS接口,这个时钟从哪来?
璞致PZSDR系列板卡的做法是让AD9361输出一个DATA_CLK给ZYNQ,ZYNQ用这个时钟来采样RX数据并生成TX数据。这样做的好处是收发时钟天然同步,不需要额外的时钟域转换。但代价是ZYNQ的PL端逻辑必须在这个时钟域下工作,如果你的基带处理逻辑跑在另一个时钟域,就得做跨时钟域处理。
我实测下来,DATA_CLK的频率跟采样率相关,AD9361在不同采样率下输出的DATA_CLK频率不同。如果你在运行时动态切换采样率,ZYNQ端的逻辑必须能适应时钟频率的变化,否则会出现数据错位。这一点在官方例程里往往被简化处理了,实际项目中需要特别注意。
3. AD9361初始化:从0x247寄存器读出0x80说起
3.1 初始化流程的完整链路
AD9361的初始化不是简单地写几个寄存器就完事。完整的流程包括:SPI接口验证、基带PLL配置、射频PLL配置、采样率设定、滤波器加载、增益模式设置、校准触发。每一步都有依赖关系,顺序错了后面全乱。
我习惯把初始化分成三个阶段。第一阶段是SPI通信验证,读AD9361的版本寄存器,确认返回值正确。第二阶段是时钟和PLL配置,包括基带PLL和射频PLL的锁定。第三阶段是数据通路配置,包括接口模式、数据格式、增益控制。
璞致PZSDR板卡的参考设计里提供了一套初始化序列,但那是针对特定频段和采样率调好的。如果你的应用需要不同的采样率或频段,必须自己重新生成初始化参数。AD9361的官方评估软件可以导出寄存器配置脚本,但那个脚本是给FPGA用的,移植到ZYNQ上需要做适配。
3.2 0x247寄存器读出0x80的根因分析
0x247是AD9361的校准控制寄存器之一,正常情况下写入特定值后读回应该反映校准状态。如果你读出来一直是0x80,说明校准没有完成或者SPI通信有问题。
我排查这个问题的顺序是这样的:先确认SPI读写是否正常,读一个已知的只读寄存器比如版本号,看返回值对不对。如果版本号都不对,那就是SPI接口的问题,检查片选、时钟极性、相位这些。如果版本号对但0x247不对,那就是校准流程没走完。
常见的原因有几个:一是基带PLL没有锁定,导致后续校准无法进行;二是参考时钟频率不对,AD9361内部PLL算出来的分频比超出范围;三是初始化序列中遗漏了某个必要的写操作。我遇到过最隐蔽的一次是SPI时钟频率太高,AD9361在某个温度下响应不过来,降频到10MHz以下就正常了。
3.3 CP OVRG HIGH与RX PLL失锁的关联
CP OVRG是Charge Pump Overrange的缩写,这个标志置位说明电荷泵的输出超出了正常范围,通常意味着PLL环路滤波器参数不对或者VCO频段选择错误。RX PLL失锁和CP OVRG往往是同时出现的,因为电荷泵过载会直接导致环路无法锁定。
解决这个问题的关键是检查VCO频段配置。AD9361的RX PLL有一个VCO工作频段表,你需要根据目标本振频率选择正确的频段。如果频段选错了,VCO输出频率偏离太远,电荷泵就会过载。璞致板卡的参考设计里通常会给一个频段对照表,但如果你改了参考时钟频率,这个表就得重新算。
我自己的经验是,先用AD9361的官方评估软件算出目标频率对应的VCO频段和分频比,然后手动写入寄存器,不要依赖自动校准。自动校准在参考时钟有偏差的时候容易选错频段,手动指定反而更可靠。
3.4 初始化调试的实操检查清单
下面这个清单是我调试AD9361初始化时必查的项目,按顺序执行可以覆盖大部分问题:
| 检查项 | 正常表现 | 异常处理 |
|---|---|---|
| SPI版本寄存器读取 | 返回0x0A或0x0B | 检查SPI模式、片选、时钟频率 |
| 基带PLL锁定 | 锁定标志置位 | 检查参考时钟频率和分频比 |
| 射频PLL锁定 | 锁定标志置位 | 检查VCO频段和电荷泵电流 |
| 0x247校准寄存器 | 校准完成后返回预期值 | 确认前序步骤全部完成 |
| DATA_CLK输出 | 频率与采样率匹配 | 检查接口模式和时钟使能 |
| RX/TX数据通路 | 环回测试数据正确 | 检查LVDS时序和IDELAY设置 |
注意:每次修改初始化参数后,建议完整复位AD9361再重新配置,不要试图在运行中修改关键寄存器。AD9361的某些寄存器在PLL锁定后修改会导致不可预期的行为。
4. ZYNQ端的工程落地:从裸机USB到DMA数据搬运
4.1 裸机USB通信方案的选择困境
ZYNQ的PS端有USB控制器,但在裸机环境下使用USB并不是一件轻松的事。Xilinx的Standalone库提供了USB控制器的驱动,但只支持Host和Device模式的基本功能,要实现自定义的数据传输协议需要自己写类驱动。
我试过基于libusb的方案,但在裸机下libusb根本跑不起来,因为它依赖操作系统的USB子系统。裸机下可行的方案有两种:一是把ZYNQ的USB控制器配置成Device模式,自己实现一个简单的Bulk传输协议;二是用USB Host模式,通过EHCI控制器枚举外接设备。
璞致PZSDR板卡的参考设计里通常会用USB来做调试通道或者数据回传。如果你只是传一些控制命令和低速数据,Device模式下的Bulk传输足够了。但如果你要传高速采样数据,USB2.0的带宽(理论480Mbps,实际300Mbps左右)可能不够用,这时候就得考虑用千兆以太网或者PCIe。
4.2 ZYNQ DMA的配置逻辑与带宽计算
ZYNQ的PL端有专门的DMA控制器,通常用AXI DMA IP核来实现。配置DMA的时候有几个关键参数需要计算:突发长度、FIFO深度、数据位宽。
以AD9361的12位I/Q数据为例,假设采样率是30.72MSPS,那么单通道数据率是30.72M * 12bit = 368.64Mbps,I/Q两路加起来约737Mbps。如果DMA的数据位宽是64位,时钟频率是100MHz,理论带宽是6.4Gbps,看起来绰绰有余。但实际中DMA的效率受限于总线仲裁和内存带宽,通常只能达到理论值的60%到70%。
我一般会留出50%的余量,也就是说如果计算出来需要737Mbps,我会选择能提供至少1.5Gbps有效带宽的配置。AXI DMA的突发长度设置也很关键,太短会导致总线利用率低,太长会增加延迟。实测下来,突发长度设为64或128比较平衡。
4.3 JTAG固化Flash时DDR的必要性
这个问题在热词里出现了:“zynq 7020 使用jtag固化flash时必须使用ddr吗”。答案是:不一定,但大多数情况下需要。
ZYNQ的启动流程是BootROM先运行,然后加载FSBL,FSBL再加载bitstream和应用程序。如果你用JTAG固化Flash,FSBL需要把Flash里的数据读到内存中再写入。如果应用程序比较大,或者bitstream比较大,没有DDR的话内存不够用。
但如果你只是固化一个很小的裸机程序,ZYNQ的OCM(On-Chip Memory)有256KB,勉强够用。不过实际操作中,FSBL本身就要占一部分OCM,再加上bitstream动辄几MB,没有DDR几乎不可能完成固化。所以结论是:固化Flash时DDR是必须的,除非你的程序极小且不需要bitstream。
璞致PZSDR板卡上通常板载了DDR3,容量足够。固化的时候注意FSBL的配置要正确指定DDR的型号和时序参数,否则FSBL跑不起来,JTAG连接会失败。
4.4 Qt与ZYNQ串口库的编译适配
如果你打算在ZYNQ的Linux系统上跑Qt应用,并且需要通过串口跟AD9361或者其他外设通信,那Qt的SerialPort库编译可能会遇到问题。ZYNQ的ARM核是Cortex-A9,属于ARMv7架构,Qt的预编译包通常不包含这个架构。
我的做法是在Ubuntu主机上交叉编译Qt的SerialPort模块。需要先配置Qt的交叉编译环境,指定ZYNQ的交叉编译器(通常是arm-xilinx-linux-gnueabi-),然后单独编译qtserialport模块。编译的时候注意把sysroot指向ZYNQ的根文件系统,否则头文件和库路径会找不到。
编译完成后,把生成的库文件拷贝到ZYNQ的根文件系统里,在Qt应用里通过QSerialPort类来操作串口。实测下来,ZYNQ的UART控制器在Linux下工作稳定,波特率最高可以到921600,足够配置AD9361使用。
5. 宽频射频场景下的实测经验与避坑要点
5.1 宽频覆盖的增益平坦度问题
AD9361的射频前端覆盖70MHz到6GHz,但并不是整个频段内增益都平坦。在频段边缘,比如接近70MHz和接近6GHz的地方,增益会下降,噪声系数会恶化。璞致PZSDR板卡的外围匹配电路是针对宽频应用优化的,但如果你要覆盖整个频段,仍然需要在软件里做增益补偿。
我的做法是在初始化完成后,对目标频段内的几个频点做增益校准,记录每个频点的实际增益,然后在基带处理里做数字补偿。补偿的精度取决于校准点的密度,通常每100MHz一个校准点就够了。
5.2 采样率切换时的时钟稳定时间
AD9361在切换采样率的时候,内部PLL需要重新锁定,这个过程需要时间。如果你在运行中频繁切换采样率,每次切换后都要等待PLL锁定标志置位才能继续收发数据。我实测下来,锁定时间在几十微秒到几毫秒之间,取决于切换的幅度。
如果你的应用需要快速切换采样率,建议在ZYNQ的PL端做一个状态机,自动等待PLL锁定后再使能数据通路。不要依赖软件轮询,因为软件轮询的延迟不确定,容易丢数据。
5.3 LVDS接口的IDELAY校准
ZYNQ的SelectIO资源支持IDELAY,可以用来调整LVDS数据的采样相位。AD9361的DATA_CLK和数据之间的相位关系受PCB走线和温度影响,固定延迟不一定能在所有条件下都正确采样。
我通常会在初始化阶段做一次IDELAY扫描,找到一个稳定的采样窗口。具体做法是:发送已知的测试图案,然后逐步调整IDELAY值,记录每个值下的误码率,选择误码率最低的窗口中心作为最终值。这个过程可以在FSBL或者应用程序启动时自动执行。
5.4 电源噪声对射频性能的影响
AD9361对电源噪声非常敏感,尤其是射频PLL的供电。璞致PZSDR板卡在电源设计上做了滤波,但如果你把板卡放在开关电源附近,或者电源本身纹波较大,射频性能会明显下降。
我遇到过一次RX灵敏度突然变差的情况,查了半天发现是实验室的开关电源换了型号,纹波从10mV涨到了50mV。换回线性电源后立刻恢复正常。所以如果你在做射频调试,电源的质量一定要保证,有条件的话用电池供电做对比测试。
6. 从项目落地角度再看这套架构的取舍
璞致PZSDR系列板卡把ZYNQ和AD9361组合在一起,本质上是在灵活性和开发效率之间找了一个平衡点。ZYNQ的PS端让你可以用软件的方式处理复杂的控制逻辑,PL端又保留了硬件加速的空间。AD9361则把射频前端的复杂度封装成了一组寄存器接口,你不需要懂射频电路设计,只需要会配置寄存器就能收发信号。
但这套架构也有它的边界。如果你的应用需要超过6GHz的频段,AD9361就不够了,得换其他射频前端。如果你需要极高的实时性,比如纳秒级的响应,ZYNQ的PS-PL交互延迟可能成为瓶颈。如果你需要极低的功耗,ZYNQ加AD9361的组合功耗在几瓦级别,不适合电池供电的便携设备。
我在实际项目中选型的时候,会先问三个问题:频段覆盖够不够、数据吞吐量能不能满足、功耗和体积有没有硬约束。这三个问题回答完了,基本就能判断这套架构适不适合。对于大多数宽频射频的科研和工业应用来说,ZYNQ加AD9361的组合仍然是性价比很高的选择,璞致PZSDR系列板卡把这个组合做成了标准产品,省去了自己画板调试的麻烦,对于快速原型验证来说很实用。
最后分享一个小技巧:调试AD9361的时候,手边常备一份寄存器手册和官方评估软件的安装包。遇到寄存器行为不符合预期的时候,先在评估软件里复现,确认是配置问题还是硬件问题。评估软件里能正常工作但板卡上不行的,多半是SPI时序或者电源问题;两边都不行的,那就是配置参数本身有问题。这个排查思路帮我省了很多时间。