搞ZYNQ-7020调试的兄弟,估计十有八九都撞过这么一堵墙:Vitis里点开调试,等半天,结果弹出来一行报错,说找不到目标设备,或者干脆卡在连接阶段,Target Manager里那个ARM DAP的图标死活不亮。我前阵子就在一块自制的7020板卡上被这事困了两天,Vitis 2023.2、JTAG-HS3下载器,hello world工程的elf都编译好了,就是不往下走。后来一步步把硬件链路、hw_server、XSCT脚本全捋了一遍,才定位到是板卡上PS_POR_B复位引脚的电平时序跟调试器初始化顺序有冲突。
这类问题在7系列ZYNQ上非常典型,尤其是从Vivado 2020.1之后版本切换到统一安装器、或者从SDK切到Vitis环境的朋友,遇到"无法识别ARM DAP"的次数比想象中高得多。这篇就把我这次的排查过程、原理分析和解决手段完整写出来,从硬件信号到软件工具链,按层拆解,希望能帮同样被卡住的人省点时间。
1. 先搞懂ARM DAP:Vitis调试时到底在连什么
很多人在这一步就懵了,因为Vitis报错信息里经常出现DAP、Debug Hub、ARM CoreSight这些词,但并不知道它们之间的关系。如果不理解Vitis访问目标的链路,排查起来就是瞎猜,一会儿怀疑硬件一会儿怀疑软件,效率很低。
1.1 报错背后的调试链路
7系列ZYNQ的调试架构基于ARM CoreSight调试体系,内部集成了DAP(Debug Access Port,调试访问端口)。DAP不是一个单纯的寄存器块,它由两部分组成:DP(Debug Port,调试端口)和AP(Access Port,访问端口)。DP负责处理外部JTAG接口协议,AP则负责连接到芯片内部的调试总线,比如AXI-AP、MEM-AP等。
Vitis调试时,链路是这样的:
下载器(比如Digilent JTAG-HS3)通过USB连接到PC,JTAG信号接到板卡的JTAG接口,走TDI、TDO、TCK、TMS四根线,进入ZYNQ的JTAG TAP。这个TAP就是DAP的对外窗口。Vitis侧通过hw_server这个后台服务进程跟下载器通信,hw_server通过JTAG链路向DAP发送DPACC和APACC操作,DAP再转发到AXI总线,从而访问DDR、OCM、或者读取Cortex-A9核的状态寄存器。
当你看到Vitis提示无法识别ARM DAP时,通常是这条链路的某一环出了问题。有可能是JTAG接口根本没枚举到ZYNQ设备,也有可能是枚举到了但DAP无法正常应答,还有可能是DAP应答了但后续访问AP时得到了错误返回。不同环节出问题,报错长得很不一样,但只要理解了这条链路,排查方向就很清晰。
1.2 DAP与AP的区别决定排查方向
DP和AP的分工是理解调试问题的关键。DP层负责最底层的JTAG交互,比如读取IDCODE、写DPACC寄存器。AP层负责更高层的总线访问,比如通过MEM-AP访问地址空间。如果DP层都过不去,说明硬件连接或时钟有问题;如果DP层能过、但AP层失败,那问题可能在于目标系统没有初始化好,比如AXI总线时钟没起、DDR控制器没配置。
实际工作的时候,我习惯先分两层去判断:
- DP层失败:表现为JTAG枚举能看到IDCODE,但尝试访问DPACC寄存器时返回全F或超时。这通常和电源、参考时钟、复位有关。
- AP层失败:表现为DPACC寄存器能读能写,但AP中的MEM-AP或AXI-AP访问异常,比如读DDR返回数据不对。这通常和PS端的时钟启动、MIO配置、或者DDR初始化代码有关。
在Vitis的调试流程里,它启动目标时会枚举JTAG设备,如果第一步就失败,会提示类似"Device not found"或"Target connection failed";如果第二步失败,则会提示Cortex-A9 core无法halt或无法读取寄存器。
注意:很多人在7系列ZYNQ上遇到的DAP无法识别,实际上是DP层的问题,也就是外部条件没满足。这类问题往往不是Vitis配置错了,而是板卡硬件层面的坑。
2. 硬件排查:先确认Target端"活着"
软件工具链再强大,也架不住硬件链路不通。我在做硬件调试排查时,第一步永远是确认目标板卡的基本状态,这个顺序不能乱,不然容易把问题往复杂里想。
2.1 电源与时序:不要一上来就怀疑软件
ZYNQ-7000的供电要求不算复杂,但每一路都缺一不可。VCCINT、VCCAUX、VCCBRAM、VCCO、VCCPLL、VCCPAUX这些电源域的电压和时序必须满足要求。这里有个常见的坑:PS端的VCCAUX和VCCPLL如果没供电或电压不对,JTAG接口是有可能枚举出IDCODE的,但DAP内部的逻辑无法正常工作,导致后续调试失败。
我自己做板卡习惯用示波器量一下上电时序,确认VCCPLL和VCCPAUX在上电后保持稳定。VCCPLL是PS内部PLL的供电,如果这个电压不稳,PS_CLK即使有时钟,内部逻辑也跑不起来。之前遇到过一块板卡,VCCPLL上的电容焊错容值导致纹波过大,Vivado Hardware Manager里能看到设备,但Vitis怎么都连不上DAP,排查了好久才发现是这里的问题。
另外,PS_POR_B信号非常关键。这个引脚是PS的复位输入,低电平有效。调试器初始化ZYNQ时,需要先释放PS_POR_B,PS才能正常工作。很多自制板卡会用RC电路给PS_POR_B做上电延时复位,如果R或C的取值不合理,PS_POR_B释放时间太晚,或者释放时存在抖动,Vitis在枚举设备时会反复读到不稳定的状态。
实测经验:PS_POR_B的RC复位时间建议控制在10ms到100ms之间。太短了无法可靠复位,太长了调试器在扫描设备时会因为复位未释放而识别不到DAP。
2.2 JTAG信号完整性检查要点
JTAG信号看着简单,只有四根线加可选的地线,但这几根线是最容易出问题的。用万用表量一下板卡上JTAG接口跟ZYNQ引脚之间的通断是最基础的。我之前遇到过JTAG连接器虚焊,TMS引脚不通,导致设备枚举时好时坏。
除了通断,还要注意JTAG信号的参考电平和上拉下拉电阻。ZYNQ的JTAG引脚位于特定的BANK,这个BANK的VCCO电压必须和下载器输出电平匹配。比如ZYNQ-7020的JTAG引脚在BANK 500,如果这个BANK的VCCO是3.3V,但下载器是1.8V电平,电平不匹配就会导致信号识别异常。
JTAG信号建议按以下检查:
- TDI、TDO、TCK、TMS四根线逐一量通断,确认没有断路或短路。
- 确认TCK、TMS、TDI有合适的上拉或下拉电阻。按照Xilinx官方建议,TCK建议下拉,TMS和TDI建议上拉,TDO可以不处理。如果板卡上没有这些电阻,下载器本身的驱动能力可能不足,调试不稳定。
- 量一下JTAG接口的VCCO参考电压是否正常。
2.3 PS端复位与时钟的特殊性
ZYNQ的PS有多个复位信号,除了PS_POR_B之外,还有PS_SRST_B和外部看门狗复位。PS_SRST_B作用范围比PS_POR_B小,但同样会影响调试连接。在JTAG调试时,如果PS_SRST_B一直被拉低,内核无法运行,DAP的某些寄存器访问也会失败。
时钟方面,PS_CLK是一个必须关注的信号。ZYNQ-7000本身需要一个PS_CLK输入时钟,在没有配置PLL的情况下,PS_CLK会直接作为PS内部模块的参考时钟。DAP本身对PS_CLK的依赖相对较低,因为DAP可以通过JTAG时钟独立工作,但很多AP访问操作,比如通过AXI-AP访问DDR,依赖PS内部的时钟已经初始化。
如果PS_CLK根本没有起振,Vitis大概率能枚举到JTAG上的ZYNQ设备IDCODE,但访问CPU时就会失败,因为CPU没有时钟跑不起来。所以排查时用示波器确认PS_CLK频率是否正常,一般7系列ZYNQ用33.333MHz或其他频率,但必须在数据手册规定的范围内。
3. 软件环境排查:从hw_server到Vitis的完整链路
硬件状态确认无误之后,如果还是识别不了ARM DAP,那就要转到软件工具链这边来查了。不要再反反复复重启Vitis或者重新插拔调试器,那个意义不大,正确做法是逐层看工具的日志和状态。
3.1 hw_server日志怎么读
Vitis调试时启动的hw_server进程,是PC和调试器之间的桥梁。它负责枚举下载器、扫描JTAG链路上的设备、以及处理Vitis发下来的调试命令。hw_server启动时会在终端或日志文件里输出当前扫描到的设备信息,这些信息就是第一手的排查依据。
在Vitis中可以在Flow Navigator里找到Xilinx -> Program and Debug,或者在终端里手动启动hw_server。手动启动的好处是能看到完整的日志输出,不会因为GUI界面把细节吞掉。
日志里最关键的几处:
- 下载器识别信息:USB连接是否成功,驱动是否加载。
- JTAG链扫描结果:枚举出了哪些IDCODE,链上设备的数量。
- 设备匹配信息:识别出的设备是否与Vitis工程期望的目标匹配。
我这次遇到的情况,hw_server日志里显示能识别到Xilinx的下载器,但扫描JTAG链时,链上只有一个非预期设备,没有ZYNQ的IDCODE。这说明问题出在JTAG链路连接或目标设备本身。
3.2 Vivado Hardware Manager和Vitis结果不一致怎么办
这是个值得单说的问题。很多时候你会发现,同一个下载器同一块板卡,用Vivado Hardware Manager连接一切正常,能看到ZYNQ设备,也能读IDCODE;但切到Vitis里调试就识别不到ARM DAP。如果出现这种情况,反而说明硬件链路是通的,问题出在Vitis的配置或版本匹配上。
Vitis的调试目标配置是在工程里设置的。新版本的Vitis在创建调试配置时需要选择目标设备,有时候这里选错了,或者配置文件里记录的IDCODE与板卡实际IDCODE不匹配,连接时就会失败。解决方法是手动检查调试配置的target设置,删掉旧的重新扫描。
另外,Vivado和Vitis内置的hw_server版本如果不一致,也可能导致问题。一个比较典型的情况是Vitis安装时没有选择安装Vivado的完整组件,导致Vitis调用了一个旧版或缺失的hw_server。可以到安装目录下看hw_server的版本,确认和Vivado版本匹配。
3.3 Cable驱动与权限问题
这个坑在Linux环境下尤其常见,Windows下也偶尔碰到。Digilent的JTAG-HS3、Xilinx Platform Cable USB II这类下载器,在Linux下需要安装对应的udev规则,否则普通用户没有权限访问USB设备,hw_server就无法打开下载器。
Windows下常见的问题是驱动装错,或者调试器插了多个,hw_server选择了错误的设备。可以打开设备管理器,查看调试器是否正确枚举为"Jungo"或"Digilent"设备,而不是未知设备。
如果条件允许,建议在排查DAP问题前,先做一次最简单的测试:在Vivado Hardware Manager里打开硬件目标,点击设备枚举,看是否能看到ZYNQ的IDCODE。这个测试能帮你快速把问题切分到硬件链路还是Vitis工程配置。如果连Vivado都识别不到,就不要再折腾Vitis了,回头检查硬件和下载器。
4. 用XSCT命令行手动探测DAP
Vitis的图形界面对排查问题不太友好,因为它做了很多封装,报错信息也模棱两可。真正高效的方式是直接用XSCT(Xilinx Software Command-Line Tool)手动连接,一步步探测DAP的状态。XSCT是Vitis底层调试引擎的shell,命令能精确控制调试链路。
4.1 连接、枚举的基本命令
打开XSCT的方式是在Vitis的终端里输入xsct,或者直接打开安装目录下的xsct可执行文件。启动后,第一步是连接hw_server:
connect这个命令会让XSCT尝试连接默认本地hw_server服务。如果当前没有启动hw_server,可以先启动再连接:
connect host localhost port 3121连接成功后,用以下命令查看当前JTAG链上的所有目标:
targets这会列出链上的所有设备,包括JTAG TAP、ARM核、以及其他调试组件。正常情况下,应该能看到一个类似"ARM Cortex-A9 MPCore"的target。如果这里什么都没有,或者只看到一个JTAG连接而没有任何ARM设备,那么DAP的探测就失败了。
4.2 手动访问AP与Memory
如果targets命令能看到ARM核,说明JTAG链路和DAP的DP层是好的。接下来可以尝试通过DAP访问内部存储或寄存器,确认AP层是否正常。
先选中ARM target:
targets -set -filter {name =~ "ARM*"}然后尝试复位系统并读取寄存器:
rst rreg如果这些命令能正常返回,说明DAP工作正常,问题可能不在硬件而在Vitis工程配置。如果rreg卡住或报错,说明AP层有问题,需要进一步深入调试。
我遇到过一种情况:targets命令能看到ARM核,但rreg返回数据全是0xFFFFFFFF,这通常意味着DAP和AP之间的连接不稳定,或者PS的时钟没有初始化好。此时可以尝试用bps(breakpoint)设置或mrd(memory read)来进一步诊断:
mrd 0x00000000如果读取OCM地址空间返回异常,基本可以确定PS内部时钟或总线接口没有正常启动。
4.3 从日志反推问题出在哪一层
XSCT执行每条命令时,都会在后台输出交互日志,可以通过设置日志级别来获取更多细节:
log -level debug调试级别的日志会显示DPACC和APACC操作的详细结果,包括返回的ACK值。这里有个简单的判断法则:
- 如果DPACC操作返回的ACK不是OK(二进制01),说明DP层有问题。
- 如果DPACC正常但APACC返回错误,说明AP层有问题。
用这个方法反推,能把问题定位得非常准。大部分时候,DP层出问题都逃不开供电、复位、JTAG信号这几个因素,AP层出问题则偏向PS初始化、时钟、DDR配置这些软件层面的因素。
5. 常见报错与排查速查表
这次排查过程中,我整理了几个ZYNQ调试时的典型报错和对应解决思路,做成速查表,遇到问题可以按图索骥。
| 报错现象 | 可能原因 | 排查方向 |
|---|---|---|
| hw_server日志中无JTAG设备 | USB驱动/下载器连接问题 | 检查设备管理器/udev规则,更换USB口 |
| JTAG链枚举不到ZYNQ IDCODE | JTAG信号通断、VCCO不匹配 | 万用表量通断,确认参考电压 |
| 枚举到IDCODE但DAP无法访问 | PS_POR_B未释放、VCCPLL异常 | 示波器查复位时序和电源纹波 |
| targets中没有ARM core | 调试配置选错设备、JTAG菊花链影响 | 用Vivado Hardware Manager对比,检查配置 |
| rreg返回全F | AP层异常、PS时钟未初始化 | 检查PS_CLK,尝试rst -system |
| Vitis报错Debug hub not detected | 调试配置中Target选择错误 | 删除配置重新扫描,核对IDCODE |
5.1 典型报错对照
上面表格里列的几种情况,我按从硬件到软件的顺序排了优先级。先确认供电,再查JTAG线缆,然后看复位信号,最后才查Vitis配置。大多数卡在"DAP无法识别"的问题,都能在这个顺序里找到答案。
5.2 多板卡/多调试器场景
如果你同时接了多块板卡或者多个调试器,还会遇到目标冲突的问题。hw_server会把所有调试器上的设备都扫描出来,Vitis默认连接第一个匹配的设备。有时候Vitis连上了A板卡,但你实际要在B板卡上调试,也会出现"找不到目标"的假象。XSCT里可以通过以下方式查看所有连接到的设备,并手动选择:
targets -g在Vitis图形界面的Target Manager里,也可以通过手动选择指定的调试器和设备来规避。
5.3 烧写Flash与DDR依赖问题澄清
关于网络热词里提到的"ZYNQ 7020使用JTAG固化Flash时必须使用DDR吗"这个问题,我在这篇文章里简单澄清一下。JTAG固化Flash(比如QSPI)时,通常不需要DDR参与,因为固化流程是通过AXI-AP访问QSPI控制器完成的,跟DDR没关系。但很多参考设计确实会先用一段初始化脚本设置PS端的引脚和时钟,这段脚本运行在OCM里,也不依赖DDR。
如果你用了错误的FSBL或者初始化脚本,固件里包含了DDR初始化的操作,那编译、链接时不会报错,但运行固化流程时可能会卡住,因为DDR根本没有接或者没配好。这时Vitis的报错可能涉及DAP无法访问,需要区分是真正的DAP问题还是初始化脚本的问题。
经验之谈:遇到固化Flash失败,先确认初始化脚本里是否包含DDR相关的MIO配置。如果有,可以把DDR初始化这一段注释掉再试,能排除很大一部分干扰。
6. 几点实操心得
6.1 自制板卡的调试顺序
如果你用的是自制板卡,我在这次之后总结了一套固定的调试顺序,分享出来:
- 第一步,上电后先量所有供电轨,确认电压和纹波在规格范围内。
- 第二步,用示波器确认PS_CLK有时钟,PS_POR_B释放后有稳定的高电平。
- 第三步,在Vivado Hardware Manager里做JTAG识别测试,确认能看到ZYNQ的IDCODE。
- 第四步,在XSCT里手动连接,确认能枚举到ARM核并访问寄存器。
- 第五步,才打开Vitis的调试,加载elf。
这套顺序只需几分钟,但能把"硬件问题"和"工程配置问题"彻底切分,省下的时间远远超过这几分钟。
6.2 版本兼容性是个隐形杀手
这次遇到的问题之所以折腾了那么久,有一个原因是Vitis 2023.2和之前一直使用的Vivado硬件服务器版本不匹配。安装Vitis时,如果同时安装了Vivado,Vitis会调用自己的hw_server。但如果你的环境里既有旧版Vivado又在PATH里,或者Vitis安装时勾选组件不全,就会出现hw_server版本混乱的情况。排查这个问题,可以查看进程里实际运行的hw_server路径和版本。这个细节平时不起眼,关键时刻却能卡你一天。
6.3 最后再分享一个小技巧
在Vitis的Debug Configuration里,如果遇到"Target selection"下拉框为空或选不到设备,可以尝试在Target Manager里点击"Add"重新扫描一次。有时候是因为Vitis启动时hw_server还没有完全就绪,GUI就刷新了列表,导致目标列表为空。手动重新扫描往往能解决问题。
另外,使用第三方调试器的话,建议每次更换调试器型号后删除旧的调试配置重新创建。Digilent、IXXAT、SEGGER等调试器的Target配置格式并不完全一样,直接沿用旧配置很可能会踩到识别不出来的坑。