
做射频或者软件无线电这行的应该没人不知道 AD9361。这颗由 ADI 出的宽带收发器几乎成了 SDR 硬件平台的代名词。很多项目开发者的第一站都是去 GitHub 上找“官方例程”我也是这么过来的。但真正下载下来之后不少人会愣住例程不是一个工程文件而是一大堆 HDL、C 代码、设备树和脚本的集合和平时点个 STM32 例程的体验完全不同。这篇文章我就围绕 AD9361 官方例程这件事把整个例子体系的组成、怎么把它跑起来、怎么基于它做 BPSK 调制解调以及怎么把老工程里的设备树平滑搬到新建的 PetaLinux 工程里这几条最常被问的路线按我自己的实际操作经验一条一条拆开讲。内容偏向工程落地不堆理论公式适合刚拿到开发板准备开干的人也适合被设备树和编译流程折腾到头疼的进阶玩家。1. 例程全景先搞明白官方仓库里到底有什么1.1 三条主线HDL、No-OS、Linux 驱动的关系AD9361 的官方例程体系里最基本的其实是三套东西它们负责的层次完全不同但项目里通常要一起出现。第一套是 HDL 参考设计存放在 ADI 的 hdl 仓库里对应目录是projects/ad9361。它解决的是“FPGA 和 AD9361 之间的数字接口怎么搭”的问题包含 LVDS/CMOS 数据接口、SPI 控制模块、DMA 引擎、jesd 之类的逻辑实际上 AD9361 走的是并行接口没有 JESD这里重点是数据通路和控制通路。Xilinx 的 Vivado 工程直接关联这个目录跑一下 tcl 脚本就能生成完整的 bitstream。第二套是 No-OS 驱动与示例应用代码在 no-OS 仓库的ad9361部分。它面向“没有操作系统的裸机环境”主要提供 AD9361 的寄存器读写、初始化序列、校准流程、收发使能状态机等。它的核心价值不是给你一个可以跑业务的应用而是把 AD9361 的“脾气”摸透了你拿到手可以立刻完成芯片的初始化和数据收发测试。第三套是 Linux 下的 IIO 驱动和 libiio 用户态工具。ADI 把 AD9361 做成了标准 IIO 设备内核里有ad9361驱动用户态可以用iio_oscilloscope、iio_reg这些工具直接读写寄存器、采集波形、配置频率。工程上绝大多数最终产品都会跑 Linux这一条线才是真正能让你快速验证射频链路通不通的锤子。所以当你听到“AD9361 官方例程”时要先建立这个概念它是一个三层结构。最底下是 HDL 比特流中间是驱动裸机或 Linux最上层是你自己的调制解调算法或者应用。三层之间靠接口、设备树和寄存器约定串联起来。后面我所有的经验都围绕这个三层结构来讲。1.2 为什么第一件事不是改代码而是跑通自带脚本很多开发者的习惯是把源码拉下来以后先去读代码、改代码想一上来就针对自己的需求调整。AD9361 官方例程上这个习惯要改一改。我的建议是第一件事是完完整整地把官方脚本跑一遍先让默认工程在硬件上工作起来。理由很简单AD9361 的数字接口不是一根线那么简单。FPGA 和 AD9361 的时序必须严格匹配涉及数据速率、接口模式CMOS 还是 LVDS、单端还是差分、延迟对齐、双通道还是单通道。这些参数只要错了一个表现出来都是“数据收不到”或者“波形是花的”但根因极其隐蔽。官方 HDL 工程里已经帮你把这些时序约束做死了只要你用配套的板卡和配置跑出来的状态就是对的。在这个基础上再改你自己的逻辑才有一个可信的基线。我见过太多人一上来就按自己的理解改了数据接口模式结果三天没调通最后回退到默认配置才发现时钟极性反了。所以说官方例程用得好不好区别不在于你会不会改而在于你知不知道什么不能改。1.3 版本配套一个容易被忽略的大坑AD9361 官方例程的第二个大坑是版本配套。ADI 在 GitHub 上维护代码时HDL、No-OS 和 Linux 驱动经常同步更新。比如你在 2023 年拉了一个 HDL 主分支再用两年前的 No-OS 代码去配它很可能出现寄存器映射不匹配、SPI 命令格式不同的问题。因为 AD9361 的 API 版本尤其是一些校准算法相关的配置会跟着驱动一起演进。我的习惯是项目一开始就固守一个“版本快照”。建议从 ADI 的 release 标签里选一个稳定的组合比如 HDL 的hdl_2022_r2配合 No-OS 对应 tagLinux 内核也固定到同样的 Yocto release。这样遇到问题可以在社区里找到相同版本的环境网上搜到的答案才不会和你本地的代码对不上号。2. 硬件准备与工程目录解构2.1 最小系统搭建开发板、载板与电源检查跑官方例程硬件平台最好用一个“官方验证过”的组合。ADI 自己的 FMComms2/3/4 载板搭配 Xilinx 的 Zedboard、ZC706 或者 ADI 自家的 ADRV9361 系列是最不容易出幺蛾子的选择。你当然可以用国产 FPGA 板卡自己画接口转接板但那就意味着 HDL 工程的引脚约束、时钟输入方式全都要重新适配这块工作量和调试风险会非常大。电源是第一个要检查的点。AD9361 的供电轨比较多1.3V 数字、2.5V 模拟、3.3V 接口等载板上通常由 LDO 从 5V/6V 输入转出来。跑例程之前用万用表确认各供电轨的电压值是否在 AD9361 数据手册规定的范围内尤其是 AVDD1P3 和 DVDD1P3偏差超过 5% 就可能出现寄存器读回值随机跳变的现象。这个问题和软件完全无关但经常被误判成驱动 bug。第二个检查点是参考时钟。AD9361 需要一路参考时钟FMComms2 板上一般由 40MHz 晶振产生。如果参考时钟不稳后面所有载波频率都会偏可能导致接收端解调出来的星座图一直在旋转。这一点在 BPSK 这种对相位敏感的应用里尤其不能凑合。2.2 HDL 工程的目录结构与 IP 含义官方 HDL 工程打开以后很多人会被目录结构绕晕。这里挑最核心的几块说。projects/ad9361/common下存放的是 AD9361 相关的通用逻辑包括数据接口模块ad9361_data、 SPI 控制器ad9361_spi、 以及把这两者封装成 AXI 外设的axi_ad9361。在 Vivado 里你会在 Block Design 中看到axi_ad9361这个 IP它对外提供 AXI 接口给 PS 或软核访问对内连接 AD9361 的并行数据引脚。projects/ad9361/zc706_fmcomms2这样的板级目录下是具体板卡的顶层逻辑、引脚约束xdc 文件和 Block Design tcl 脚本。你直接打开这个目录里的 Vivado 工程或跑make就能得到适配这块板卡的 bitstream。还有一部分容易被忽略但是至关重要的逻辑是 DMA 引擎。axi_dmacIP 负责把 AD9361 的接收数据流搬到内存或者把内存里的发射数据搬到 AD9361。它和axi_ad9361配合就是官方例程里“FPGA 到 PS 内存”的主干道。理解这一点之后你在 IIO Oscilloscope 里看到数据本质上就是 DMA 从内存里抓出来的。2.3 No-OS 应用层的模块划分No-OS 工程里ad9361目录下有几个文件是理解整个例程的钥匙。ad9361_api系列文件实现了对外 API 层比如ad9361_set_tx_fir、ad9361_set_rx_gain、ad9361_rf_pll_set_freq。这些是你做应用配置的时候直接调用的函数底层细节被封装好了。ad9361.c和ad9361_conv.c是核心驱动文件内部处理寄存器初始化序列、校准、增益表加载、滤波器配置下载等。普通应用开发基本不用改这里但其中ad9361_init这个函数的参数结构体adi_ad9361_init_param里有一堆与硬件连接相关的信息比如 GPIO 引脚号、接口模式、频率规划你配置错了后面全错。ad9361_util.c提供一些寄存器读写内部函数其中 SPI 底层通过ad9361_spi模块实现在 No-OS 环境里通常用 GPIO 模拟或直接映射到 AXI SPI。3. 把官方例程跑起来编译与下载3.1 获取代码与工具链准备代码获取建议直接 git clone 官方仓库并且用 tag 固定版本。比如git clone https://github.com/analogdevicesinc/hdl.git cd hdl git checkout hdl_2022_r2No-OS 仓库类似git clone https://github.com/analogdevicesinc/no-OS.git cd no-OS git checkout 2022_R2工具链方面HDL 工程需要 Xilinx Vivado版本最好与 ADI 仓库说明一致避免综合或实现阶段出现莫名其妙的 IP 版本报错。No-OS 裸机工程需要对应 FPGA 芯片的 SDK 或 Vitis如果只跑 Linux 就不需要 No-OS。3.2 Vivado 工程编译流程在hdl/projects/ad9361/zc706_fmcomms2目录下官方提供了 Makefile 风格的编译方式make这条命令会自动调用 Vivado 的 batch 模式运行system_project.tcl生成 bitstream。首次运行时间长因为它会把所有 IP 重新生成一遍。如果你的机器配置一般建议耐心等同时观察终端输出里有没有时序失败timing failed的提示。AD9361 接口的时序要求比普通逻辑高如果出现 setup time violation先不要急着改约束检查是不是 Vivado 版本太老、编译策略太激进或者直接跑make AD9361_LVDS1切到 LVDS 模式看是否更稳。编译完成后在runs目录下会生成system_top.bit和system_top.hdf或 xsa。这个 bit 文件就是要下载到 FPGA 的镜像。3.3 在 Linux 下快速跑一个收发环回如果用的是 PetaLinux 或 Yocto 出来的系统镜像把 bit 文件烧进 FPGA 后系统起来就会自动加载ad9361驱动IIO 设备节点会在/sys/bus/iio/devices/下出现。这时你不需要写任何 C 代码就能用官方工具验证射频链路。最直接的办法是用 ADI 提供的 IIO Oscilloscope图形化工具或者命令行工具iio_readdev、iio_writedev。比如用 iio_readdev 抓一段接收数据iio_readdev -s 1024 cf-ad9361-lpc 2/dev/null | xxd | head -20这段命令从接收 DMA 设备cf-ad9361-lpc读取 1024 个样本输出十六进制数据。正常工作时如果天线口有信号进来这里的 I/Q 数据会不断变化如果没有信号可能是全零或者一个接近直流的偏置值。这时候你可以先不接天线用一个射频信号源给 RX 口一个单载波看能否在时域看到正弦波形的 IQ 轨迹。提示AD9361 的接收链路默认有一个直流失调校正所以非常强的 DC 信号会被自动扣除这是正常现象。调试时不要看到直流分量消失就以为链路断了。3.4 用 IIO Oscilloscope 验证整条链路IIO Oscilloscope 是 ADI 为 Linux 下的 IIO 设备做的跨平台示波器。连接到目标板的 IP 后它能同时显示时域波形、频域频谱和 IQ 星座图。实测下来这个工具最大的价值是能快速确认“RF 前端 数据接口 DMA”三者是否协同。你把本振设到 2.4GHz用信号源发一个 -30dBm 的 2.4GHz 单音示波器上应该能看到一个以 0 为中心的旋转向量对应 IQ 平面上的圆。如果看到的是直线或很扁的椭圆说明 IQ 幅度不平衡或者相位不正交多半是配置里 RX 增益或滤波器参数有问题。官方例程跑通这一整套之后你才算真正“摸到了”AD9361 的完整数据通路后面做 BPSK 调制解调就有一个非常扎实的底子。4. 从官方例程到 BPSK 调制解调的工程化实现4.1 官方例程里没有 BPSK但提供了所有积木AD9361 官方例程不会直接给你一个 BPSK 调制解调的完整工程因为 AD9361 本身只是射频收发器调制解调功能要由外部 FPGA 或处理器完成。但它把最难的射频前端和高速数据接口给你准备好了你真正要做的是在 Zynq 的 PS 端或者 PL 端把基带数据流“加工”成 BPSK 信号再送进 AD9361 发射接收时从 AD9361 拿回基带 IQ 数据完成解调和判决。所以实现 BPSK 的过程本质上就是在官方例程的骨架上搭自己的算法。你可以用 PS 端纯软件实现低速率的 BPSK也可以用 PL 端 Verilog 实现高速率的 BPSK。下面我以“FPGA 生成 BPSK 基带数据 软件控制收发”这个组合为例讲具体步骤。4.2 关键配置时钟树、带宽与数据率AD9361 的采样率决定了一切。AD9361 的 ADC/DAC 采样率范围在几十 MSPs 量级具体数值和接口模式有关。BPSK 的符号速率必须低于这个采样率并且 AD9361 内部 FIR 滤波器的通带要能容纳你的信号带宽。假设你设定了 ADC 采样率为 40MSPSBPSK 符号速率为 1MSPS那么每个符号有 40 个采样点。在发射端先要把每个 bit 映射成 1/-1 的幅度序列然后经过成型滤波通常是根升余弦滤波器产生基带波形再按每符号 40 个点的节奏写入发射 DMA 的缓冲区。AD9361 会自动把这个基带波形上变频到射频载波频率上。用 No-OS 的 API 设置采样率时可以这样ad9361_set_tx_sampling_freq(ad9361_phy, 40000000); ad9361_set_rx_sampling_freq(ad9361_phy, 40000000); ad9361_set_tx_rf_bandwidth(ad9361_phy, 1000000); ad9361_set_rx_rf_bandwidth(ad9361_phy, 1000000); ad9361_set_tx_lo_freq(ad9361_phy, 2400000000); ad9361_set_rx_lo_freq(ad9361_phy, 2400000000);这里设置带宽 1MHz 是为了配合 1MSPS 的 BPSK 信号。带宽太大会引入更多噪声太小会把信号边缘切掉。4.3 调制端用 DMA 持续发送基带数据发射路径的基带数据是放在内存里的一个数组里面是交替的 I 和 Q 样本16bit 有符号整数。BPSK 里 Q 路可以直接置 0只把数据放在 I 路。这样发射出来的就是标准的二相键控信号。一个最简单而有效的发送流程是准备一段伪随机 bit 序列比如 PN9。把 0 映射为 2000一个合适的幅度把 1 映射为 -2000。按每符号 40 个样点重复得到 IQ 交错数组。通过iio_writedev或 No-OS DMA 接口把这个数组循环写入发射设备。射频端接上频谱仪或者另一个接收机来验证。如果你用 Linux 下的 libiio核心代码大概这样struct iio_device *tx iio_context_find_device(ctx, cf-ad9361-dds-core-lpc); // 直接写 raw 数据块到 TX 设备 iio_device_open(tx, 0); iio_device_write(tx, buffer, buffer_size);这里cf-ad9361-dds-core-lpc是官方 HDL 里 DDS/DMA 发送设备的默认名称。写进去的数据会被 FPGA 以发射采样率不断重复发送形成连续的 BPSK 帧。注意一个实测经验发射幅度不要给满。AD9361 的 DAC 满量程附近非线性会略微增加星座点会向内弯。一般用满量程的 50%~70% 比较合适。示例中幅度 2000/32767 大约是 6%偏保守了实际可以到 8000~12000 都没问题但别一口气加到 30000 以上。4.4 解调端同步、判决与误码验证接收端比发射端复杂。BPSK 解调除了要看准符号还要解决载波同步和定时同步。官方例程不会帮你做这层处理所以你要自己写。我的做法是分三步走第一步先不加任何同步算法把 IQ 数据直接抓下来用 Python 或 MATLAB 做离线分析。用一段已知的 PN9 序列做前导码在接收数据流里滑动相关找到帧头位置。这一步能验证射频环路通不通。第二步实现定时同步。因为发射和接收的采样时钟都是同一个 AD9361 参考时钟派生出来的短时间内的采样偏差很小。你可以把“每 40 个点取一个符号中心点”当作最简单的定时恢复。如果发现符号边缘漂移可以在 FPGA 里做一个简单的 Gardner 定时同步环。第三步实现载波同步。BPSK 信号解调后如果接收本振和发射本振之间存在频率偏移星座图上的点会缓慢旋转。一个经典的解决方法是使用 Costas 环。在 Zynq 的 PL 端写一个 Costas 环并不复杂核心就是一个鉴相器、一个环路滤波器和一个数控振荡器。锁定之后星座图稳定在 1/-1 两个点上判决就非常容易。判决时取 I 路的符号位即可大于 0 判为 0小于 0 判为 1。然后把判决结果和原始 bit 比对统计误码率。在信噪比正常、频偏纠正好的情况下BPSK 链路的误码率应该可以做到非常低实测在 -10dBm 以上的信号强度下千帧数据无误码是很正常的表现。5. 把原有设备树移到新建 PetaLinux 工程里5.1 为什么设备树不能直接拷很多人做 PetaLinux 移植时习惯直接拷贝旧工程里的设备树文件也就是.dts或.dtsi结果在新工程里编译报错或者启动时驱动加载失败。这里面的核心问题在于设备树不只是描述硬件还描述硬件在某个特定内核版本下的访问方式。内核版本变了中断控制器类型、时钟框架、GPIO 控制器的组织方式都会变老设备树里的节点在新内核下可能根本找不到对应的驱动总线或父节点。还有一个容易踩的坑是PetaLinux 新工程会自动生成一套基于模板的设备树里面已经有很多板级节点。你直接把整棵旧树覆盖过去等于丢了新内核需要的节点比如新的 CPU 中断控制器标识、FPGA 管理的相关节点、内存节点。所以正确做法是“按需移植”只搬和 AD9361 相关的部分。5.2 迁移流程从 sysuser.dtsi 到顶层 dtsi我的实践经验是不修改 PetaLinux 自动生成的顶层设备树而是在meta-user/recipes-bsp/device-tree/files/system-user.dtsi里做增量修改。这个文件最后会被包含进最终的设备树编译流程里不破坏原有自动生成的节点。在原有例程里与 AD9361 相关的设备树节点一般包括ad9361...compatible 为adi,ad9361挂在 SPI 总线上。一组时钟节点通常引用adi,ad9361-clkout或ad9361_clk作为 FPGA 数据接口的时钟来源。FPGA 侧的 AXI 外设节点比如cf-ad9361-lpccompatible 为adi,axi-ad9361。复位和使能引脚通过reset-gpios、enable-gpios引用 GPIO 控制器。如果有 TX 监控、RX 监控还会有对应的 DMA 设备节点cf-ad9361-dds-core-lpc和指令处理器节点。迁移时把这些节点完整复制到system-user.dtsi然后按新工程的实际总线地址调整reg属性。旧工程里如果 SPI 控制器地址是0xE0006000新工程里如果用的是同一个 Zynq 芯片这个地址通常不变。但要注意中断号新内核如果从interrupt-parent intc改成了 GIC v2 或其他中断控制器中断号要重新核对。下面是一个典型的 AD9361 设备树迁移片段spi0 { status okay; ad9361: ad93610 { compatible adi,ad9361; reg 0; spi-max-frequency 16000000; clocks ad9361_clk; clock-names ad9361_ext_refclk; reset-gpios gpio0 0 GPIO_ACTIVE_HIGH; enable-gpios gpio0 1 GPIO_ACTIVE_HIGH; }; };这里ad9361_clk需要单独定义一般用fixed-clock或者从 PL 端导出的时钟。最省事的方式是引用原有工程里的时钟定义复制过来后修改为ad9361_clk: clock0 { compatible fixed-clock; clock-frequency 40000000; #clock-cells 0; };5.3 内核配置与驱动匹配检查设备树搬过去还只是第一步新 PetaLinux 工程的内核配置里如果没有编译 AD9361 相关驱动设备树写得再漂亮也白搭。检查的项目包括CONFIG_AD9361 必须为 y 或 m驱动文件是drivers/iio/adc/ad9361.cADI 树里是drivers/iio/adc/ad9361.c。CONFIG_CF_AXI_AD9361对应 FPGA 里axi_ad9361IP 的驱动。CONFIG_AD9361_DDS 之类和 TX 发射 DMA 相关的配置。如果用到 libiioCONFIG_IIO_BUFFER、CONFIG_IIO_TRIGGERED_BUFFER 也要打开。在 PetaLinux 里可以用petalinux-config -c kernel进入内核配置界面搜索AD9361确认这几项都被勾选。驱动匹配靠的是compatible adi,ad9361这个字符串在内核源码的of_device_id表里必须存在。如果驱动编译进内核了但设备没 probe可以查启动日志dmesg | grep ad9361如果看到ad9361: probe of spi0.0 failed with error -22多半是设备树里某个属性写错或者时钟没配对。如果看到-517说明某个依赖的 GPIO 或时钟还没 probe属于顺序问题可以考虑加depends-on或者检查时钟节点的状态。5.4 迁移之后怎么验证设备树改完系统启动后先确认驱动绑定成功ls /sys/bus/iio/devices/正常情况下会出现iio:device0对应 ad9361-phy和iio:device1对应 cf-ad9361-lpc等节点。然后用 libiio 工具做一次收发环回验证比如先把发射频率设为 1GHz接收频率也设为 1GHz从发射 DMA 发一组正弦波接收 DMA 抓回来用 Python 的 numpy 做一次相关分析确认波形的频率和初相是否对得上。这一步通过说明设备树移植没有破坏 AD9361 的软件链路后续在上面跑 BPSK 或 OFDM 这类业务算法就安心了。6. 高频问题排查实录6.1 采集数据全零或恒定 DC最常见的原因有几个。首先是接收链路增益设置太低AD9361 的 RX 增益可以从 0 到 70dB 左右调节如果设成 0天线口进来的微弱信号根本不被 ADC 检测到。用 IIO Oscilloscope 调增益时先设一个中等增益如 30dB 再观察。第二个原因是 RX 使能没打开。AD9361 的收发状态机ENSM如果没有正确进入接收模式数据接口上不会有有效的 IQ 数据。在 No-OS 里要调用ad9361_set_en_state_machine设置工作模式并初始化。第三个坑比较隐蔽就是数据接口时序不对。CMOS 模式下数据线在时钟上升沿还是下降沿采样由数据手册里的一个寄存器位控制。如果改了逻辑没有同步改寄存器就可能采到全是 0 或 0xFF 的数据。6.2 IIO Oscilloscope 连接不上目标板检查两点。第一目标板是否运行了iiod守护进程如果没有libiio 的网络后端连不上端口 30431。第二网络是否通先ping一下目标板 IP。如果 ping 通但 iio 连接失败可能是防火墙或 iiod 没起执行iiod 看有没有报错。如果用的是 USB 或者本地模式要确保加载了libiio的本地后端并且设备节点有访问权限。实际调试中我发现不少问题出在用户权限上iio_readdev命令前可以加sudo或者把用户加入iio组。6.3 BPSK 解调星座图旋转星座图旋转的本质是收发端的本振频率有偏差或者采样时钟有偏差。先检查收发两端配置的 LO 频率是否完全一致包括小数部分。AD9361 的 LO 分辨率是微赫兹级别的配置脚本里如果用了浮点打印容易出现肉眼不可见的微小差异积累起来会造成星座图缓慢旋转。如果频率配置没问题就要关注参考时钟精度。晶振的 ppm 值会直接转化为载波频偏。比如收发各用一块板卡参考时钟准确性都是 20ppm2.4GHz 下频偏最坏可以到 96kHz对 1MSPS 的 BPSK 来说影响很大。解决思路是在数字域做频偏估计和补偿或者用外置高精度参考时钟。也可以用 Costas 环把残余频偏消掉这更符合工程实际。6.4 PetaLinux 启动时设备树编译报 duplicate unit address这通常是因为复制节点时没有注意源文件里已经有同名节点比如ad93610在外层 dtsi 里已经被定义过你在system-user.dtsi里又定义了一次。正确做法是用ad9361 { ... }这样的引用方式修改已有节点而不是重新定义。如果旧工程里节点命名是ad93610新工程里 SPI 子节点的地址可能是ad93610也可能是ad93611要按 SPI 片选的实际编号来写不要无脑照抄。6.5 一套问题排查顺序清单多年的调试经验总结下来我遇到问题时一般按这个顺序排查先确认电源和参考时钟这两个是基础。再用 SPI 读寄存器验证通信比如读 AD9361 的 Product ID 寄存器。然后查 FPGA 数据接口是否有时钟信号AD9361 的 DATA_CLK 引脚必须有脉冲。再查 DMA 和中断链路确认 CPU 能收到 DMA 中断。最后才怀疑算法和业务逻辑问题。这个顺序让我少走了非常多弯路。很多人一上来就怀疑算法其实大部分问题都出在链路没有通。一些实际操作里的小经验最后分享几个和 AD9361 官方例程打了很多年交道之后攒下的琐碎经验。第一SPI 读写务必加超时机制。AD9361 的 SPI 通信偶尔会因为时序竞争或者电平不稳导致读取失败如果代码里没有超时保护一次卡死就会让整个初始化流程陷入死循环。No-OS 例程里部分版本对这方面处理不够完善建议在自己的工程里统一封装一层读不到预期寄存器值就重新初始化。第二多备几根 SMA 线缆。射频调试时线缆损耗、接头松动都会让你误判链路好坏。最典型的例子是接收端收不到信号排查半天发现是 SMA 接头只拧了一半。这种问题和软件一点关系都没有但确实能把人逼疯。第三官方例程里的滤波器配置表值得好好研究。AD9361 内置的 FIR 滤波器可以灵活配置官方例程里已经为几种常用采样率生成了对应的系数。你不要一上来就自定义滤波器先用官方配置跑通有性能瓶颈再考虑优化。第四版本记录很重要。复现 AD9361 问题时给别人报信息的时候写明 HDL 的 commit、No-OS 的 commit、内核版本和硬件板卡型号。这四个信息缺一个别人想帮你看问题都无从下手。AD9361 的官方例程体系看着复杂但它其实是一套设计很优雅的参考设计。把 HDL、No-OS、Linux 驱动和设备树这四层的关系理解了把默认流程完整跑一遍再去做自己需要的调制解调算法或者系统移植就不会有那种“满屏代码却不知道从哪下手”的感觉。这套东西我用来用去最终的体会就一句话官方例程是给你打底的不是给你抄的理解每一层为什么这么设计比背下来一百个 API 都有用。