ZCU106开发板调试手记:当串口不够用时,用XSCT的jtag-uart功能搞定MicroBlaze打印输出

在嵌入式开发中,调试信息的输出是验证软件逻辑的关键环节。传统方式依赖物理串口,但在资源受限或接口被占用的场景下,开发者常陷入"无串口可用"的困境。本文将分享如何利用Xilinx工具链中的 XSCT命令行工具 ,通过JTAG接口实现虚拟串口功能,彻底摆脱物理串口的限制。

1. 理解jtag-uart的技术背景与价值

JTAG作为芯片级调试接口,通常仅用于程序下载和硬件调试。但Xilinx的 MicroBlaze Debug Module (MDM) 提供了将JTAG转换为虚拟串口的能力,这种技术称为jtag-uart。其核心原理是:

  • MDM模块在FPGA逻辑中实现UART协议栈
  • 处理器通过AXI或LMB总线连接MDM
  • XSCT工具建立JTAG到MDM的通信隧道
  • printf输出被重定向到JTAG接口而非物理UART

与物理串口相比,jtag-uart具有三大优势:

对比维度 物理UART jtag-uart
硬件资源占用 需要专用引脚 复用JTAG接口
连接复杂度 需外接转换器 仅需标准JTAG电缆
波特率灵活性 受硬件限制 理论无速率限制

实际项目中,当板载UART被其他外设占用或PCB设计未引出UART引脚时,jtag-uart往往成为唯一可行的调试方案。

2. 硬件环境搭建与MDM配置

以ZCU106开发板为例,配置jtag-uart需要以下准备工作:

  1. Vivado工程配置 :

    • 在Block Design中添加MicroBlaze Debug Module IP
    • 确保MDM参数中启用UART功能(默认开启)
    • 连接MDM到处理器的调试总线(AXI或LMB)
  2. 关键避坑点 :

    • MDM时钟必须与处理器调试接口同源
    • 在Zynq UltraScale+平台,需禁用PS侧的UART0/1复用
    • 检查Address Editor中MDM的基地址是否冲突
# 示例:Vivado中验证MDM连接的Tcl命令
get_bd_cells -filter {VLNV =~ "*mdm*"}
get_bd_intf_pins -of [get_bd_cells mdm_1] -filter {MODE == Slave}
  1. 生成比特流时的注意事项 :
    • 实现后需确认MDM被正确映射到调试网络
    • 建议在Vivado中运行 report_debug_cores 命令验证

3. 软件工程的关键配置步骤

在Vitis环境中,BSP配置直接影响jtag-uart的可用性。以下是经过实战验证的配置流程:

3.1 BSP参数设置

  1. 打开应用工程的Board Support Package设置
  2. 在 standalone 驱动配置中找到 stdin/stdout 选项
  3. 将设备选择为 psu_coresight_0 (而非常见的mdm_0)
  4. 保存配置并重新生成BSP

这是最易出错的环节——选择mdm_0会导致输出无法传递到JTAG接口。笔者曾因此浪费一整天排查问题。

3.2 应用代码适配

无需修改标准printf语句,但建议添加重定向检查代码:

#include <stdio.h>
#include <xil_printf.h>

int main() {
    // 验证输出通道是否就绪
    if (XST_SUCCESS != Xil_AssertSetCallback(debug_uart_assert)) {
        xil_printf("Warning: STDIO not initialized properly!\n");
    }
    
    // 正常调试输出
    printf("JTAG-UART test message\n");
    return 0;
}

4. XSCT实战操作全流程

完成软硬件准备后,通过以下步骤启动jtag-uart终端:

  1. 硬件连接:

    • 使用USB-JTAG电缆连接开发板
    • 开发板上电(注意供电稳定性)
  2. 启动XSCT会话:

    • 在Vitis菜单中选择 Xilinx Tools > XSCT Console
    • 或直接运行 xsct 命令启动独立终端
  3. 核心操作命令序列:

# 建立JTAG连接
connect

# 查看处理器状态(简写ta即targets)
ta

# 启动jtag-uart终端
jtagterminal -start

# 下载可执行文件(注意路径格式)
dow {C:/project/debug/app.elf}

# 运行程序
con

路径格式陷阱 :Windows环境下必须用 {} 包裹路径,例如:

# 正确写法
dow {D:/work/zcu106/app/Debug/app.elf}

# 错误写法(会导致下载失败)
dow D:\work\zcu106\app\Debug\app.elf
  1. 调试技巧:
    • 使用 stop 命令暂停处理器执行
    • step 可单步执行代码
    • bpadd 添加断点时建议使用函数名而非绝对地址

5. 高级调试场景与故障排除

当基础功能正常后,可尝试以下进阶应用:

5.1 多核调试配置

在Zynq UltraScale+多核系统中,需指定目标处理器:

# 列出所有可用处理器
targets -filter {name =~ "Cortex-A53*"}

# 选择特定核心
target 2
jtagterminal -start

5.2 常见问题解决方案

现象1:jtagterminal无输出

  • 检查MDM时钟是否激活
  • 确认BSP中STDIO连接的是psu_coresight_0
  • 尝试重置处理器后重新运行

现象2:输出乱码

  • 确认MDM UART波特率与软件设置匹配
  • 检查JTAG电缆连接质量(可尝试降低TCK频率)

现象3:连接不稳定

  • 更换USB端口或JTAG电缆
  • 在Vivado Hardware Manager中验证JTAG链完整性
# 诊断JTAG链的Tcl命令
open_hw
connect_hw_server
current_hw_target [get_hw_targets *]
open_hw_target
get_hw_devices

5.3 性能优化技巧

  • 在 xsct 启动时添加 -nocrc 参数可加快下载速度
  • 对于大量输出,建议在代码中控制printf频率
  • 使用 -quiet 参数减少XSCT自身日志输出

在最近的一个电机控制项目中,我们通过jtag-uart成功调试了无感FOC算法。当所有串口都被用于与上位机通信时,JTAG终端成为观察转子位置估算值的唯一窗口。特别是在紧急排查过流保护问题时,实时输出的电流采样数据帮助我们快速定位了ADC采样时序的偏差。

更多推荐