第四十章:双路DA实验
本文对应原书第1054页起,第五篇「实战篇」。
本章在讲什么?(先看这个)
前面章节的 AD/DA 都是 8 位芯片,且一次只能输出一路波形。本章换成正点原子的 ATK_DUAL_HS_DA 模块,板载两颗 3PD5651E 芯片——10 位分辨率、125MSPS 更新率的高速 DAC,实验任务是用 FPGA 同时驱动两路 DAC,输出两路完全相同的正弦波。
这一章的意义在于三点升级:分辨率从 8 位升到 10 位(1024 级)、单路变双路(为后续通信类实验打基础)、波形数据从 256 点 ROM 升级到 1024 点 ROM。整体代码结构与第三十七章高度相似,学习成本不高,重点体会"10 位数据 + 双路并行"带来的细节差异。
核心概念拆解
3PD5651E 芯片特点
3PD5651E 是 10 位高速权电流型 DAC:
- 数据接口:DB0~DB9 共 10 根数据线 + CLOCK 时钟线;
- 数据在时钟上升沿锁存(与 AD9708 相同的规矩);
- 最大更新速率 125MSPS;
- 差分电流输出(IOUTA/IOUTB),经运放转成电压输出。

因为数据在上升沿锁存,FPGA 侧应在下降沿更新数据(或如 ch37 的做法,用 da_clk = ~clk 让锁存沿与更新沿错开半个周期),保证数据稳定期间被采样。这一点在时序图上要仔细看清楚。
10 位数据的幅度表
ROM 变为 rom_1024x10b:深度 1024、宽度 10 位。波形数据由 WaveToMem 软件生成正弦 COE,幅度范围 0~1023。数据与电压的对应关系:中间值 512 对应 0V,满值 1023 对应正满量程,0 对应负满量程。

硬件连接
模块通过扩展口接开发板(与 ch37 相同的 J3 扩展口体系),两路 DAC 的数据线、时钟线并行引出。

程序架构
系统框图与 ch37 一脉相承:PLL 产生 50MHz/25MHz/25MHz(deg120) 三路时钟,da_wave_send 模块读 ROM 送数据,两路 DAC 共用同一份波形数据和发送逻辑,因此输出两路相同波形。
// da_wave_send 核心逻辑(双路输出同一数据)
reg [9:0] rom_addr;
always @(posedge clk or negedge rst_n) begin
if (!rst_n)
rom_addr <= 10'd0;
else
rom_addr <= rom_addr + 1'b1; // 地址循环递增,遍历1024点正弦表
end
assign da_data1 = rom_data; // 第一路DAC数据
assign da_data2 = rom_data; // 第二路DAC数据(同波形)
顶层 hs_dual_da 例化 PLL、rom_1024x10b、da_wave_send。地址位宽从 ch37 的 8 位扩展到 10 位,计满 1024 归零。

验证方法
上板后用示波器分别测量两路 DA 的模拟输出(模块上每路都有测量孔位),应看到两路同频同相的正弦波。也可以把其中一路接到示波器双通道同时观察,验证"双路同波形"的设计目标。
图片对照
- 芯片资料:图 40.1.1(模块硬件结构图)、图 40.1.2(3PD5651E 内部功能框图)、图 40.1.3(时序图)、图 40.1.4(FPGA 内部时序)、图 40.1.5(正弦波数据与电压对应)。
- 硬件:图 40.2.1(模块实物图)、图 40.2.2(3PD5651E 原理图),以及与 ch37 共用的开发板扩展口图
/images/zynq/ch37/ch37_p0982_00937_db3955cefd0832ae.png。 - IP 配置:图 40.4.3(WaveToMem 设置)、图 40.4.4~40.4.8(Block Memory Generator 与 Clocking Wizard 各选项卡)。
- 设计与仿真:图 40.4.9(da_wave_send 框图)、图 40.4.10(端口波形)、图 40.4.11(模块仿真)、图 40.4.12(总体仿真波形)。
- 上板:图 40.5.1(实物连接图)、图 40.5.2(DA 模拟电压测量孔位)、图 40.5.3(示波器显示界面)。
初学者容易踩的坑
- ROM 数据位宽仍是 8 位:从 ch37 工程复制过来忘了改,10 位芯片只能收到 8 位数据,输出幅度直接损失 3/4。Block Memory Generator 的宽度必须设为 10。
- 地址位宽没有跟着扩到 10 位:8 位地址计满 256 就回卷,正弦波只输出了前 1/4 段就重复,波形严重畸变。
- 锁存沿弄反:3PD5651E 在时钟上升沿锁存数据,若 FPGA 恰好在同一沿更新数据,会出现建立时间不足。继续沿用
da_clk = ~clk的错半周期方法最稳妥。 - 两路数据接反或只接一路:模块上两路 DA 的数据线是独立引脚,例化时 da_data1/da_data2 都要连,漏接一路会以为"双路"没生效。
- 幅度表范围写错:10 位的满幅是 1023 而不是 255,WaveToMem 生成 COE 时参数 A 要对应调整,否则输出幅度减半。
- 示波器探头打到 1X 档导致带宽不足:高频正弦波用 1X 档看起来会"发圆",应使用 10X 档并校准补偿。
小结 & 下一步
本章完成三个升级:8→10 位分辨率、单路→双路输出、256→1024 点波形表。代码上几乎只是"位宽加宽 + 数据复制两份",但正是这种通用化设计,让同一套 da_wave_send 架构能支撑不同规格的 DAC。下一章把镜头转向另一侧:用双路高速 ADC(3PA1030,10 位 50MSPS)采集外部信号发生器输入的两路波形。