资讯详情

资讯详情

AD9361官方例程全解析:从环境搭建到BPSK实现与设备树迁移

做射频收发手里要是有块AD9361第一件事基本都是从官方例程开始的。这颗芯片在软件无线电圈子里确实常见单芯片覆盖70MHz到6GHz收发带宽最高能到56MHz很多SDR、小型基站、雷达和测量设备上都能看到它。但说实话我刚接触AD9361那会儿以为官方例程就是几个演示程序跑一跑能出个波形就完事了。真去翻源码和文档才发现官方例程是一整套工程——HDL代码、Linux驱动、No-OS平台代码、IIO工具链全都包含在内。把这一套吃透后面自己搭射频数据链路、做调制解调验证、甚至改设备树移植到新工程都有章可循。这篇文章就围绕AD9361官方例程展开讲清楚三件事官方例程里到底有什么怎么快速搭起来跑通如何在例程基础上实现BPSK调制解调把数据真正收回来以及一个很多人都会踩的坑——怎么把老工程里的AD9361设备树干净地迁移到新建的PetaLinux工程里。内容以实际操作经验为主适合正在用AD9361做开发、或者准备用ZynqAD9361方案做无线通信验证的工程师参考。1. 官方例程的全貌从HDL到Linux驱动ADI到底给了什么1.1 先把AD9361的定位理清楚AD9361是ADI亚德诺的射频捷变收发器内部集成了完整的收发链路接收端从LNA、混频器、滤波器到12位ADC发射端从12位DAC、滤波器、混频器到PA驱动级。频率范围70MHz到6GHz支持两路发射和两路接收通道带宽从200kHz到56MHz可配。它本质上是一个“射频直采”级别的模拟前端但数字侧的调制解调、编解码、协议处理都得靠外部FPGA或处理器来做。这一点很重要因为很多人误以为AD9361能直接解调出BPSK、QPSK这样的基带数据实际上它只负责把射频信号下变频成I/Q基带数字流剩下的活儿得你自己干。1.2 官方例程的资源分布ADI官方例程并不是一个单独的压缩包而是一组分布在GitHub上的工程仓库。主要包含这么几块HDL工程analogdevicesinc/hdl以Vivado工程的形式提供支持的平台很多常见的有Zynq-7000系列的FMCOMMS2/3/4/5-EBZ板卡也有针对ADRV9361、ADRV9371等射频模块的参考设计。工程里集成了AXI接口、DMA控制器、AD9361的数字接口逻辑代码组织得比较规整是FPGA侧定制的基础。Linux内核驱动analogdevicesinc/linuxAD9361在Linux下走的是IIOIndustrial I/O框架驱动源码在drivers/iio/adc/ad9361.c。它把寄存器操作、增益控制、滤波器配置都封装成了标准IIO属性用户态可以通过libiio库直接访问。No-OS驱动analogdevicesinc/no-OS这是给裸机或RTOS环境用的C驱动不依赖Linux直接操作SPI寄存器。如果项目里用的是MicroBlaze或者自己写的软核处理器这版驱动更合适。文档和wikiADI在wiki.analog.com上有大量应用笔记和用户指南比如FMCOMMS2-EBZ的硬件手册、AD9361参考手册、以及各种软件配置示例。建议先看wiki再动手很多问题其实文档里早就写了。1.3 先选对路线Linux还是No-OS这个问题其实取决于你的应用场景我列个对比给你参考对比项Linux IIO/libiioNo-OS裸机驱动开发效率高用户态直接用libiio读写有现成示波器工具低所有寄存器都需要自己管理实时性一般涉及内核调度和DMA中断高可控性强适合定制时序适合场景快速验证、数据采集、协议处理在PS端完成FPGA直接控制、实时信号处理、低延迟闭环调试手段IIO Oscilloscope、iio_readdev等现成工具需要自己写调试接口上手难度相对容易需要深度理解寄存器我自己习惯的做法是先用LinuxIio路线把链路跑通、把射频参数调好确认硬件没有问题再到关键模块上用No-OS做定制。如果你现在只是想把板子点亮、看看IQ波形那Fully Linux方式是最快的。2. 环境搭建与镜像构建从拉代码到跑通IIO Oscilloscope2.1 硬件准备和版本对齐硬件上最常见的是AD-FMCOMMS2-EBZFMCOMMS2配Zynq-7000开发板比如ZedBoard、ZC706。FMCOMMS2板卡通过FMC接口和Zynq连接AD9361的SPI控制、GPIO复位、数据接口都在FMC上定义好了插上去就能识别。也有人用自研的AD9361板卡那通常在原理图阶段就要参考FMCOMMS2的设计保证FMC引脚定义一致否则后面设备树要改的东西会非常多。软件版本的对齐是第一个容易踩坑的地方。ADI的hdl库和Linux内核库会定期打tag比如hdl的版本对应Vivado版本linux的版本对应内核版本。建议先用官方wiki上指定的组合不要一上来就拿最新的Vivado编译旧版本的hdl库编译报错会非常折磨人。以我常用的一个组合为例Vivado 2020.2、PetaLinux 2020.2、ADI的hdl库release_2020_r2、linux库的对应分支。这套组合在FMCOMMS2ZedBoard上很稳。2.2 HDL工程的拉取和编译先拉hdl库git clone https://github.com/analogdevicesinc/hdl.git cd hdl git checkout release_2020_r2然后进入fmcomms2工程目录cd projects/fmcomms2 make不需要手动打开Vivado工程make脚本会自动调用Vivado生成bit文件。第一次编译时间比较长通常在一小时以上取决于机器性能。编译完成后会在hdl/projects/fmcomms2/zc706或对应平台目录下生成bit流文件和hdf硬件描述文件。这个bit流包含了AXI接口、DMA通道、以及AD9361的数字接口时序逻辑是后面系统跑起来的基础。注意如果要修改PL侧的基带处理逻辑比如加入BPSK调制解调就要在hdl工程里加模块然后重新综合。这一步会在第三节细说。2.3 PetaLinux工程和内核配置拉Linux内核库是为了把AD9361驱动编进去。用PetaLinux创建工程后把hdf文件导入然后在内核配置里使能相关驱动petalinux-create -t project --name ad9361_bsp --template zynq petalinux-config --get-hw-descriptionhdf路径 petalinux-config -c kernel在内核配置菜单里找到Device Drivers → Industrial I/O support → Analog to digital converters → Analog Devices AD9361Device Drivers → Industrial I/O support → Frequency synthesizer DDS/PLL → AD9361把这两项编成模块或直接编进内核都行。然后设备树里要有AD9361的节点官方hdl工程生成时已经带了默认设备树源文件在hdl/linux的arch/arm/boot/dts里可以找到类似zynq-zed-ad9361-fmcomms2-ebz.dts的模板。PetaLinux编译完成后把BOOT.BIN和image.ub放到SD卡启动。2.4 第一次跑通IIO Oscilloscope启动Linux后用libiio的现成工具直接看数据iio_info -s iio_attr -d ad9361-phy iio_osciio_attr能列出当前AD9361的配置参数比如频率、采样率、增益、滤波器带宽。iio_osc是图形化工具能实时显示收发的I/Q波形和频谱。到这一步至少说明SPI控制链路、数据通道和驱动都正常了。我第一次看到sin波形时心里那块石头才落地——说明FMC接口、DMA、驱动、PL逻辑这条长链路整个是通的。3. 在官方例程上实现BPSK调制解调把数据真正“跑”起来3.1 官方例程为什么没有直接给BPSK解调代码很多人找官方例程时期望能找到BPSK、QPSK、甚至OFDM的现成demo但翻遍仓库会发现ADI官方并没有把这些高层调制解调做成一个固定例程。原因也简单AD9361是射频收发前端基带调制解调属于FPGA或者DSP的活儿不同应用场景的调制方式、帧格式、同步策略完全不同ADI不会在官方例程里锁死一个方案。但官方例程提供了完整的数据通路你可以在这个基础上加自己的基带算法。这恰恰是例程真正的价值——链路是通的你只需要专注于算法验证。3.2 整条BPSK数据链路怎么搭BPSK二进制相移键控简单说就是用0°和180°两种相位表示0和1。在AD9361的数字接口上数据是以12位I/Q并行数据流的形式进出的。如果你的调制在数字域做那发射链路是PS或PL产生PN序列 → BPSK符号映射0/1映射为1/-1 → 脉冲成型滤波 → 送入AD9361 TX端口 → AD9361内插上变频到射频 → 天线接收链路反过来天线 → AD9361下变频到基带I/Q → 抽取滤波 → 12位I/Q数字流进入FPGA → 载波同步/定时同步 → 匹配滤波 → 判决恢复出0/1注意BPSK调制时的载波信号可以放在AD9361内部产生也可以放在FPGA里用DDS产生。更常用的做法是在FPGA里用I路发送成型后的基带信号Q路发0AD9361配置成单边带发射模式这样载波泄漏和镜像抑制会好一些。接收端如果只做非相干解调对载波同步要求低但误码率会高一些如果做相干解调需要Costas环或者平方环来恢复载波。这属于通信原理的基本功这里不展开理论推导但实现时要注意AD9361的接收IQ数据速率和本振频率之间的偏差即使外部时钟很准收发两端如果不同源还是会有残余频偏需要在FPGA里做频偏估计和补偿。3.3 我落地BPSK的实操步骤这里分享一套我验证过的方案基于FMCOMMS2 ZedBoardPL端用官方hdl工程作为基础加入一个简单的BPSK发送模块。第一步在hdl工程里添加自定义RTL模块。比如写一个bpsk_tx.v内部用LFSR产生伪随机序列做符号映射再通过成型滤波器后输出12位I/Q数据。接口上这个模块的输入是FPGA时钟和DMA状态输出直接接到AD9361的数据接口。为了简单也可以绕过DMA直接让模块把数据发到ad9361的tx端口。hdl库里AD9361的接口信号定义得很清楚找到ad9361_tx_clk、ad9361_tx_data等信号对接就行。第二步重新综合生成新的bit流。这个过程会比较久建议先在Vivado里验证功能仿真确认模块时序没问题再上板。第三步调整AD9361的发射配置。在Linux里通过IIO属性设置iio_attr -c ad9361-phy voltage0 frequency 434000000 iio_attr -c ad9361-phy voltage0 sampling_frequency 10000000 iio_attr -c ad9361-phy voltage0 rf_bandwidth 2000000这里把中心频率设为434MHz采样率10MSPS射频带宽2MHz。如果你的调制数据速率是1Mbps这样的配置是够用的。接收端的BPSK解调可以在PS端用C语言写一个简单的相关解调。libiio提供了数据流读取接口用iio_device_find_buffer、iio_buffer_refill等API读回IQ数据然后在软件里做匹配滤波和判决。这种方法验证方便但实时性差一些只适合低速数据。如果数据速率高还是得把解调逻辑写进FPGA。3.4 回环测试和结果观察做回环测试时用一根SMA线把板子的TX1连接到RX1这样发射出去的BPSK信号可以直接回到接收端方便调通链路。在IIO Oscilloscope里同时观察TX和RX的I路波形应该能看到类似成型滤波后的BPSK包络。再用下面这段简单的Python脚本读回数据统计误码率import iio ctx iio.Context(local) rx_dev ctx.find_device(cf-ad9361-lpc) buf iio.Buffer(rx_dev, 1024, False) buf.refill() samples buf.read() # 后续做判决和误码统计这个脚本只是一种验证手段实际工程中还是建议用C或FPGA实现。整个过程跑下来如果能稳定解出PN序列说明BPSK调制解调链路已经打通了。这一步做完你对AD9361的数据通路会有非常直观的理解。4. 设备树迁移实战把老工程的AD9361设备树搬到新PetaLinux工程4.1 为什么设备树迁移会让人头疼官方例程跑得好好的但很多时候我们都会面临一个新问题领导让你新建一个PetaLinux工程把原来工程里的AD9361设备树搬过去。看起来只是复制粘贴实际操作起来问题一堆spi节点冲突、时钟引用失效、GPIO引脚不一致、axi-dma节点缺失、编译时报“xxx not found in /ps7”之类的错误。原因主要在于设备树不是孤立的一棵树AD9361节点依赖整个系统级的引用关系比如时钟、中断、DMA通道、引脚复用。只拷贝一个节点那些依赖关系不会自动跟着过去。4.2 AD9361相关的核心设备树节点要迁移之前先搞清楚老例程里AD9361节点到底涉及哪些部分。以Zynq FMCOMMS2为例核心节点包括节点/属性作用迁移时常见坑spie0006000 下的 ad9361-phy0AD9361的SPI从设备节点寄存器地址0新工程SPI控制器基地址或时钟不同会注册失败ad9361-phy1第二片AD9361如果有FMCOMMS3才有单芯片板卡可忽略axi-ad9361-adc / axi-ad9361-dacPL里的DMA节点负责搬运IQ数据必须与hdl工程的AXI地址、DMA中断保持一致ad9361_clkout 等时钟节点AD9361提供的参考时钟输出引用时钟名不匹配会编译报错gpio控制复位、使能、tx/rx开关对应FMCOMMS板卡上的GPIO扩展新板卡引脚不同需重新映射interrupts属性对应DMA中断号中断号错误会导致数据采集卡死4.3 我的设备树迁移步骤我在多个工程里做过AD9361设备树迁移总结下来按下面几步走最稳第一步把老工程编译后生成的device tree source一般在petalinux工程里路径类似components/plnx_workspace/device-tree/device-tree/system-top.dts打开找到ad9361相关的所有节点从spi节点、adc/dac dma节点、时钟节点、gpio节点到中断控制器引用全部复制到一个新文件里。第二步打开新工程的system-user.dtsi用/include/的方式包含刚才的文件/include/ ad9361.dtsi把这个dtsi文件放到新工程meta-user的recipes-bsp/device-tree/files目录下。这样相当于把老设备树的内容叠到新工程之上。第三步检查新工程的顶层设备树是否已经有冲突。常见情况是新工程里已经有默认的spi控制器节点但ad9361的spi子节点没有定义这没问题但如果有多个spi节点且地址相同就要手动调整。另外老工程里的gpio定义用到了Zynq的EMIO引脚如果新板卡没有接对应的EMIO需要修改gpio号。第四步处理时钟依赖。AD9361驱动在注册时会查找“ad9361_clkout”这个时钟源新工程如果没有对应的时钟节点驱动加载会直接报错。操作上在dtsi里要保留老例程的ad9361_clkout节点同时确保时钟控制器节点没有被新工程覆盖。第五步重新编译内核和设备树启动后检查AD9361是否注册成功。在系统里执行iio_info -s cat /proc/device-tree/axi/ad9361-phy0/name ls /sys/bus/iio/devices/如果能看到ad9361-phy设备说明SPI和时钟部分没问题如果设备存在但采集不到数据通常问题出在DMA节点检查dma的地址范围和中断号是否与bit流实际配置一致。4.4 我踩过的设备树迁移坑有一次我把老工程设备树搬到新PetaLinux工程SPI和时钟都对了但IIO设备死活不出数据。折腾了很久最后发现是DMA中断号不对。老工程里axi-ad9361-dma使用的中断号是在hdl工程里静态分配的新工程里因为其他外设变化中断号发生了偏移。这种问题在设备树层面看起来毫无异常因为编译能过、驱动能加载但申请中断失败数据流就断了。解决方法是打开hdl工程生成的xparameters.h文件看DMA的interrupt ID再对到设备树里的interrupts属性。Zynq的中断号一般等于中断ID减去16因为SPI中断从32开始去掉OFFSET。这一步需要仔细比对别凭经验猜。另一个坑是GPIO复位引脚。老板卡上AD9361的复位脚默认接到某一个GPIO如果新板卡复位脚没接或者接到了别的引脚上驱动会出现加载时卡死、写寄存器超时的情况。排查方法是在设备树里把复位GPIO临时去掉如果问题依旧那就是硬件问题或SPI配置问题。5. 常见问题与排查技巧实录5.1 设备树相关的高频问题排查现象可能原因排查方法Linux启动时ad9361驱动报错“failed to read chip id”SPI通信异常、复位GPIO不对、电源未就绪用i2c或逻辑分析仪查SPI时序确认复位时序iio_info看不到ad9361-phy设备设备树节点没有解析成功或者内核驱动没有编译进去查看dmesg日志确认是否加载了ad9361驱动dmesg里报“clock not found”时钟节点引用错误在设备树里查clocks和clock-names属性确保与驱动代码匹配运行iio_osc时波形全零DMA中断异常、数据接口时序不对确认bit流和hdf一致用vivado硬件管理器看PL寄存器发射无信号功率过低、频率配置错误、TX使能GPIO不对先用iio_attr设置发射衰减再用频谱仪检查5.2 调制解调联调时的常见问题BPSK链路调不通大部分时候不是算法问题而是链路配置问题。最典型的三个现象第一接收端I/Q波形幅度异常。这通常是因为自动增益控制AGC没有配置好。先用iio_attr把RX增益模式改成manual把增益设成一个固定值排除AGC波动的影响后再看波形。第二载波频偏过大导致解调星座图旋转。收发两端如果共用一个参考时钟这个现象不明显如果用的是两套独立板卡频偏是必然存在的。解决办法是在FPGA里加一个鉴频器或者先用廉价的晶振校准用数字方法在接收端补偿。第三符号定时偏差。BPSK数据速率和AD9361采样率不匹配会导致眼图闭合。我的经验是先把采样率设成符号速率的整倍数比如1Msps符号速率对应10MSPS采样率然后在接收端用一个简单的Gardner定时恢复算法基本能稳定工作。这些问题的排查思路其实就是一条先把每段链路单独验证。先用自环模式BIST验证AD9361数字接口正常再把调制器输出的数据从发射经线缆回环到接收逐步缩小问题范围。这一步对新手极其有用。6. 关于官方例程的扩展玩法与我的实际体会官方例程对于AD9361这个平台来说相当于一副完整的骨架。你可以不用从零开始写SPI驱动、不用自己调DMA、不用纠结Vivado工程结构这些都是官方已经做好的。基于这套骨架后续扩展的方向其实很多。比如可以把BPSK调制成QPSK、16QAM也可以通过配置AD9361的TDD/FDD模式实现时分双工通信还可以把FPGA里的基带模块换成OFDM。如果你要做更底层的自研通信协议例程里的HDL接口规范也值得好好研究。我个人的建议是不要一上来就想着把所有功能都放进系统里。先跑通官方例程在Linux下的收发用IIO Oscilloscope看到实际IQ波形理解数据从天线到软件之间的整个流动过程。然后再开始加BPSK模块一步步来。设备树迁移这类问题虽然繁琐但只要理清节点间的依赖关系掌握好排查方法风险是可控的。最后再分享一个小技巧在调试AD9361的时候始终保留一个最小可跑的备份工程。不管是改设备树还是改FPGA逻辑都先在备份上验证改坏了也能迅速回退。这个习惯帮我省了非常多的时间。希望这篇内容能让你在AD9361的官方例程这条路上少走一些弯路。
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →