news 2026/10/21 4:13:11

AD9361+Vivado例程调通指南:从信号链到避坑实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
AD9361+Vivado例程调通指南:从信号链到避坑实战

简介:AD9361 Vivado例程是一套面向FPGA与射频通信开发者的工程模板,基于Xilinx Vivado 2016.4环境,演示从IP核集成、接口设计到配置控制、时序约束及仿真验证的完整流程。资源包共2000个文件,约95MB,主要包含Verilog源码、Tcl脚本、C/H驱动、Makefile、XDC约束、BIT比特流和XCI工程配置,另有大量文档说明,目录结构清晰便于查阅。目前已有4861人学习,适合需要快速上手AD9361的工程师。通过研读工程文件和脚本,可掌握AD9361 IP核配置、AXI总线连接及常见排错方法,为自主设计无线通信系统提供可复用模板。

1. AD9361 + Vivado 例程:为什么拿到源码还是调不通

做软件无线电的朋友大多有过这种经历:从某个地方搞到一套基于 AD9361 的 Vivado 例程,兴冲冲打开工程,跑完综合实现,加载到板卡上,却发现 IIO 设备节点不出现、DMA 读不到数据、频谱上是白噪。问题不在你,而在于这类射频收发例程是一个“串行依赖链”:FPGA 逻辑、管脚约束、嵌入式驱动、设备树、射频前端配置,任何一环没对齐,整条链路都是哑的。这篇文章要拆的资源,就是一套能直接复现的 AD9361 Vivado 参考例程,包含 HDL 工程生成脚本、顶层模块、约束文件和 Linux 侧的设备树与驱动适配脚本。它解决的核心问题只有一个:让你越过四处拼凑的坑,从零把射频收发链路点亮,拿到连续正确的 IQ 数据。适合正在做 Zynq 或纯 FPGA 驱动 AD9361 的开发者,也适合刚接触软件无线电、想用现成例程验证自己算法的从业者。注意,这不是让你“打开工程就跑”,而是要你理解例程里那些默认参数为什么这么定,以及改动之后该怎么调。

2. 从数据手册到上板:AD9361 例程里的信号链与关键 IP

2.1 AD9361 射频前端与 FPGA 接口:为什么例程必须用 LVDS

AD9361 是一颗集成度很高的射频收发器,覆盖 70 MHz 到 6 GHz,接收通道带宽从 200 kHz 到 56 MHz。它内部有混合信号前端、ADC/DAC、抽取/插值滤波器和数字增益控制,但对外与 FPGA 的接口并不复杂:一组 SPI 用于寄存器配置,一组数据总线用于采样数据,还有若干控制 GPIO。数据总线有两种模式,CMOS 和 LVDS。大多数 Vivado 例程默认使用 LVDS 双通道模式,原因很简单:在采样率超过 40 MSPS 时,CMOS 接口的 12 位双通道数据会占用大量管脚,而且时序容易恶化。LVDS 模式下,I 路和 Q 路各自差分成两对线,用 DDR 时钟在上升沿和下降沿分别传两个 bit,这样单通道 12 位数据被折叠成 6 对差分线,管脚压力小得多。

我在写顶层连线前,会先确认 AD9361 的 datasheet 里数据接口时序:FPGA 侧需要提供一个数据时钟(通常由 AD9361 输出,也可以由 FPGA 生成),例程中会有一个ad9361_clkgen模块负责产生采样时钟、数据时钟和字节时钟。这个模块的输出频率计算很关键,如果你修改了采样率配置而没同步调整时钟分频,LVDS 数据采样就永远跟不上,星座点会绕成圆圈。

例程中通常有一个顶层 IP 叫axi_ad9361,它把所有 FPGA 与 AD9361 之间的数据、时钟和状态线集成在一起。外部看是 AXI 接口,内部有接收数据通道、发送数据通道、SPI 控制器和状态寄存器组。下图是典型数据流的文字描述,不是图:AD9361 的 RX 数据经 LVDS 进来,axi_ad9361按协议解析出 I/Q 样本并打包成 AXI Stream,然后交给axi_dmac搬运到 DDR。发送路径相反,CPU 把 I/Q 样本写入 DDR,axi_dmac把数据流送入axi_ad9361的 TX 通道,再按 LVDS 时序送到 AD9361 的 DAC。

2.2 Vivado 例程的工程结构:src、ip、约束、脚本

拿到例程第一步不是双击 xpr,而是先看目录结构。一套规范的 AD9361 Vivado 例程通常长这样:

ad9361_vivado/ ├── projects/ │ ├── common/ │ │ ├── ad9361_bd.tcl │ │ └── ad9361_constr.xdc │ └── zc706/ │ ├── system_top.v │ ├── system_bd.tcl │ └── makefile ├── library/ │ ├── axi_ad9361/ │ ├── axi_dmac/ │ └── util_pack/ ├── scripts/ │ └── make_tcl.tcl └── README.md

这个结构中,projects/common里的 TCL 脚本是模板,ad9361_bd.tcl定义了与板卡无关的 IP 连接,ad9361_constr.xdc定义的是通用管脚约束。真正的板级细节放在projects/zc706下面,比如时钟源、DDR型号、FMC连接器位置。如果你用的是自己的板卡,需要改的主要是system_top.v和对应的约束文件,而不是去动 common 里的 TCL 脚本。很多人在这一步犯的错是直接改 common 中的约束,结果导致生成工程时管脚冲突。

这里有个值得注意的习惯:例程里system_top.v是顶层,它会实例化一个 Block Design,同时把外部差分时钟、复位、UART、网络接口等引出。调试时如果需要加 ILA,最好不要改这个顶层,而是另建一个 wrapper 文件,把顶层实例化后,再在内部对axi_ad9361的关键总线挂 ILA。这样能避免每次重新生成工程时手工修改被覆盖。

2.3 顶层模块与数据通路:接收链的寄存器配置

以接收链路为例,FPGA 内部的数据流是这样的:AD9361 的 RX 差分数据 ->axi_ad9361的 LVDS 接口 -> 内部 FIFO -> AXI Stream 输出 ->axi_dmac-> AXI4 写入 DDR。axi_ad9361内部有一些寄存器,用来配置数据格式(二进制补码还是偏移二进制)、通道交换、数据类型。这些寄存器可以通过 AXI 接口写入,也可以在 Block Design 里设置默认值。

常见例程的顶层实例化片段大致如下,不同版本 IP 名字可能有差异,但思路不变:

axi_ad9361 #( .ID(0), .DELAY_DATA(1'sb0), .DELAY_CLK(0), .DELAY_RX_DATA(1'sd0) ) i_rx_ad9361 ( .adc_clk_in_p(adc_clk_p), .adc_clk_in_n(adc_clk_n), .adc_data_in_p(rx_data_p), .adc_data_in_n(rx_data_n), .adc_valid(rx_valid), .dac_clk_out_p(dac_clk_p), .dac_clk_out_n(dac_clk_n), .dac_data_out_p(tx_data_p), .dac_data_out_n(tx_data_n), .dac_valid(tx_valid), .s_axi_aclk(s_axi_clk), .s_axi_aresetn(s_axi_rstn), .adc_enable_iq0(adc_enable_iq0), .adc_enable_iq1(adc_enable_iq1), .dac_enable_iq0(dac_enable_iq0), .dac_enable_iq1(dac_enable_iq1), .s_axi_awaddr(s_axi_awaddr), .s_axi_awvalid(s_axi_awvalid), .s_axi_awready(s_axi_awready), // ... AXI write and read ports );

这段代码里有几个信号值得注意:adc_valid是接收数据有效标志,adc_enable_iq0和adc_enable_iq1分别使能两路接收通道。如果你只需要单通道,可以把另一个使能拉低,但数据总线仍然按双通道宽度传输,控制器内部会屏蔽无效通道。DELAY_RX_DATA参数用于调节接收数据的采样相位,这是调试 LVDS 接口时最重要的参数,后面避坑章节会专门展开。

3. 让例程跑起来的完整流程:工程生成、约束修改与比特流构建

3.1 通过脚本重建工程:make 与 TCL 流程

拿到 Vivado 例程,我一般不会直接用 GUI 打开 .xpr 工程,而是先执行它的工程生成脚本。原因有两个:一是 .xpr 里记录的 IP 路径可能指向原作者机器上的绝对路径,换一台电脑大概率会失效;二是脚本能统一管理 Vivado 版本、IP 缓存和输出目录。大多数 AD9361 例程的生成逻辑是通过 make 调用 Vivado 的批处理模式执行一个 TCL 脚本,比如:

cd projects/zc706 make vivado-2019.1

这条命令会在projects/zc706/下生成zc706_vivado_2019.1目录,里面才是可用的工程文件。如果没有 make 环境,也可以手动打开 Vivado 并执行:

source ../common/ad9361_bd.tcl source ./system_bd.tcl source ./system_constr.xdc

但手动执行时要注意脚本之间的依赖关系,system_bd.tcl里会调用ad9361_bd.tcl,所以必须先设置好搜索路径。TCL 脚本中通常会包含set_part、create_bd_design、add_board_connections等命令。如果你要改板卡,比如把目标器件从 xc7z045 换成 xc7z035,需要修改所有出现set_part的地方,但更推荐的做法是直接在 makefile 里传入PART变量:

make vivado-2019.1 PART=xc7z035ffg676-2

这个参数会覆盖脚本中默认的器件型号,避免你改错 TCL。注意,不同封装的器件管脚坐标完全不同,换了器件之后 XDC 文件里的引脚位置必须同步更新,否则综合后布局布线必然会报错。

3.2 管脚约束与时钟:最容易翻车的第一道坎

AD9361 例程中,XDC 约束文件通常分成两部分:一部分是通用约束,比如时钟周期、差分对规则;另一部分是板级管脚分配。官方例程的约束文件默认对应某一块特定的 FMC 板卡,如果你用的是其他厂商的板卡,最稳妥的办法是只保留端口名称,然后把端口绑定到你自己板卡上实际连接 AD9361 的那个 FMC 连接器引脚。

下面是一段典型的差分数据约束:

set_property -dict { PACKAGE_PIN AE14 IOSTANDARD LVDS } [get_ports {adc_data_p[0]}] set_property -dict { PACKAGE_PIN AF14 IOSTANDARD LVDS } [get_ports {adc_data_n[0]}] set_property -dict { PACKAGE_PIN AC16 IOSTANDARD LVDS } [get_ports {adc_clk_p}] set_property -dict { PACKAGE_PIN AD16 IOSTANDARD LVDS } [get_ports {adc_clk_n}]

这里有一个容易忽略的细节:AD9361 的 LVDS 接口使用的电平标准是LVDS_25还是LVDS,取决于硬件设计。大部分 FMC 板卡供电为 2.5V,所以用LVDS(有时 Vivado 会根据电压自动选择)。如果你的板卡上 AD9361 的接口电平是 1.8V,那就必须改成LVDS_18,否则上板后数据线没有电压摆幅,死活采不到正确数据。这个现象极其坑人,因为综合实现不会报错,仿真也正常,只有实测时数据全为 0。

时钟约束方面,例程里通常有一个create_clock约束,用于接收 AD9361 输出的数据时钟:

create_clock -name adc_clk -period 8.000 [get_ports {adc_clk_p}]

这个 period 值对应 125 MHz,如果例程默认采样率是 61.44 MSPS,DDR 数据时钟是 122.88 MHz,实际周期约 8.138 ns。如果你在 Block Design 里改了采样率,别忘了同步修改这条时钟约束。否则时序报告会异常,或者下到板卡后采样时间不对。

3.3 生成比特流并验证:从硬件管理器到 ILA 抓信号

工程生成后,先做一次 “Generate Bitstream”,等待综合、实现、生成 bit。这个过程在只改动约束的情况下大约需要 30 分钟到 1 小时,主要取决于电脑配置。生成结束后,打开 Hardware Manager,加载 bit 文件到 FPGA。如果只是纯数字验证,可以先不连 AD9361 的射频前端,直接跑 FPGA 内部回环。

在 FPGA 内部,axi_ad9361通常支持数字回环模式:把发送数据直接环回到接收数据通路,这样不需要外部射频信号就能验证 AXI DMA 通路。开启这个模式需要往axi_ad9361的寄存器写值。常见做法是通过 AXI GPIO 或 JTAG 的 ILA 触发器来修改。更方便的是通过 PS(Zynq 处理器)端写寄存器,但如果你没有 PS,或者例程配置的是微盲区(standalone)模式,那就要用 Vivado 的 VIO 核来手动置位。

使用 ILA 时,建议把axi_ad9361的接收数据接口挂上,观察adc_valid是否周期性拉高,以及数据是否在变化。许多人第一次抓 ILA 遇到的问题是adc_valid一直为低,这通常不是信号链问题,而是 ILA 的时钟没选对。axi_ad9361的数据时钟和 AXI 总线时钟是异步的,如果 ILA 挂在 AXI 时钟域而数据是数据时钟域,必须用async方式跨时钟,否则 ILA 采样到的adc_valid会一直是一个错误电平。我一般在调试时挂两套 ILA:一套挂 AXI 总线时钟域的 DMA 接口,另一套挂数据时钟域的原始数据接口,分开观察。

4. 调试射频链路:从丢包到频谱异常的排查清单

4.1 回环测试校准基带

不管最终要用射频收发,还是只做基带验证,我都建议先跑一遍数字回环。AD9361 的参考例程中,会在顶层预留一个dcxo或gpio控制位,用来切换 AD9361 的工作模式。在没有 AD9361 驱动初始化之前,FPGA 的数字回环可以直接在axi_ad9361内部完成:TX 数据在输出前被复制到 RX 数据入口。这个操作可以通过修改寄存器实现,也可以通过一个简单的 AXI GPIO 控制。

在 Zynq 方案中,如果使用 PetaLinux 和 IIO 框架,可以通过iio_regmap或直接操作寄存器地址来开启回环。更简单的方法是先在裸机环境跑一个最小测试例程:只配置 AXI 总线,不配置 AD9361 芯片,然后尝试写一个已知序列到 TX DMA,再从 RX DMA 读回。如果读回的数据与写入完全一致,说明 FPGA 内部通路是通的。如果读回的数据不一致,重点排查 AXI DMA 的缓冲长度是否正确。很多例程在顶层配置了 8KB 的 DMA buffer,但你实际搬运的样本数超过这个长度,数据就会被截断或覆盖。

具体操作步骤是先用一个数组填充发送缓冲区,比如填充递增数 0x000 到 0xFFF,然后启动 TX DMA,再启动 RX DMA,完成后比较接收缓冲区。代码里可以用一个简单函数:

int fill_and_check(uint32_t *buf, int len) { for (int i = 0; i < len; i++) { tx_buf[i] = (i & 0x0FFF) | 0x1000; // 加入固定标记位 } dma_start_tx(0, tx_buf, len); dma_start_rx(0, rx_buf, len, 1); for (int i = 0; i < len; i++) { if (rx_buf[i] != ((i & 0x0FFF) | 0x1000)) { return i; } } return -1; }

这个函数里的dma_start_tx和dma_start_rx是封装的寄存器操作。关键在于 RX 需要比 TX 提前启动,或者至少要在 TX 写完之前启动,否则会丢开头几个样本。例程中axi_dmac支持一种“循环模式”,它会让 DMA 不断填充新数据,比较适合这种回环验证。

4.2 射频回环与增益控制

数字回环通过后,再打开 AD9361 的射频回环。此时需要先完成 SPI 初始化,然后配置收发频率。通常 AD9361 的例程会提供一个配置文件或者初始化脚本,用一组寄存器表写入芯片。常见的操作是在 Linux 里用 IIO 设备来配置:

echo 2430000000 > /sys/bus/iio/devices/iio:device0/out_altvoltage0_frequency echo 20 > /sys/bus/iio/devices/iio:device0/out_voltage0_hardwaregain echo 1 > /sys/bus/iio/devices/iio:device0/out_altvoltage0_att_ctl

这些参数分别是设置 TX 本地振荡器频率为 2.43 GHz,发送通道增益为 20 dB,以及使能衰减控制。RF 端需要一个衰减器或者天线负载,否则回环可能引发自激。如果你没有频谱仪,也可以把 TX 输出直接通过一段同轴电缆连到 RX 输入,注意加一个 30 dB 固定衰减器。很多人在这里翻车:直接连一根线,结果 AD9361 的 LNA 饱和,接收频谱变成一片平顶。正确做法是先设置 RX 自动增益控制为慢速模式,并观察 RSSI 是否在合理范围。用 IIO 读 RSSI:

cat /sys/bus/iio/devices/iio:device0/in_voltage0_rssi

如果 RSSI 接近满量程,说明输入功率过高,应该增加衰减器或者降低 TX 增益。这一条调试经验,比你在误码率上纠结半天更管用。

4.3 常见问题排查:位宽不匹配、数据顺序错、时钟域问题

在排查过程中,有几个高频问题值得单独拎出来说。第一个是位宽不匹配。AD9361 的 ADC 和 DAC 是 12 位,但通常以 16 位样本存储到 DDR 中,低 4 位要么是符号扩展,要么是零填充。如果你发现数据幅度只有预期的一半,或者信号有直流偏置,检查一下是否把 12 位数据当成了 16 位来解释。很多例程会提供ad9361_adc_interface模块,它负责把 12 位复用信号扩展成 16 位 I/Q。

第二个是数据顺序错。在 LVDS 双通道模式下,数据线上传输的顺序是 IQ 交替还是 I 两路后再 Q 两路,取决于配置。如果你的星座图出现镜像或者 Q 路变成 I 路,多半是通道交换配置没对齐。axi_ad9361中有寄存器可以设置 IQ 顺序,也可以在驱动初始化脚本里修改IQCORRECTION相关参数。有一个肉眼可判断的方法:发送一个单音信号,观察 I 路和 Q 路的频谱能量;如果能量在正负频段对称,说明通道没问题;如果只有一边有能量,则可能 I/Q 交换了或者正交度出了问题。

第三个是时钟域问题。当 FPGA 逻辑自定义部分(比如用户自己的 FFT)与axi_ad9361接口交接时,很容易产生跨时钟域数据丢失。例程中通常提供了axis_clock_converterIP,你应该保证用户逻辑的 AXI Stream 时钟与 DMA 的时钟一致,或者在快慢时钟域变换时使用足够的 FIFO 深度。不要图省事直接用寄存器打两拍来跨时钟,因为 AXI Stream 的 valid-ready 信号需要严格握手,简单打拍会导致数据丢失。

5. 避坑指南:AD9361 Vivado 例程的五个典型翻车现场

5.1 IP 核版本不匹配导致综合报错

现象:打开例程工程后,点击 Generate Bitstream,在综合阶段报出一堆端口不匹配错误,比如Port 'adc_valid_i0' does not exist。原因:例程是用某个特定 Vivado 版本创建的,你用的版本更高,IP 核被自动升级,但底层端口变化了。解决:先不要升级 IP,右键 Block Design 的 IP 核,选择 “IP Settings -> Compatible Families”,或者在生成工程前确保环境变量里指定的 Vivado 版本和例程 README 中的版本一致。如果非要使用新版本,那就需要手动检查所有实例化端口,特别是自定义的axi_ad9361的端口列表。更稳妥的做法是使用脚本重新生成整个工程,而不是打开 .xpr 后让 Vivado 自动升级,因为脚本会直接适配当前版本创建 IP。

5.2 现象:DDC/DUC 配置后输出频率偏移

现象:配置好 LO 频率后,接收信号的中心频率与预期偏移了几十 kHz 到几百 kHz。原因:AD9361 内部的抽取滤波器系数或者采样率设置与 FPGA 侧的数据时钟不同步。使用例程时,如果只修改了 RF 频率,而没有修改 PLL 的参考分频、采样率和 FPGA 时钟生成部分,就会出现频率偏移。解决:例程中一般有一个ad9361_clkgen模块,它会根据配置寄存器自动生成时钟,但前提是驱动侧的时钟配置表与 HDL 侧完全一致。建议检查 Linux 下iio_info -s输出的采样率是否和 FPGA 实例化参数一致,如果不一致,用echo <new_rate> > /sys/bus/iio/devices/iio:device0/in_voltage_sampling_frequency重新配置。如果仍然偏移,就要重新生成 AD9361 的配置表,而不是靠软件去修正一个小数倍频。

5.3 现象:LVDS 数据采样相位不对,星座图散乱

现象:射频回环正常,但接收到的单音信号在 IQ 图上是一个圆环,而不是一个点。原因:LVDS 接口的采样窗口没有对准。AD9361 输出的数据在时钟沿前后一段时间有效,FPGA 内部需要在正确的边沿进行抽样。如果时钟延迟或数据延迟设置不对,抽样点会落在数据翻转区域。解决:调整axi_ad9361的DELAY_RX_DATA参数,这个参数本质上是 FPGA 的 IODELAY 配置。你可以从 0 开始逐渐增大,每次增加 1 延迟步进,重新采集数据并观察 EVM。找到 EVM 最低点后固定参数。有些例程会在初始化脚本里设置这个值,建议放在一个便于修改的位置,例如ad9361_bd.tcl顶部的局部参数。

5.4 现象:DMA 无法工作,读取不到数据

现象:寄存器配置成功,ILA 看到 AXI Stream 上有数据,但读取 DDR 里的缓冲全是 0。原因:通常不是axi_dmac本身问题,而是 MMU 或缓存一致性问题。在 Zynq 上运行 Linux 时,DMA 写入的内存如果不能保证缓存一致,CPU 读到的是陈旧缓存。解决:使用 IIO 内核驱动时,驱动会使用dma_alloc_coherent分配一致内存,理论不存在这个问题。但如果是在裸机上自己写 DMA,就要确保缓冲区地址是物理连续地址,并且设置 MMU 的 Cache 属性为 Non-Cacheable。另外检查axi_dmac的DMA_SRC_ADDR寄存器的地址,如果例程默认是 0x40000000,而你实际 DDR 是 0x00000000,就要修改设备树或者寄存器值。

5.5 现象:设备树和驱动加载失败

现象:加载 bit 文件后,Linux 启动时dmesg提示Failed to probe ad9361,或者 IIO 设备节点没有生成。原因:设备树里 spi 节点、使能引脚、中断号与实际硬件不匹配。解决:对比你的板卡原理图,确认 AD9361 的 SPI 片选接到了 PS 的哪个 SPI 控制器,中断线接的是哪个 GPIO。常见例程中设备树会写为:

&spi0 { ad9361@0 { compatible = "adi,ad9361"; reg = <0>; spi-max-frequency = <10000000>; adi,frequency-integer = <1>; }; };

这个spi-max-frequency很容易出问题。AD9361 的 SPI 最高频率根据数据手册不同,有些版本只支持到 50 MHz,写太快会导致寄存器配置出错。如果你在初始化过程中发现校准失败,尝试把 SPI 频率降到 10 MHz 以下,这是不少开发者折腾几天才找到的原因。

6. 把官方例程改成适合自己的设计:裁剪与验证的三个技巧

官方例程的价值在于它给了你一个已知正确的地基,你可以在这个地基上修自己的楼。三个技巧我认为最实用。

第一个技巧是保留 Block Design 中的验证环境,把你的自定义 DSP 模块挂到 AXI Stream 总线上。不要直接改axi_ad9361的内部,而是新建一个 AXI 外围设备,把axi_ad9361的 M_AXI 接口(接收数据)连到你的模块,你的模块处理后再连到axi_dmac。这样如果数据不对,可以先把自定义模块置为直通,验证官方通路还是好的,再逐步打开自己的处理逻辑。这个“直通开关”一定要做成 AXI 寄存器,方便运行时切换。我通常会在自定义模块里加一个 32 位控制寄存器,bit0 为 1 时输出等于输入,bit0 为 0 时输出是自己的处理结果。这个小小的设计能省下大量来回烧 bit 的时间。

第二个技巧是学会修改采样率和带宽。很多人在例程上想把自己的信号采样率从 10 MSPS 改成 2 MSPS,但只改了驱动侧参数,没改 FPGA 侧时钟。正确路径是:先确认 AD9361 的 BB 带宽和 ADC 抽取率,再计算出数据时钟频率,然后回到 Vivado 工程修改ad9361_clkgen的目标频率,最后同步调整 XDC 里的时钟约束。如果路径复杂,最省事的办法是直接用官方提供的配置工具生成新的配置表,然后用脚本替换旧表。不要相信驱动会自动重配 FPGA 时钟,至少在我见过的例程中,FPGA 的实际时钟是固化在 bit 里的,驱动侧只能配置芯片内部的分频,无法改变 FPGA 和 AD9361 之间的数据传输频率。所以当你发现驱动设置采样率后数据速率对不上,优先回源头检查时钟。

第三个技巧是用 Python 脚本实时解析接收数据,快速验证射频通路。不要每次都用 ILA 去抓波形,效率太低。在 Linux 上通过 IIO 读取数据后,用 Python 处理 IQ 样本,绘制频谱和星座图。我在调试时有一个固定流程:启动后先用一个 L脚本设置中心频率 2.4 GHz,采样率 10 MSPS,然后让 DMA 连续采集 1 秒数据,保存到文件,再用 Python 读文件做 FFT。如果频谱上只有一个主峰,说明例程配置成功;如果出现谐波或杂散,则检查功率是否过高或者滤波器是否设置错误。这个习惯帮我避开了“盯着 ILA 时序看半天,却忘记看整体频谱响应”的老路。

这套 AD9361 Vivado 例程里,真正值钱的不是那些 IP,而是它把射频与 FPGA 之间的所有细节都填好了。从那以后我每次拿到新板卡,都强制走一遍数字回环 → 射频回环 → IIO 数据采集的流程,先确认官方通路,再做自己的改动。希望你也能少走这些弯路,一次点亮。希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/21 4:12:47

迁移学习从入门到整理:概念、微调与踩坑指南

“迁移学习还没整理好”——这句话我在好几个朋友的文档收藏夹里都见过。说真的&#xff0c;迁移学习这个方向入门不算难&#xff0c;但想把理论、代码、实验技巧串成一条线&#xff0c;确实容易越看越乱。今天我就把自己整理迁移学习内容的思路和踩过的坑从头到尾捋一遍&#…

作者头像 李华
网站建设 2026/10/21 4:12:45

SpringBoot驱动的数据库原理教学辅助系统设计与实践

基于SpringBoot的《数据库原理》课程教学辅助系统开题报告做课程教学辅助系统这类项目&#xff0c;很容易一开始就被“后台管理增删改查”带偏思路。我最初拿到“基于SpringBoot的《数据库原理》课程教学辅助系统”这个题目时&#xff0c;翻来覆去想的都是用户管理、课程管理、…

作者头像 李华
网站建设 2026/10/21 4:12:45

拆解BAT32G157固件库:平替STM32F0的国产MCU选型与移植指南

简介&#xff1a;中微半导体 BAT32G137 的 1.00.4 版开发资源包&#xff0c;面向低功耗与高性能嵌入式项目开发者&#xff0c;也适合从 STM32 迁移过来的工程师快速上手&#xff0c;可用于电池供电、传感器采集等场景。压缩包共 591 个文件&#xff0c;体积仅 1.62MB&#xff1…

作者头像 李华
网站建设 2026/10/21 4:12:31

知识工作者插件管理:分层配置与工作流优化

前阵子整理工作环境&#xff0c;我统计了一下自己日常在用的插件&#xff1a;笔记软件里装了十几个&#xff0c;代码编辑器里二十多个&#xff0c;浏览器里还常驻着几个。数字看着挺唬人&#xff0c;但真正每天都在用、能显著提升效率的&#xff0c;其实不到三分之一。剩下的那…

作者头像 李华
网站建设 2026/10/21 4:11:48

K8s Pod终端断线重连:链路分析、tmux与WebSocket心跳

连着 k8s pod 的终端又断了。我盯着屏幕上的 Connection reset by peer&#xff0c;已经不知道是第几次了——跑了一小时的数据同步任务&#xff0c;进度显示到 63%&#xff0c;现在整个终端像睡着了一样&#xff0c;按什么键都没反应。更郁闷的是&#xff0c;任务本身没崩&…

作者头像 李华
网站建设 2026/10/21 4:10:42

空压机数字化管理:从能耗黑洞到智能诊断的落地实践

半夜接到车间主任电话&#xff0c;说空压机跳机了&#xff0c;整条产线停摆&#xff0c;电费这个月又超了预算。这种场景在制造业里太常见了&#xff0c;空压机明明是车间里最不起眼的“辅助设备”&#xff0c;却常常是电费单上的头号大头。很多工厂宁愿花几十万换新机&#xf…

作者头像 李华