使用系统控制台调试 FPGA 硬件
本教程向您展示了如何使用系统控制台调试工具将编译好的 FPGA 设计编程到 FPGA 器件中,然后访问在该 FPGA 设计中实例化的硬件模块(即外设)。
概述
本教程向您展示了如何使用系统控制台调试工具将编译好的 FPGA 设计编程到 FPGA 器件中,然后访问在该 FPGA 设计中实例化的硬件模块(即外设)。本系统控制台教程基于“构建自定义硬件系统”教程中创建的 FPGA 设计。在该教程中,您将创建此 Qsys 系统。
在本教程中,您将通过连接到 FPGA 的 JTAG 电缆与 Qsys 系统进行交互,通过 JTAG 主组件发送读写事务,以与连接到它的从属外设进行交互。
材质
硬件
- Windows* 或 Linux* 开发主机 PC
- Intel® Cyclone® 10 LP FPGA 评估套件
- USB Type A 转 Mini-B 数据线
软件
-
已安装 Intel® Quartus® Prime 软件套件。可以是 Lite 版或 Standard 版,但不能是 Pro 版。这已在“如何编程您的第一个 FPGA”教程中完成。
-
已完成的 Quartus 项目,来自“构建自定义硬件系统”教程。如果您尚未完成该教程,应立即返回并完成它。
第一步:准备电路板
本节介绍如何准备 Intel® Cyclone® 10 LP FPGA 电路板以用于本教程。
-
将 mini USB 数据线插入电路板的 USB 连接器。然后将 USB 数据线的另一端插入您的主机 PC。
-
确保 DIP 开关 S1-4 (BYPASS) 处于图 2 所示的默认“OFF”位置。这通过 USB 启用电路板的 JTAG 连接。其他 3 个开关是通用的用户输入,可以处于任何状态。
第二步:开始使用系统控制台
本节介绍如何使用系统控制台将 FPGA 设计下载到 FPGA 器件,然后通过 Qsys 系统中的 JTAG 主 IP 核进行交互,以便读写连接的外设。它还演示了系统控制台提供的 JTAG 链路调试和 Qsys 系统运行状况的可视化。
- 启动 Intel® Quartus® 软件,并通过选择“文件”>“打开项目”,导航到您的项目文件夹,然后选择 `blink.qpf` 文件来打开您在“构建自定义硬件系统”教程中创建的 **blink** 项目。
- 从“工具”>“系统调试工具”>“系统控制台”菜单启动系统控制台。图 3:系统控制台菜单
- 系统控制台工具会查找连接到 JTAG 电缆的设备。要列出可用设备,请找到系统控制台窗口右下角的 **TCL 控制台**窗格,然后键入以下命令,然后按 Enter 键。
get_service_paths device
图 4:系统控制台的 TCL 控制台 - 您可以使用选项卡完成功能在键入命令时完成命令,甚至可以显示您键入的命令前缀可能完成的所有命令。例如,在命令行上键入 **get**,然后按 **TAB**,将显示所有以 **get** 开头的命令的弹出列表。您可以使用键盘上的向上和向下箭头在列表中上下滚动以选择其中一个命令。按 **Enter** 从弹出菜单中选择命令。图 5:按 Tab 键之前的命令行图 6:按 Tab 键之后的命令行
您还可以使用键盘上的向上和向下箭头在 TCL 控制台历史缓冲区中向后和向前滚动,从而轻松调用以前执行过的命令。
- 所有命令都可以通过传入 **help** 命令来获得帮助。在 tcl 提示符下键入
help get_service_paths
图 7:获取命令帮助键入 `help help` 以查看命令列表。
第三步:编程 FPGA
-
要对 FPGA 器件进行编程,我们首先需要获得器件的服务路径。我们将把该路径分配给一个名为 `d_path` 的变量,方法是键入以下命令。
set d_path [lindex [get_service_paths device] 0 ]
-
通过键入以下命令将 SOF 文件下载到器件。
device_download_sof $d_path output_files/blink.sof
当上述命令完成后,琥珀色的 D5 **CONFIG** LED 应该会亮起。
第四步:使用 JTAG 调试服务
利用 JTAG 主组件提供的 JTAG DEBUG 服务路径。
-
找到 JTAG 主的 JTAG DEBUG 服务路径,并将其存储在一个名为 `jd_path` 的新变量中,方法是键入以下命令。
set jd_path [lindex [get_service_paths jtag_debug] 0]
-
通过在系统级调试节点 (SLD) 的 tdi 和 tdo 之间通过循环发送一组值来利用 JTAG 接口。此命令会检查电路板的物理接口以及 FPGA 器件的 JTAG TAP 控制器引脚。键入以下命令并观察返回的值。
jtag_debug_loop $jd_path [list 1 2 4 8 15 16]
-
检查连接到 Qsys 系统中 JTAG 主组件的时钟。此命令会检测时钟是否处于活动状态,如果处于活动状态则返回 1,否则返回 0。键入以下命令。
jtag_debug_sense_clock $jd_path
-
对连接到 Qsys 系统中 JTAG 主组件的时钟的“状态”进行采样。重复采样时钟,直到捕获到其高电平 (1) 和低电平 (0) 状态。键入以下命令并按 Enter 键以观察时钟状态。通过按向上箭头然后按 Enter 重复命令。
jtag_debug_sample_clock $jd_path
-
对连接到 Qsys 系统中 JTAG 主组件的复位信号进行采样。电路板上的 S3 按钮连接到 Qsys 系统的复位输入(低电平有效)。要对复位信号进行采样,请键入以下命令。
jtag_debug_sample_reset $jd_path
-
要查看复位信号的变化,请按住 S3 按钮并重新采样复位,然后释放 S3 按钮并重新采样复位。
第五步:使用 JTAG 主服务
接下来,我们将利用 JTAG 主提供的服务路径。这将需要我们回顾上一个“构建自定义硬件系统”教程中生成的地址映射。请记住,我们在该教程中使用了 **sopc-create-header-files** 来创建 `master_0.h` 头文件,然后转储了该文件中的基地址宏。为了让您回忆起来,这些地址如下。
# define OCRAM_64K_BASE 0x0 # define LED PIO BASE 0x10000 # define BUTTON PIO BASE 0x10010 # define SWITCH_PIO_BASE 0x10020 # define SYSTEM_ID_BASE 0x10030
-
首先,设置几个 TCL 变量,以便在剩余的本教程中更轻松地调用这些基地址。执行以下每个命令来设置这些变量。
set ocram 0x0 set led 0x10000 set button 0x10010 set switch 0x10020 set sysid 0x10030
-
要与设备中的外设通信,我们将使用“master”服务。找到 JTAG 主组件的服务路径,并将其保存到 tcl 变量 `m_path` 中,方法是键入以下命令。
set m_path [lindex [get_service_paths master] 0 ]
声明主服务路径,以便我们能够与 JTAG 主组件进行交互,并将其保存到 tcl 变量 `c_path` 中,方法是键入以下命令。
set c_path [claim_service master $m_path ""]
-
现在我们已经可以向 JTAG 主发送命令了,让我们通过从片上 RAM 的基地址读取单个字来与之交互。键入以下命令并按 Enter 键。
master_read_32 $c_path $ocram 1
现在通过键入以下命令并按 Enter 键将一个字写入基地址。
master_write_32 $c_path $ocram 0x1234de10
最后,让我们通过再次读取片上 RAM 来验证该字是否已写入。
master_read_32 $c_path $ocram 1
-
接下来,我们将使用 JTAG 主与 LED PIO 组件进行交互。首先,通过键入以下命令并按 Enter 键来点亮一半的 LED。
master_write_32 $c_path $led 0x55
现在,关闭那些 LED,然后点亮另一半,方法是键入以下命令。
master_write_32 $c_path $led 0xaa
现在可以创建一个循环,每半秒闪烁 LED0 和 LED1 10 次,方法是键入以下命令(或粘贴到 Tcl 控制台中)。
set COUNT 0 while {$COUNT < 10} { master_write_32 $c_path $led 0x01 after 500 master_write_32 $c_path $led 0x02 after 500 set COUNT [expr $COUNT + 1] }
最后,使用以下命令关闭所有用户 LED。
master_write_32 $c_path $led 0xff
-
利用 JTAG DEBUG 服务的复位功能。现在我们已经点亮了一些 LED,让我们看一下 JTAG 主组件提供的另一个 JTAG DEBUG 服务。我们可以断言由 JTAG 主组件连接到 Qsys 系统的复位信号。为此,我们使用以下命令。
jtag_debug_reset_system $jd_path
执行该命令后,所有 LED 应该都会亮起,恢复到其复位状态。您可以通过按下 S3 按钮触发相同的复位效果,就像我们之前做的那样。再次关闭一些 LED,然后尝试按下 S3 来证明这一点。
-
通过读取 S4 按钮的状态来与按钮 PIO 组件进行交互。
首先,在按下按钮之前读取它,使用以下命令。
master_read_32 $c_path $button 1
接下来,按住 S4 并重复该命令。
-
与开关 PIO 组件进行交互。DIP 开关 SW1 中有 4 个滑动开关,但只有 3 个用于 GPIO。我们将使用 SW1-1 到 SW1-3;避免更改 SW1-4,因为它会导致设备 JTAG 链路被旁路。
首先,将 SW1-1 到 SW1-3 设置为 ON 位置,然后读取开关,使用以下命令。
master_read_32 $c_path $switch 1
现在,逐个将 SW1-3 到 SW1-1 设置为 OFF 位置,然后再次读取开关。
-
与系统 ID 组件进行交互。该组件包含两个 32 位字。第一个字是我们在此教程的先前硬件部分中设置为 0xde10de10 的 ID 值,第二个字表示生成 Qsys 系统时的 Unix 秒时间值。
master_read_32 $c_path $sysid 2
-
利用默认的从属外设。在这里,我们将演示读取和写入未映射地址时会发生什么。
我们的外设被映射到地址 0x0000_0000 到 0x0001_0038。通过读取该范围之外的地址,我们将从默认从属外设(在设备配置时初始化为 0x0000_0000)读取。通过以下命令从未映射的地址读取。
master_read_32 $c_path 0x01000000 4
读取操作应返回以下数据。
0x00000000 0x00000000 0x00000000 0x00000000
让我们用特定的递增模式向同一地址写入 4 个字。
master_write_32 $c_path 0x01000000 [list 0x0badf00d 0x1badf00d 0x2badf00d 0x3badf00d]
现在验证该模式每 4 个字重复一次。
master_read_32 $c_path 0x01000000 8
读取操作应返回如下所示的数据。
0x0badf00d 0x1badf00d 0x2badf00d 0x3badf00d 0x0badf00d 0x1badf00d 0x2badf00d 0x3badf00d
让我们写入一个没有写入接口的从属设备,例如系统 ID 外设。该写入操作不会被系统中的任何从属设备解码,而是会被定向到默认从属设备。
master_write_32 $c_path $sysid 0xfacecafe
现在验证此写入操作是否已发送到默认从属设备。
master_read_32 $c_path 0x01000000 4
读取操作应返回如下所示的数据。由于只写入了一个字 (0xfacecafe),因此只有默认从属设备的第一字被更改。
0xfacecafe 0x1badf00d 0x2badf00d 0x3badf00d
-
通过键入以下命令关闭主服务。
close_service master $c_path
这样,您就使用系统控制台调试和测试了 FPGA 硬件系统。
正如您所见,系统控制台对于 IP 核的低级、脚本化或交互式测试和调试非常有用。在本练习中,我们通过 JTAG 链路与设备通信,但您也可以使用其他通信通道,例如 TCP/IP,这使得该工具也可用于远程调试。有关使用系统控制台的更多详细信息,请在此处查看专门的网页 这里。