高雄市网站建设_网站建设公司_交互流畅度_seo优化
2025/12/25 9:51:56 网站建设 项目流程

启动嵌入式系统是任何 FPGA 或嵌入式 Linux 开发流程中最常做、也最关键的一步。很多时候我们依赖 SD 卡、TFTP 或 NFS,但当你无法访问板载存储或以太网时,唯一可用的方式就是 通过 JTAG 启动 Linux 镜像。

官网有一篇关于《通过JTAG在AMD XILINX SoC器件里启动Linux的方法》,核心就是通过XSCT 进行调试,本文就在官网文章基础上进一步扩展。

原文地址:

https://adaptivesupport.amd.com/s/article/000035979?language=zh_CN

PS:本文仅介绍 Zynq-7000 SoC 的应用场景。对于 Zynq-UltraScale+,应用场景类似,但面临不同的挑战。计划在另一篇文章中进行介绍,敬请期待 :)

XSCT 是什么?

XSCT,即 Xilinx Software Command-line Tool,是 Xilinx 提供的 CLI 工具,用于替代旧的 XSDB(见下图,原文:https://adaptivesupport.amd.com/s/question/0D52E00007GTvwySAD/xsct-vs-xsdb?language=zh_CN)。它安装在安装 Vivado、Vitis 或 PetaLinux 后,并支持脚本与交互式操作。主要用于管理硬件目标、下载 FPGA 或可执行文件、系统初始化等。

Xilinx 提供了相关说明文档(UG-1400),请参阅此页面:

https://docs.xilinx.com/r/en-US/ug1400-vitis-embedded/Xilinx-Software-Command-Line-Tool

硬件需求

要使用 JTAG 启动,必须满足以下条件:

  • 目标硬件必须包含可访问的 JTAG 接口

  • 使用 JTAG 调试线连接开发主机和板卡

推荐使用 Xilinx SmartLynq(支持更高频率且可远程连接)

也可使用 Platform Cable USB II 等传统线缆

步骤详解:JTAG 引导流程

1️⃣ 启动 XSCT

在命令行中运行 XSCT 可进入其交互式环境,例如:

<INSTALLATION_PATH>/Xilinx/Vitis/2021.1/bin/xsct

或者直接从【开始菜单】启动:

你将看到一个带提示符的界面,可以执行各种命令如 help、jtag 或 memory 等。

2️⃣ 连接目标

XSCT并非Xilinx提供的唯一实用程序。还有其他一些实用程序用途各异。任何实用程序都可以通过适当的调用来调用其他实用程序。XSCT和其他实用程序会调用硬件服务器来连接到JTAG套件。在XSCT中,可以通过调用connect如下命令来实现。

connect -url tcp:<DEVICE_IP>:3121

设备的 IP 地址会根据用于连接的 JTAG 套件而有所不同。

  • 使用 SmartLynq 时,服务器 IP 会显示在设备上。

  • SmartLynq 也可以通过 USB 连接,在这种情况下,可以使用10.0.0.2 版本。

  • 使用Platform Cable电缆时,可以使用127.0.0.1进行连接。

每个连接的默认端口都是3121,其他端口自行设置。

3️⃣ 查看 JTAG 设备

使用 targets 命令列出链上所有设备,例如:

xsct% targets 1 APU 2 ARM Cortex-A9 MPCore #0 (Running) 3 ARM Cortex-A9 MPCore #1 (Running) 4 xc7z020

如果连接错误或板卡电源未打开,会提示错误信息。

xsct% targets 1 whole scan chain (board power off)

最常遇到的问题与使用的 JTAG 频率有关。JTAG 链路的某些物理特性可能会影响合适的 JTAG 频率,例如电缆长度、目标数量等。在这种情况下,XSCT 工具会生成一些错误消息,指示与目标的连接不稳定。可以在下方看到一些示例。

xsct% targets 1 whole scan chain (Unknown device configuration) xsct% targets 1 whole scan chain (Unknown IR length) xsct% targets 1 whole scan chain (too many devices)

当出现此类输出时,应该重新调整 JTAG 频率,建立可靠稳定的连接。可以通过调用jtag frequency -list以下方法查找 JTAG 电缆支持的频率。然后,可以从列表中选择合适的频率。也可以选择任意频率,该实用程序会自动处理舍入误差。

xsct% jtag targets 1 xsct% jtag frequency -list 125000 250000 500000 1000000 2000000 3000000 4000000 6000000 7500000 10000000 12000000 13000000 15000000 20000000 30000000 40000000 50000000 60000000 70000000 80000000 90000000 100000000 xsct% jtag frequency 7500000 7500000 xsct% jtag frequency 7000000 7017543

4️⃣ 下载 FPGA 逻辑

通过 JTAG 下载 bitstream 至 FPGA:

xsct% targets 1 APU 2 ARM Cortex-A9 MPCore #0 (Running) 3 ARM Cortex-A9 MPCore #1 (Running) 4 xc7z020 xsct% targets 4 xsct% fpga "<PATH_TO_IMAGE>/system.bit" 00% 0MB 0.0MB/s 00:00 33% 1MB 0.9MB/s 00:01 66% 2MB 0.9MB/s 00:02 100% 3MB 0.9MB/s 00:03

这将把 PL(可编程逻辑)映像写入 FPGA 并替换现有bit。

5️⃣ 下载 FSBL(一阶段引导)

FSBL (第一阶段引导加载程序)是启动 Zynq-7000 SoC 时首先调用的程序(实际上是第二个,BootROM 首先调用) 。它负责在调用 SSBL (第二阶段引导加载程序)或所需的裸机应用程序之前配置硬件并初始化一些组件。可以使用自动生成的 FSBL,也可以编写自己的 FSBL。要下载并运行 FSBL,请运行dow命令。请注意,FSBL 必须在 Zynq 处理系统的第一个 Cortex-A9 内核上运行。因此,我们需要相应地选择目标平台。

xsct% targets -set -nocase -filter {name =~ "arm*#0"} xsct% dow "${imagesPath}/zynq_fsbl.elf" Downloading Program -- zynq_fsbl.elf section, .text: 0x00000000 - 0x0000e753 section, .handoff: 0x0000e754 - 0x0000e79f section, .init: 0x0000e7a0 - 0x0000e7ab section, .fini: 0x0000e7ac - 0x0000e7b7 section, .rodata: 0x0000e7b8 - 0x0000eacf section, .data: 0x0000ead0 - 0x000116bf section, .mmu_tbl: 0x00014000 - 0x00017fff section, .init_array: 0x00018000 - 0x00018003 section, .fini_array: 0x00018004 - 0x00018007 section, .rsa_ac: 0x00018008 - 0x0001903f section, .bss: 0x00019040 - 0x0001b29f section, .heap: 0x0001b2a0 - 0x0001d29f section, .stack: 0xffff0000 - 0xffffd3ff 100% 0MB 0.4MB/s 00:00 Setting PC to Program Start Address 0x00000000 Successfully downloaded zynq_fsbl.elf Info: ARM Cortex-A9 MPCore #0 (target 2) Stopped at 0x3ff67154 (Suspended) xsct% con; after 5000; stop Info: ARM Cortex-A9 MPCore #0 (target 2) Running Info: ARM Cortex-A9 MPCore #0 (target 2) Stopped at 0xfaf0 (Suspended)

该dow命令负责将指定的二进制可执行文件下载到目标设备,并将程序计数器设置为其入口点。设置程序计数器后,CPU 会立即停止。为了使 FSBL 完成其操作,应该让它运行几秒钟,然后手动停止。这样做是为了使硬件为即将到来的 JTAG 启动做好准备。

  • 在 FSBL 下载到目标系统之前,必须禁用内存管理单元 (MMU),因为它会虚拟化内存访问并阻止对内存的直接读写操作。如果目标系统正在运行任何 Linux 镜像,请在启动前中断该镜像。否则,将无法下载和运行 FSBL。

  • FSBL 根据启动引脚配置完成其操作。如果启动引脚可调,请将其调整为 JTAG 启动模式。我的情况是,启动引脚是固定的,我不得不通过修改 FSBL 的源代码来强制其进入 JTAG 启动模式。

6️⃣ 初始化处理系统

使用 Xilinx Vivado 生成的硬件平台镜像不仅包含 BIT 文件,还包含一个 Tcl 脚本,可用于初始化硬件。运行 FSBL 后,我们需要配置其余硬件以访问外设、内存、I/O 引脚等。导出的 XSA 文件包含以下文件:

$> cd hw-description && ls -l ... system.bit ... ps7_init.c ... ps7_init.h ... ps7_init.tcl <The rest is stripped>

要初始化硬件,我们必须调用ps7_init.tcl文件中提供的初始化方法。请按如下方式操作。如果没有输出,则表示初始化成功。

xsct% targets 1 APU 2* ARM Cortex-A9 MPCore #0 (Suspended) 3 ARM Cortex-A9 MPCore #1 (Running) 4 xc7z020 xsct% targets 1 xsct% source ps7_init.tcl xsct% ps7_init

如果你查看 Tcl 文件,你会看到它是如何逐步初始化硬件的。这或许能让你深入了解 SoC 中各个组件之间的关联方式。

proc ps7_init {} { variable PCW_SILICON_VER_1_0 variable PCW_SILICON_VER_2_0 variable PCW_SILICON_VER_3_0 set sil_ver [ps_version] if { $sil_ver == $PCW_SILICON_VER_1_0} { ps7_mio_init_data_1_0 ps7_pll_init_data_1_0 ps7_clock_init_data_1_0 ps7_ddr_init_data_1_0 ps7_peripherals_init_data_1_0 puts "PCW Silicon Version : 1.0" } elseif { $sil_ver == $PCW_SILICON_VER_2_0 } { ps7_mio_init_data_2_0 ps7_pll_init_data_2_0 ps7_clock_init_data_2_0 ps7_ddr_init_data_2_0 ps7_peripherals_init_data_2_0 puts "PCW Silicon Version : 2.0" } else { ps7_mio_init_data_3_0 ps7_pll_init_data_3_0 ps7_clock_init_data_3_0 ps7_ddr_init_data_3_0 ps7_peripherals_init_data_3_0 puts "PCW Silicon Version : 3.0" } }

该脚本负责 DDR、PLL、时钟、IO 等硬件初始化。

7️⃣ 下载设备树文件(U-Boot 使用)

设备树二进制文件是 U-Boot 的必要组成部分。如果没有它,就像 Linux 内核一样,U-Boot 将无法识别芯片内外的设备。通过使用设备树二进制文件,U-Boot 可以将匹配的驱动程序绑定到受支持的硬件目标/组件。

要将设备树二进制文件下载到 DDR 内存上的预定地址,我们将再次使用dow命令。请参见下文。

xsct% targets -set -nocase -filter {name =~ "arm*#0"} xsct% set deviceTreeOffset 0x100000 xsct% dow -data "system.dtb" ${deviceTreeOffset} 100% 0MB 0.4MB/s 00:00 Successfully downloaded system.dtb

此-data选项为必填项,因为给定的文件并非常规的 ELF 二进制文件。它应该只下载到主内存,而不能下载到其他地方。

设备树的偏移量在编译期间被硬编码到 U-Boot 中。对于 Petalinux 项目,可以在项目配置文件中找到它<PLNX_PRJ_PATH>/project-spec/configs/config。相应的配置标签是<tag> CONFIG_SUBSYSTEM_UBOOT_DEVICETREE_OFFSET。下面是一个可用于从配置文件中提取该信息的 bash 脚本。

DEVICE_TREE_OFFSET="$(grep "CONFIG_SUBSYSTEM_UBOOT_DEVICETREE_OFFSET" "<PLNX_PRJ_PATH>/project-spec/configs/config" | cut -d'=' -f 2)" echo ${DEVICE_TREE_OFFSET}

8️⃣ 下载第二阶段引导(U-Boot)

与 FSBL 类似,U-Boot 也是一种引导加载程序,但它更复杂。它代表第二阶段引导加载程序。我们已经满足了启动 U-Boot 的先决条件。将其下载到主内存并从入口点释放 CPU 后,就可以在串口终端上看到一些输出。

xsct% targets -set -nocase -filter {name =~ "arm*#0"} xsct% dow "u-boot.elf" Downloading Program -- u-boot.elf section, .text: 0x04000000 - 0x040003a7 section, .efi_runtime: 0x040003a8 - 0x040011ef section, .text_rest: 0x04001200 - 0x0409dbff section, .rodata: 0x0409dc00 - 0x040c0ea8 section, .hash: 0x040c0eac - 0x040c0ec3 section, .data: 0x040c0ec8 - 0x040cc4cf section, .got.plt: 0x040cc4d0 - 0x040cc4db section, .u_boot_list: 0x040cc4dc - 0x040ce30f section, .efi_runtime_rel: 0x040ce310 - 0x040ce3df section, .rel.dyn: 0x040ce3e0 - 0x040e22e7 section, .bss_start: 0x040ce3e0 - 0x040ce3df section, .bss: 0x040ce3e0 - 0x040e1397 section, .bss_end: 0x040e1398 - 0x040e1397 100% 0MB 0.4MB/s 00:02 Setting PC to Program Start Address 0x04000000 Successfully downloaded u-boot.elf xsct% con Info: ARM Cortex-A9 MPCore #0 (target 2) Running

调用释放已停止 CPU 的命令后con,如果正确配置了硬件镜像,将立即在串口终端上看到 U-Boot 的输出。请注意,Zynq-7000 SoC 有两个 UART 接口连接到处理系统。应该仔细选择要用于交互的端口。我的终端屏幕显示如下输出。

U-Boot 2021.01 (Jun 01 2021 - 11:54:06 +0000) CPU: Zynq 7z020 Silicon: v3.1 DRAM: ECC disabled 1 GiB Flash: 0 Bytes NAND: 0 MiB MMC: mmc@e0101000: 0 Loading Environment from SPIFlash... SF: Detected s25fl256s1 with page size 256 Bytes, erase size 64 KiB, total 32 MiB *** Warning - bad CRC, using default environment In: serial@e0000000 Out: serial@e0000000 Err: serial@e0000000 Net: ZYNQ GEM: e000b000, mdio bus e000b000, phyaddr -1, interface rgmii-id eth0: ethernet@e000b000 Hit any key to stop autoboot: 0 Zynq >

9️⃣ 下载并启动 Linux Kernel

本教程的最后一步是将 Linux 内核镜像下载到 DDR 内存中,并通过 U-Boot 启动。U-Boot 启动成功后,可以通过多种方式启动 Linux 内核,例如 JTAG、TFTP、QSPI、eMMC 等。本文将以 JTAG 启动为例进行说明。某些方法可能不适用,具体取决于具体硬件配置。

请注意,Linux 内核需要设备树二进制文件和可挂载的根文件系统才能完成启动过程。为了快速演示,我准备了一个 INITRAMFS 镜像,并使用 PetaLinux 工具将内核、根文件系统和设备树二进制文件打包到一个镜像文件中。也可以根据需要选择其他方法。

用于下载镜像的地址存在一些限制。

  • 必须将镜像放入 DDR 的空白区域。

  • 它不能损坏内存中已有的任何其他镜像。如果创建了一个 PetaLinux 项目,可以在配置文件中找到带有<path>标签的相应地址CONFIG_SUBSYSTEM_UBOOT_FIT_IMAGE_OFFSET。

  • 它必须与 U-Boot 可执行文件的对齐方式相匹配。

xsct% targets 1 APU 2* ARM Cortex-A9 MPCore #0 (Running) 3 ARM Cortex-A9 MPCore #1 (Running) 4 xc7z020 xsct% stop Info: ARM Cortex-A9 MPCore #0 (target 2) Stopped at 0x3ff67154 (Suspended) xsct% dow -data "image.ub" 0x10000000 100% 104MB 0.4MB/s 04:49 Successfully downloaded image.ub xsct% con

由于打包后的内核文件较大,通过 JTAG 传输需要一些时间。下载完成后,我们可以释放 CPU。其余操作将在 U-Boot 终端上完成。如果一切顺利,可以通过运行命令并传入bootm下载的内核镜像地址来轻松启动 Linux 镜像。以下是我的 Linux 镜像成功启动的输出。

Zynq> bootm 0x10000000 ## Loading kernel from FIT Image at 10000000 ... Using 'conf-system-top.dtb' configuration Verifying Hash Integrity ... OK Trying 'kernel-1' kernel subimage Description: Linux kernel Type: Kernel Image Compression: uncompressed Data Start: 0x100000f8 Data Size: 56678904 Bytes = 54.1 MiB Architecture: ARM OS: Linux Load Address: 0x00200000 Entry Point: 0x00200000 Hash algo: sha256 Hash value: a6b9da747c32596a2818145ac499b124900effba9552aa23483fe758574c1003 Verifying Hash Integrity ... sha256+ OK ## Loading ramdisk from FIT Image at 10000000 ... Using 'conf-system-top.dtb' configuration Verifying Hash Integrity ... OK Trying 'ramdisk-1' ramdisk subimage Description: petalinux-image-minimal Type: RAMDisk Image Compression: uncompressed Data Start: 0x13612bb4 Data Size: 52367968 Bytes = 49.9 MiB Architecture: ARM OS: Linux Load Address: unavailable Entry Point: unavailable Hash algo: sha256 Hash value: d77edbad8b69e33e1885c32edbc89c9e8085028a44593a8e5ece09c0b356a797 Verifying Hash Integrity ... sha256+ OK ## Loading fdt from FIT Image at 10000000 ... Using 'conf-system-top.dtb' configuration Verifying Hash Integrity ... OK Trying 'fdt-system-top.dtb' fdt subimage Description: Flattened Device Tree blob Type: Flat Device Tree Compression: uncompressed Data Start: 0x1360dbfc Data Size: 20202 Bytes = 19.7 KiB Architecture: ARM Hash algo: sha256 Hash value: f440bd81389f4e984d78d8baba23f93118ce9562bfcce6c47a741b1ef01cb238 Verifying Hash Integrity ... sha256+ OK Booting using the fdt blob at 0x1360dbfc Loading Kernel Image Loading Ramdisk to 2ce0e000, end 2ffff260 ... OK Loading Device Tree to 2ce06000, end 2ce0dee9 ... OK Starting kernel ... Booting Linux on physical CPU 0x0 Linux version 5.10.0-xilinx-v2021.1 (oe-user@oe-host) (arm-xilinx-linux-gnueabi-gcc (GCC) 10.2.0, GNU ld (GNU Binutils) 2.35.1) #1 SMP PREEMPT Fri Jun 4 15:57:16 UTC 2021 CPU: ARMv7 Processor [413fc090] revision 0 (ARMv7), cr=18c5387d ............... <Skipped for readability> ............... PetaLinux 2021.1 ZynqLinux ttyPS0 root@ZynqLinux:~ > uname -r 5.10.0-xilinx-v2021.1

总结

虽然 JTAG 启动的方式比较复杂,但绝对值得付出努力。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询