跳到主要内容 FPGA 工程实战经验:板级调试与 Qsys 系统搭建 | 极客日志
C
FPGA 工程实战经验:板级调试与 Qsys 系统搭建 FPGA 项目的板级调试方法及基于 Nios II 软核处理器的 Qsys 系统搭建流程。内容包括使用 Quartus II 工具进行内存内容编辑与验证,通过 Qsys 添加 System ID、JTAG UART、PIO、RAM 及 Timer 等外设并配置连接。随后在 EDS 环境中创建 C 语言工程,编写 LED 闪烁控制程序,完成软硬件联调。
内存管理 发布于 2026/3/21 更新于 2026/4/18 1 浏览4.6 板级调试
①打开对应工程文件夹。
②执行 Quartus II 菜单栏 Tools→In-System Memory Content Editor 命令,在界面的右侧选择 vip.sof 文件,执行下载操作,即单击 File 右侧的小按钮。
③下载完成后可以看到 VIP 板上的指示灯 D1 闪烁。此时我们接着选中 Index 下面的 Memory 项,然后单击'循环读取'按钮。
④接着我们可以观察 Memory 当前的数据变化。如图 4-28 所示,矩形框起来的高字节数据,即我们每隔一秒多统一递增一次的数据,而其后的低字节数据则始终是从 0 开始递增和地址一一对应的递增数据。因此,我们看到的实验结果是,这个 onchip RAM 的所有 16bit 的高字节每隔一秒都会递增一,而其后的数据则一直保持当前状态不变。
第 5 章 工程实例 3——Qsys 系统搭建与软件开发
本章导读
同样是一个最简单的 LED 指示灯闪烁控制系统,但本章的工程是基于 Nios II 软核处理器来实现的。因此,本章的重点是引导读者使用 Quartus II 中集成的 Qsys 开发平台搭建一个基本的硬件系统,并且在此系统上配合软件开发环境 Eclipse 实现软件开发。
5.1 功能概述
如图 5-1 所示,本实例使用 Quartus II 的 Qsys 构建一个片上系统,该系统使用 NIOS II 处理器,其代码和数据都存储在 40KB 的片内 RAM 中。此外,还有一些常见外设,如 System ID、JTAG UART、LED PIO 和 Timer(定时器)。JTAG UART 使用 PC 和 VIP 核心板之间的 JTAG 连接进行数据传输,这在系统调试中非常实用。
本实例搭建好一个最基本的嵌入式处理器硬件平台后,将编写一个最简单的 LED 闪烁的软件程序,该程序运行在 NIOS II 处理器上。
本实例的软件流程图如图 5-2 所示。程序运行后,首先进入后台,初始化相关外设,这个步骤在我们编写的应用软件上是看不到的。接着通过 JTAG UART 在 EDS(NIOS II 处理器的软件开发工具)上打印字符串,最后进入 while 循环中进行 LED 指示灯闪烁控制。
5.2 Qsys 系统搭建
前面两个实验中我们只使用了 FPGA 内部的逻辑,没有任何嵌入式处理器的参与,本实例将充分发挥 FPGA 的灵活性,搭建一个片上系统,然后在它的 NIOS II 处理器上运行一个简单的小程序。
微信扫一扫,关注极客日志 微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
相关免费在线工具 Base64 字符串编码/解码 将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
Base64 文件转换器 将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
Markdown转HTML 将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online
HTML转Markdown 将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online
JSON 压缩 通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online
JSON美化和格式化 将JSON字符串修饰为友好的可读格式。 在线工具,JSON美化和格式化在线工具,online
如图 5-1 的功能框图所示,在这个系统中,NIOS II 处理器上不仅挂了个 40KB 的片内 RAM 用于运行程序,而且作为主机连接到系统总线上,它上面挂了 3 个外设:System ID 用于系统标识;JTAG UART 用于系统调试;PIO 连接 LED 指示灯,本实例就是要在这个系统上运行 LED 闪烁控制。(虽然已经到第 3 个例程了,还在玩 LED 闪烁控制,但这是最基础的实例,大家重在学习系统的搭建和工具的使用。)
如图 5-3 所示,在 Quartus II 中执行 Tools→Qsys 命令或单击快捷按钮启动 Qsys。
Qsys 界面窗口的布局如图 5-4 所示,相比于前一代的片上系统工具 SOPC Builder,Qsys 拥有更多的个性化编辑和设置选项。
如图 5-5 所示,初次打开 Qsys,System Content 中默认已经添加了一个孤零零的 CLOCK 组件,其他什么也没有,这只是个摆设,什么也干不了。于是,我们要在 Component Library 中查找并添加几个常用组件,如 NIOS II 处理器、JTAG UART、PIO、system ID 和 40KB 的片内 RAM。
如图 5-6 所示,在 Qsys 界面左侧的 Library 面板中,单击 Peripherals→Debug and Performance,双击 System ID Peripheral,以便添加 System ID 外设。
此时弹出如图 5-7 所示的'System ID Peripheral'组件对话框。这里只有一个可以设定的参数,即'Parameters→32 bit System ID',这个 ID 可以随意设置,代表你这个系统的唯一识别号,没有什么特殊含义,一般采用默认的 ID 号'0'也可以。单击 Finish 按钮后该组件则被添加到系统中。
如图 5-8 所示,在 Qsys 界面左侧的 Library 面板中,单击 Peripherals→Microcontroller Peripherals,双击 PIO(Parallel I/O),以便添加 PIO 外设。
此时弹出如图 5-9 所示的'PIO(Parallel I/O)'组件对话框。虽然这里可以设置的参数有不少,但是我们当前只需要关心'Basic Settings'。
·在'Width(1-32bits)'后面的文本框中可以输入 1~32 的数值,表示当前 PIO 的位宽。
·'Direction'后面有多个选项,表示 PIO 的方向,这里选择'Output',即输出。
·在'Output Port Reset Value'后面的文本框中输入 PIO 的初始值,默认为'0x0000000000000000'。
完成设置后,单击 Finish 按钮后该组件则被添加到系统中。
如图 5-10 所示,在 Qsys 界面左侧的 Library 面板中,单击 Interface Protocols→Serial,双击 JTAG UART,以便添加 JTAG UART 外设。
此时弹出如图 5-11 所示的'JTAG UART'组件对话框。JTAG UART,顾名思义,它是一个通过 JTAG 进行数据传输的串行外设。该外设可以设定内部用于缓存收发数据的 FIFO 深度,通常使用默认设置即可。单击 Finish 按钮后该组件则被添加到系统中。
如图 5-12 所示,在 Qsys 界面左侧的 Library 面板中,单击 Memories and Memory Controllers→On-Chip,双击 On-Chip Memory(RAM or ROM),以便添加片内 RAM。
此时弹出如图 5-13 所示的'On-Chip Memory(RAM or ROM)'组件对话框。这里我们配置一个 RAM。
·在 Memory type 窗口中 Type 右侧的下拉列表框中选择'RAM(Writable)'项,其他项选择默认或按如图 5-13 所示参数进行设置即可。
·在 Size 窗口中 Data width 右侧的下拉列表框中选择'32',即 RAM 位宽为 32,和 NIOS II 处理器匹配。
·在 Size 窗口中 Total memory size 右侧的文本框中输入'40000',即 RAM 的存储量大小约为 40KB。
其他选项使用默认设置,无需更改。单击 Finish 按钮后该组件则被添加到系统中。
如图 5-14 所示,在 Qsys 界面左侧的 Library 面板中,单击 Peripherals→Microcontroller Peripherals,双击 Interval Timer,以便添加 Timer 外设。
此时弹出如图 5-15 所示的'Interval Timer'组件对话框。
·单击选择面板右侧的 Presets→Library→Full-featured。
·'Timeout period'下设置'Period'和'Units'分别为'1'和'ms',表示定时器定时周期为固定的 1ms。
·'Timer counter size'设定为 32。
单击 Finish 按钮后该组件则被添加到系统中。
如图 5-16 所示,在 Qsys 界面左侧的 Library 面板中,单击 Embedded Processors,双击 Nios II Processor,以便添加 NIOS II 处理器外设。
此时弹出如图 5-17 所示的'Nios II Processor'对话框,在'Core Nios II'选项卡中做一些设置。
·在'Select a Nios II Core→Nios II Core'右侧选择单选按钮'Nios II/f',其中,'Nios II/e'表示 economic,是性能较低的处理器,该模式下大多数的可配置选项都向设计者关闭,毕竟它的目标是'经济';'Nios II/s'表示 standard,是性能居中的处理器;'Nios II/f'表示 fast,是性能最好的处理器,并且在该处理器模式下,IP 核开启了几乎所有可配置的选项,从而使设计者可以根据自己的性能需求随意配置。
·在'Hardware Arithmetic Operation→Hardware multiplication type'右侧的下拉列表框中选择乘法器,以便实现使用'Embedded Multipliers'。
将'Core Nios II'选项卡右侧的下拉框向下拉,接着按如图 5-18 所示参数进行设置。
·在'Reset Vector→Reset vector memory'右侧选择我们已经添加的 RAM 组件'onchip_mem_s1'。
·'Reset Vector→Reset vector offset'默认为 0x00000000。
·'Reset Vector→Reset vector'默认为 0x00010000。
·在'Exception Vector→Exception vector memory'右侧选择已经添加的 RAM 组件'onchip_mem_s1'。
·'Exception Vector→Exception vector offset'默认为 0x00000020。
·'Exception Vector→Exception vector'默认为 0x00010020。
其他选项都使用默认设置,若想做高级的 DIY 设定,推荐参考 Altera 提供的丰富的文档。
Reset vector,即复位向量。这里指定的 Reset vector memory 是存储软件代码的地方,通常是一颗非易失的存储器,如 ROM、Flash 等。这里指定为片内 RAM,也是没有问题的,因为这个 RAM 实际上可以指定初始化代码,在 FPGA 上电从外部 SPI Flash 加载时一起被加载好。
Exception vector,即执行向量。这里指定的 Exception vector memory 是软件程序执行的地方。通常情况下,处理器在上电初始化后首先会到 Reset vector memory 将代码'搬运'到 Exception vector memory 中,然后从 Exception vector memory 开始运行代码程序。我们也指定为片内 RAM。
接下来我们需要在 System Contents 的 Connections 一列中设置一些连接,将之前添加的一些分立的外设或 NIOS II 处理器连接在一起,构成一个真正的系统。还未连接好的系统如图 5-19 所示。
将鼠标指针放置在 Connections 列时,就会显示很多空心的小圆圈,点击这些空心点就会变成实心点,实心代表已连接。系统的连接其实也非常简单,我们的时钟 clk 和复位 reset 都没有做太复杂,都是 clk_0 组件输出,因此将所有组件的时钟和复位信号分别与 clk_0 的时钟和复位信号连接上即可;NIOS II 处理器的数据存储器和代码存储器都必须由片内 RAM 来担当,因此 nios2_qsys_0 的 data_master 和 instruction_master 均与代表 onchip_memory2_0 的从机总线 s1 连接。而其他作为总线 slave 的外设均连接到 nios2_qsys_0 的 data_master 上即可。
另外,要说明的是,作为系统与外部连接的接口需要特别设置一下。如图 5-21 所示,选择并双击 Export 列为'*_external_connection'后缀的信号,随后该信号接口所对应的 Connections 列中会出现一个 export 的图标,表示该信号将被引出到该系统的顶层接口,用于外部信号的连接。
在 Name 一列,我们可以选中每个外设,然后单击右键,选择 Rename,对它们的名称进行修改,如图 5-22 所示。
至此,一个漂亮的测试系统搭建完毕,后面的事情包括分配地址、中断优先级等。对于地址,一般无需手动设定,Qsys 会自动分配。有时还可以根据系统需要调整一下中断优先级,如图 5-23 所示。
·单击菜单栏 System→Assign Base Addresses 完成地址的自动分配。
·单击菜单栏 System→Assign Interrupt Numbers 完成中断优先级的自动分配。
很多外设都有中断信号,在我们的 Qsys 中也需要将对应的 IRQ 一列中的外设和 NIOS II 处理器连接上。在没有连接时,对应外设上有一个空心的小点,如果点击,则不是实心的小圆,而是可以填写数字的一个空心大圆,如图 5-24 所示,其对应的数字就是它的中断优先级。
System Contents 选项卡的右侧是 Address Map,如图 5-25 所示,其中的地址一目了然,对于不同的 Master 可以有不同的地址空间映射。
如图 5-26 所示,Project Settings 选项卡列出了系统的一些基本信息,如器件系列和具体型号、连接方式和系统 ID。
完成系统搭建后,如图 5-27 所示,在菜单栏上执行 Generate→Generate 命令则会生成刚刚创建并连接好的新系统。
如图 5-28 所示,在弹出的 Generation 对话框中,单击右下角的 Generate 按钮则生成系统。
·'Simulation'一栏设置是否生成供仿真的系统模型。
·'Testbench System'一栏设置是否生成对当前系统进行仿真的测试脚本。
·'Synthesis'一栏设置生成用于 Quartus II 工程进行综合的相关 HDL 代码。
·'Output Directory'一栏设置系统文件生成的存放路径。
当第一次单击 Generate 按钮时,会弹出提示询问是否保存当前系统,选择 Yes,然后弹出保存路径和命名,可以命名为 myqsys,然后保存。本实例完成系统生成后如图 5-29 所示。
如图 5-30 所示,在菜单栏上执行 Generate→HDL Example 命令,此时将弹出当前系统的例化模板,如图 5-31 所示,复制这个模板的脚本,可以在自己的工程中集成这个系统。
回到 Quartus II 中,先执行菜单栏的 Assignments→Setting 命令,选择 Files,弹出界面如图 5-32 所示,然后单击右侧的文件选择按钮,将刚刚生成的 vip_qsys.qsys 文件添加到工程中。
接下来在工程顶层文件中例化 vip_qsys 系统即可。
5.3 Verilog 代码解析 本实例工程代码的主要层次结构如图 5-33 所示。
·vip.v 是顶层模块,其中例化了两个模块,即 sys_ctrl.v 子模块和 vip_qsys.v 系统子模块。该模块仅仅用于子模块间的接口连接,以及连接到 FPGA 外部接口的定义,该模块中未作任何的逻辑处理。
·sys_ctrl.v 子模块中例化了 PLL 模块,并且对输入 PLL 的复位信号以及 PLL 锁定后的复位信号进行'异步复位,同步释放'处理,确保系统的复位信号稳定可靠。
·vip_qsys.v 模块则是 Qsys 系统的例化,该模块例化了一个 NIOS II 处理器,作为 Avalon-MM 总线的主机;Avalon-MM 总线上可访问的从机有片内 RAM、System ID、JTAG UART、PIO 和 Timer 等外设。
//VIP 工程顶层模块
module vip(
ext_clk,ext_rst_n,
led
);
//外部输入时钟和复位接口
input ext_clk; //外部 25MHz 输入时钟
input ext_rst_n; //外部低电平复位信号输入
//LED 指示灯接口
output led; //用于测试的 LED 指示灯
////////////////////////////////////////////////////
//系统内部时钟和复位产生模块例化
//PLL 输出复位和时钟,用于 FPGA 内部系统
wire sys_rst_n; //系统复位信号,低电平有效
wire clk_25m; //PLL 输出 25MHz
wire clk_33m; //PLL 输出 33MHz
wire clk_50m; //PLL 输出 50MHz
wire clk_65m; //PLL 输出 65MHz
wire clk_100m; //PLL 输出 100MHz
sys_ctrl uut_sys_ctrl(
.ext_clk(ext_clk),
.ext_rst_n(ext_rst_n),
.sys_rst_n(sys_rst_n),.clk_25m(clk_25m),
.clk_33m(clk_33m),
.clk_50m(clk_50m),
.clk_65m(clk_65m),
.clk_100m(clk_100m)
);
////////////////////////////////////////////////////
//Qsys 系统例化
vip_qsys vip_qsys_inst(
.clk_clk (clk_50m),
.reset_reset_n (sys_rst_n),
.pio_led_external_connection_export (led)
);
endmodule
vip_qsys vip_qsys_inst(
.clk_clk (clk_50m),
.reset_reset_n (sys_rst_n),
.pio_led_external_connection_export (led)
);
这里只有 3 个接口。clk_clk 是时钟信号,即 NIOS II 处理器的时钟,输入的时钟为 PLL 产生的 50MHz 时钟;reset_reset_n 是 NIOS II 处理器的复位信号,高电平有效,输入的时钟为'异步复位,同步释放'处理后的系统复位信号;pio_led_external_connection_export 是一个 PIO 输出信号,它将被连接到 VIP 核心板上的一个 LED 指示灯。
5.4 软件工程——创建与编译 双击桌面上或单击开始菜单中的'Nios II 13.1 Software Build Tools for Eclipse'(简称 EDS)图标,启动 EDS 软件。首先弹出如图 5-34 所示的'Workspace Launcher'设置对话框,采用默认设置并单击 OK 按钮进入软件。
如图 5-36 所示,执行菜单栏 File→New→Nios II Application and BSP from Template 命令新建一个模板工程。
在弹出的新建工程配置页面中进行设置,如图 5-37 所示。
·'Target hardware information→SOPC Information File name'后面加载系统硬件,即加载当前工程目录下的 vip_qsys.sopcinfo 文件。在'CPU name'后面的下拉列表框中选择'nios2_qsys'。
·在'Application project→project name'后面的文本框中输入软件工程名称。这里命名为'vip_swprj'。
·在'Project template→Templates'的下拉列表框中选择'Blank Project'。
如图 5-38 所示,此时我们可以在工程文件夹下看到多了一个 software 文件夹,它下面有两个文件夹:vip_swprj 和 vip_swprj_bsp,分别对应存放我们在 EDS 的 Project Explorer 下的两个工程名为 vip_swprj 和 vip_swprj_bsp 的新工程。vip_swprj 工程是软件应用工程,可以在这个工程里面新建源代码;vip_swprj_bsp 工程则用于存放硬件相关信息,其中包含很多底层硬件驱动,用于衔接软硬件,一般无需修改。
如图 5-39 所示,右键单击应用工程 vip_swprj,在弹出菜单中执行 New→Source File 命令。由此新建一个名为 main.c 的 C 文件。
main.c 文件参数的设置如图 5-40 所示。
打开 main.c 文件,编写软件程序。本实例要求使用 PIO 脚控制 LED 指示灯闪烁,因此可以编写软件程序如下。
#include "alt_types.h"
#include "altera_avalon_pio_regs.h"
#include "sys/alt_irq.h"
#include "system.h"
#include <stdio.h>
#include <unistd.h>
void delay (void ) ;
int main (void )
{
printf ("Welcom use VIP board!\n" );
printf ("Look, LED is running!\n" );
while (1 )
{
IOWR_ALTERA_AVALON_PIO_DATA(PIO_LED_BASE,0x1 );
usleep(1000000 );
IOWR_ALTERA_AVALON_PIO_DATA(PIO_LED_BASE,0x0 );
usleep(1000000 );
}
return 0 ;
}
如图 5-41 所示,在 bsp 工程目录下,有一个名为 system.h 的文件,该文件例化了 Qsys 系统所有外设的参数信息,在应用工程中常常包含该头文件,并且使用它所定义的各种参数。
下一步,别急着编译,先到 BSP Editor 中做一些设置,裁剪一下代码,否则一大堆没用的 BSP 会占用大量的代码控制,以至于我们的 40KB 代码空间都不够用。
如图 5-42 所示,选中应用工程 vip_swprj,单击右键弹出菜单,选择 Nios II→BSP Editor 命令。由此新建一个 main.c 的 C 文件。
如图 5-43 所示,进入 BSP Editor 界面,需要按照如图 5-44 截图进行设置,完成后单击 Generate 按钮,完成后按 Exit 按钮退出即可。
前面的 BSP Editor 中按照如图 5-44 做设置。另外需要提醒大家注意的是,每次硬件工程(在 Quartus II 中)的任何更改,建议在编译软件工程前都重新在 BSP Editor 中 Generate 一次,这是为了保证软硬件的一致性,否则编译将出错。
接着回到 EDS 中,分别选中 vip_swprj_bsp 和 vip_swprj,然后右键单击选中'Build Project'进行编译。记住,最好先去编译 vip_swprj_bsp 工程,然后编译应用工程 vip_swprj。编译完应用工程,如图 5-45 所示,可以看到代码量有 3300B。
5.5 软件工程——导入已有工程 打开 EDS 后,执行 File→Import 命令,如图 5-46 所示,选择 General→Existing Projects into Workspace 命令,进入下一步。
如图 5-47 所示,在'Select root directory'后面定位到当前的软件工程目录下,即'软件工程目录'文件夹下。如图 5-47 所示,在 Projects 下面将出现 vip_swprj 和 vip_swprj_bsp 两个子文件夹,确认它们都勾选后,单击 Finish 按钮完成工程导入。
工程打开后,通常我们还需要在 BSP 工程中更改 setting 文件的某些路径信息。如图 5-48 所示,这里的两个路径需要对应为你的工程所在实际路径。