【SoC FPGA学习】八、从零开始体验一把为 HPS 添加外设,以 UART 外设为例
在本系列教程中 《【SoC FPGA学习】二、SoC FPGA硬件初探,基础扫盲 》一节中的2.5小结简单介绍了一下 SOC FPGA添加timer外设的方法,但是此外设并没有实际的引出脚,并且在那篇文章的介绍中也并没有实际的跑进来timer,这一节我们就拿UART外设为例,从来开始了解添加 SOC FPGA 外设并使用起来的全部流程!
本节将通过完全手把手的形式介绍如何修改AC501_SoC_GHRD工程文件,通过在 Platform Designer(原 Qsys)加一个 Altera UART 外设到 HPS 的轻量级FPGA 到 HPS 桥(fpga2hps_lw_bridge),然后更新到 Quartus 工程中, 再重新编译生成 HPS 启动的 U-Boot 镜像文件和 Preloader 镜像文件并更新到 AC501_SoC的启动 SD 卡中。 接下来,针对重新生成的包含了有 Altera UART 外设的 HPS系统,编译得到新的 dts 文件和 dtb 文件, 最后将 dtb 文件拷贝到 AC501_SoC开发板的 Linux 系统 SD 卡中, 以使 Linux 系统能够获取新增加的 Altera UART外设。
注:上述的“重新编译生成 HPS 启动的 U-Boot 镜像文件和 Preloader 镜像文件并更新到 AC501_SoC的启动 SD 卡中”这一步可以不做,因为我们不需要在u-boot启动的时候就加载我们添加的外设IP,所以这一步我们可以不做。【只要我们不改Platform Designer中HPS组件的参数,我们就需要重新编译U-Boot和Preloader,使用之前的即可!】
本节虽是以 AC501-SoC 开发板为例进行介绍,但是由于该例子十分通用,对于其他 Cyclone V SoC 开发板的操作也都是一样的, 读者根据此例子讲解的方法,针对其他的硬件板卡所提供的 GHRD 工程,进行类似的实验。
一、修改 GHRD 工程
本小节讲述如何在提供的 AC501-SoC 开发板黄金硬件参考设计工程中添加一个 UART IP 并最终在 Quartus 中编译得到 sof 格式的 FPGA 编程文件。
1.1、打开 GHRD 工程
AC501-SoC 开发板的配套光盘中提供了一个名为 AC501_SoC 的工程, 该工程为厂家设计的一个包含了开发板上各种外设的参考工程,我们可以使用该工程进行修改,以满足客户定制需求。在光盘AC501_SoC_CD_Files\Demos\SOC_FPGA\Quartus 中,包含了该设计文件, 拷贝该文件到磁盘中,例如 D:\fpga\soc_system\examples, 然后双击AC501_SoC_GHRD.qpf, 使用高于 Quartus 14.0 的版本打开,本文使用 QuartusPrime 17.1 版本,单击图标打开 Platform Designer 工具。然后在弹出的文件打开窗口中选择 soc_system.qsys 文件并打开。 这里需要说明的是,从Quartus Prime 17.1 开始, Intel 使用 Platform Designer 一名代替之前版本软件中的 Qsys 名称。 而实际从厂家的说法可知,两者并未有实质性的更改,只是改个名而已,因此无需介意。
1.2、添加 UART IP
从 Platform Designer 左侧的 IP_Catalog 中搜索到 UART(RS-232 Serial Port)并双击添加, 各项参数默认即可,如下图所示。
UART(RS-232 Serial Port)属于性能比较低的IP核,而Altera 16550 Compatible UART 是性能比较高的UART IP核,但是它需要License证书,要想使用性能较高到Opencore网站搜索兼容16550的 UART IP核,这样既可以绕过证书,也可以使用到性能比较高的IP核。
注意,这里我勾选了Fixed baud rate,表示使用的是固定的115200的波特率进行通信,这里可以不勾选,就可以通过修改寄存器的方式切换波特率。
重点在于 UART IP 核的各个信号在 Platform Designer 中的连接。由于在 AC501_SoC_GHRD 工程中原本已经添加好了一个 UART IP 并命名为了 uart_0, 所以这里添加新的 UART IP 时软件会自动将其命名为 uart_1。
UART IP 提供一个 Avalon Memory Mapped Slave(以下简称 Avalon MM Slave)总线与主机相连。要想能够对其寄存器进行读写操作,则需要一个带Avalon Memory Mapped Master(以下简称 Avalon MM Master) 总线的外设实现。 在以 NIOS II 为核心的 SOPC 技术中, NIOS II CPU 是一个标准的 Avalon Memory Mapped 主机, 能够实现对各种 Avalon Memory Mapped Slave 的外设的读写操作。因此使用时一般直接将 UART IP 的 Avalon MM Slave 端口连接到NIOS II 的 Avalon MM Master 端口上。
1.3、关于 HPS 与 FPGA 数据交互
在含有 HPS 的 SOC 系统中,由于 HPS 中的 ARM Cortex-A9 使用的是 AXI 总线协议, 其提供的与 FPGA 通信总线也是 AXI 总线, AXI 总线和 Avalon Memory Mapped 总线在信号类型和时序上都有一定的差别,无法直接连接。HPS 针对和 FPGA 的互联通信,总共提供了 3 种形式的 AXI 总线:
- 用于FPGA 主动向 HPS 发起高效数据传输操作的 F2H_AXI_Slave 总线
- 用于 HPS主动向 FPGA 发起高效数据传输操作的 H2F_AXI_Master 总线
- 用于 HPS主动向 FPGA 发起一些控制或小容量数据传输操作的 H2F_LW_AXI_Master 总线
H2F 和 F2H 两个高速桥,每个桥最高支持 128-bit 位宽。在 HPS 侧逻辑中, 每个桥最高可运行在 200M 的时钟频率下, 数据位宽为固定的 64bit,因此在不考虑轻量级桥的情况下, FPGA 和 HPS 的总通信带宽为642200MHz=25600Mbps ,另外, Intel Cyclone V SoC FPGA 还提供了一个FPGA 到 SDRAM 的桥, 该桥最高可提供 4 个独立的读写端口和 6 个控制端口, 支持可配置的 32 位、 64 位、 128 位和 256 位的数据位宽, 适合于 FPGA 共享使用 HPS 侧的高性能存储器的应用。
为了支持 Platform Designer 中提供的所有使用 Avalon Memory Mapped 总线的 IP 能够方便的连接到 HPS 上, Platform Designer 具有 Avalon 和 AXI 总线间的自动转换功能,我们在设计时,只需要将 Avalon Memory Mapped 总线信号连接到 AXI 信号总线上即可。至于如何完成两者间的信号功能和时序的转换,用户无需关心, Platform Designer 会自动生成相应的转换逻辑。 这对于一些已经使用 NIOS II CPU 开发了相应的系统和自定义 IP 的用户来说,是一件非常方便的事情,用户可以直接在 HPS 中按照原本 NIOS II 中的系统架构添加 IP 并连接好总线,就能实现相同的功能,同时,对于用户自己开发的自定义 IP,无需做任何修改就能直接用于 SOC 系统中,大大降低了系统移植的工作量。连接效果,如下图所示。
1.4、连接 UART IP 信号端口
这样一来我们将 UART IP 连接到 HPS 上就方便多了,我们只需要将 UART IP 的 Avalon MM Slave 总线端口连接到 HPS 的 H2F_LW_AXI_Master 总线上即可。
那么为什么选择将 UART 的 Avalon MM Slave 端 口连接到H2F_LW_AXI_Master 总线,而不是 H2F_AXI_Master 总线上呢? 这是因为 UART IP 是一个数据吞吐量非常小的设备,其最高通信波特率为 115200bps, 如此低的波特率,自然没有必要连接到专为数据高速高效传输设计的 H2F_AXI_Master 总线上。另外, 使 UART IP 连接到 H2F_LW_AXI_Master 总线,并使用较低的时钟频率进行通信, 也更利于软件在对 FPGA 逻辑进行布局布线时进行合理时序优化, 使其他需要运行在较高时钟频率的逻辑能够获得更好的时序优化,从而提高系统性能。
同时,为了保证 UART IP 和 H2F_LW_AXI_Master 处于相同的时钟域,将UART IP 的 clk 端口连接到和 HPS 的 H2F_LW_AXI_Clock 端口相同的时钟源上,在 Platform Designer 中可以看到, H2F_LW_AXI_Clock 端口是连接到了clk_0 这个时钟输入模块的 clk 信号上, 因此 UART IP 的 clk 端口也连接到时钟输入模块的 clk 信号上,如下图所示。
uart IP核的clk信号要与h2f_lw_axi_master的clk信号一致。(复位也一样!)
接着连接复位信号,这里直接连到了clk_0这个IP核的clk_reset,如下图
UART IP 的 external_connection 端口是需要分配到芯片的物理管脚上与其他的 UART 控制器进行通信的,包含了 uart_tx 和 uart_rx 两个信号, 因此这个端口需要直接导出。 在 export 一栏直接双击该信号即可导出,为了便于识别,将导出名修改为 uart_1,如下图所示。
UART IP 的 irq 端口可以向中断接收器发出中断请求信号, HPS 中每个ARM 核支持一个最高可支持 32 个外部中断数量的中断控制器,中断控制器的外部中断端口名为 f2h_irq, 双核的 HPS 支持 f2h_irq0 和 f2h_irq1,本例中只需要连接到 f2h_irq0 即可,如下图所示
上面说了这么多,只是为了让读者能够更加明白每个端口或网络连接的原理,以便于能够举一反三,掌握其他类似 IP 核的添加和使用方式。实际上, 如果是初次接触的话,只需要参考这个工程中提供的 uart_0 核的所有信号连接方式即可。 因为两个 IP 的端口基本相同,因此将两个核相同属性的端口连接到同一个信号网络上, 即可完成 UART IP 的添加。 在后续的使用中,如果读者希望自己添加 PIO 核、 SPI 核、 IIC 核等,都可以参照本节的方式进行。
1.5、分配组件基地址
完成了 UART 的添加之后, 可以看到在 Platform Designer 下方的信息窗口中有报错信息, 提示 UART IP 的地址范围和其他设备冲突, 如下图所示。
这里我们可以手动调整 UART 的地址范围,也可以直接使用 Platform Designer 提供的自动分配基地址的方式来解决这个问题。如果使用自动分配基地址的方式,需要注意的是,有可能会更改之前已经添加好的 IP 的基地址,而基地址改变之后,会影响已有的软件程序的正常运行,因此,为了保证添加新的外设之后, 为之前的系统设计的软件程序还能够正常运行,建议在自动分配基地址之前先将所有原有 IP 的基地址锁定。锁定的方式非常简单, 在每个 IP 的基地址一栏的具体地址前面,都有一个“锁”型的标志,默认是打开的,点击下即可锁闭, 如下图所示。一旦锁闭,当执行自动分配基地址操作时,这些设备的基地址会保持原值不变。
而后,只需要在 Platform Designer 菜单栏中点击 System —> Assign Base Addresses即可自动分配基地址, 如下图所示。
再看qsys界面的下方或者Messages一栏,就显示 0 Error了,最后ctrl + s进行保存。
至此, 在 Platform Designer 中完成了给 HPS 添加 UART IP 的操作,接下来,我们将进行新系统的 HDL 代码的生成。
1.6、生成Qsys系统的HDL文件
在 Platform Designer 菜单栏中点击 Generate -> Generate HDL…, 然后在弹出的窗口中点击 generate 按钮即可开始 HDL 代码的生成, 如下图所示。 如果系统没有保存,软件会先进行系统的存档,系统存档完成后, 点击信息框中的close 即可开始真正的 HDL 代码的生成过程。该过程耗时大概 1~3 分钟, 具体耗时长度根据使用者的 PC 性能会有所差异。
生成HDL文件中…
生成完毕后,点击Close即可。
1.7、添加uart_1的端口到Quartus工程中
完成 HDL 代码的生成之后,我们暂时还不能关闭 Platform Designer,还有最后一个步骤,就是从 Platform Designer 的系统例化模板中复制出新增加的端口信号,添加到 Quartus 工程中的例化部分。 同样是在 Platform Designer 菜单栏中点击 Generate -> Show Instantiation Template, 打开系统例化模板, 如下图所示。
在模板中可以看到,最下方有我们新添加的 UART IP 的两个信号uart_1_txd 和 uart_1_rxd, 使用鼠标左键拖动以选中这两个信号,右击复制这两个信号内容, 如下图所示。
打开 Quartus 工程的顶层文件 AC501_SoC_GHRD.v文件,附加到 soc_system 模块例化的尾部,并修改这两个信号的例化名为uart_1_txd 和 uart_1_rxd。如下图所示。
这里补充一个 quartus的一个小技巧,将.v文件独立出来(回去):
注意, Verilog 例化一个模块时, 该模块的最后一个信号末尾是不带”,”的。上图中,最后一个信号为 i2c_0_sda_pad_io, 其末尾是不带有”,”的,在添加新的模块的信号到模块末尾时,记得先对原本模块的最后一个信号的模块补上”,”, 否则编译会报错。
另外,需要将<connected-to-uart_1_rxd>
更改为fpga_uart_1_rxd
,将<connected-to-uart_1_txd>
更改为fpga_uart_1_txd
,最后效果图,如下图所示。
最后ctrl+s进行保存。至此, Platform Designer 的任务就完成了, 可以关闭 Platform Designer, 然后回到 Quartus 软件中,完成 uart 功能的引脚添加和分配。关闭Platform Designer会弹出如下窗口,点击close即可。
在 AC501_SoC_GHRD.v 文件的端口列表中, 添加两个端口描述
input wire fpga_uart_1_rxd,
output wire fpga_uart_1_txd,
- 1
- 2
修改好的端口列表如下图所示:
最后ctrl+s进行保存!
1.8、分配 FPGA 管脚
保存 AC501_SoC_GHRD.v 文件,使用快捷键ctrl+k
或者单击工具栏的
就可以对工程进行分析和综合 了,如果分析和综合的过程中检查出有语法错误,需要自行检查改正, 然后重新分析和综合。 下图是分析综合成功后的样子。
注意,分析综合所用时间可以在quartus的右下角看到。
分析和综合完成以后, 单击工具栏的
就可以打开Pin Planner,然后可以看到 fpga_uart_1_txd 和 fpga_uart_1_rxd 两个端口了,如下图所示。
修改电平标准(I/OStandard)为 3.3-V TTL, 再将这两个信号分别映射到 FPGA 的 PIN_W18 和PIN_AB19 引脚上, 即实际对应到 GPIO0 接口上的 FPGA_GPIO0_D8 和FPGA_GPIO0_D9。 如下图所示:
我是怎么知道对应到 GPIO0 哪个接口的呢?在《用户手册》中,查找GPIO管脚分配表:
如何确定对应的电平是什么?
在管脚分配界面中,一种颜色代表了一种IO BANK。一种IO BANK 里面的电平需要设置成一样的,不然编译会报错。
电平的赋值支持 ctrl+c ctrl+v的快捷操作
引脚分配完毕后,进行全编译,生成 .sof编程文件,具体操作点击工具栏如下图所示按钮。
全编译完成后…
至此,我们就完成了在 Platform Designer(原 Qsys)加一个 Altera UART外设到 HPS 的轻量级 FPGA 到 HPS 桥(fpga2hps_lw_bridge),然后更新到Quartus 工程的工作。
一种节约时间的方法:
在上述步骤中,我们要完成引脚分配,必须要先对设计进行分析和综合。由于 Quartus 软件对该工程的综合大概需要耗费 2~5 分钟左右的样子, 而分配完引脚后,还需要再全编译一次才能生成 sof 编程文件。 全编译又会重新执行分析和综合的过程, 因此会导致实际执行了两次分析和综合的过程, 浪费时间。 为了节约时间,在对工程改动不大,或者添加的信号不多的情况下, 我们可以跳过分析和综合这一步, 手动添加引脚和对应的管脚信息,添加完成后再全编译, 这样可以节约较多的时间。
由于没有经过分析和综合, 软件无法分析出系统中有那些端口, 所以在 PinPlanner 中是不会展示这些信号的,此时设计者可以手动输入信号名来完成信号的添加。 同样还是打开 Pin Planner, 拖动右侧的滑动条到最下方, 双击<>进入编辑状态,手动输入需要增加的信号名称 fpga_uart_1_txd 和fpga_uart_1_rxd, 然后再修改 I/O Standard 为 3.3-V TTL,在 Location 一栏输入正确的管脚信息。 如下图所示:
1.9、生成配置数据二进制文件(rbf)
rbf 文件是 Quartus 编译生成的 fpga 配置文件的二进制数据量格式的文件,主要用于使用外部主机通过 PS 方式配置 FPGA。在含 ARM 硬核的 SoC FPGA 中,可以使用 HPS 配置 FPGA,配置时分为两种情况:
- 1、在 HPS 处于 uboot 启动阶段时通过 u-boot 配置
- 2、Linux 启动之后通过应用程序配置
这两种配置方式都需要用到 rbf 格式的配置文件,但是两种方式所需的 rbf 格式的配置文件却又存在着差异,其中 uboot 阶段配置 fpga 需要使用未经压缩的 rbf 格式文件,而在 Linux 应用程序中配置fpga 时,需要使用经过压缩了的 rbf 文件。默认情况下, Quartus 软件不能自动生成 rbf 文件,需要在设置种开启生成 rbf (经过压缩)文件选项。另外,也可以直接通过命令行的方式,从 quartus 编译得到的 sof 文件转换得到 rbf (未经压缩)文件。本节我们将使用命令行的方式生成未经压缩的rbf文件!
Quartus 工程编译好之后,要想能够将对应的编程信息配置到 FPGA 中,有3 种方法
- 1、使用 JTAG 直接下载 sof 文件
- 2、将 sof 文件转换为 jic 文件,烧写到 EPCS 中,然后设置 FPGA 从 EPCS 中启动
- 3、将编程文件(.sof)转换为二进制数据流文件(.rbf), 然后放置在 SoC 的启动镜像 SD 卡中,在 Uboot 启动阶段将其配置到 FPGA 中。
关于使用 JTAG 下载 sof 文件和 jic 文件的操作方法,可以参考本系列《SoC FPGA 开发板的 FPGA 配置数据下载和固化》章节的内容。这里我们选择第三种:
在 AC501_SoC_GHRD 工程中,提供了一个名为“sof_to_rbf.bat”的脚本文件,存放于 AC501_SoC_GHRD\output_files 目录下。 使用时,仅需双击该文件,即可自动运行并生成名为 soc_system.rbf 的文件,双击后如下图所示。生成的soc_system.rbf 在后续启动 FPGA 时会用到。
二、制作 Preloader Image(可选)
再次提醒:只要我们不改Platform Designer中HPS组件的参数,这一步可以不做,因为我们不需要在u-boot启动的时候就加载我们添加的外设IP。
按照正常的流程,接下来我们需要先对 Quartus 工程进行一次全编译, 在全编译完成后,软件会生成 .sof 编程文件以及用于产生 U-Boot 和 Preloader 的配置文件 hps_isw_handoff, 在进行软件设计时,这些文件可以通过 BSP Editor转换成 Preloader 需要的输入文件, 以进一步生成 Image 文件。 下图所示的是 PreloaderImage 制作流程。
2.1、打开 SoC EDS 工具
从 Windows 的开始菜单,程序列表中找到 SoC EDS Command Shell, 点击打开。 如下图所示:
这是一个命令行形式的工具, 该工具非常类似于 Windows 系统的 cmd 命令行窗口和 Linux 系统的终端窗口, 在这个窗口中,我们通过输入不同的命令就可以使用不同的工具完成相应的操作。 由于该工具中的命令与 Linux 系统中的命令基本一致,因此这里不再赘述。
2.2、生成 bsp 文件
要编译 U-Boot 和 Preloader,需要先使用 bsp-editer 工具创建相关的源码档案, 在打开的 SoC EDS Command Shell 中,输入命令 bsp-editor 即可打开 BSP编辑工具, 如下图所示:
正在打开 bsp-editor 界面
打开完成后,选择菜单 File --> New HPS BSP 来创建新的 BSP , 如下图所示:
然后设定 Preloader Setting Directory 的路径。 在 New BSP 的窗口下选择Preloader Setting Directory 的路径,把路径指向 Quartus 工程下的hps_isw_handoff\soc_system_hps_0 目录, 即C:\Users\wangxubo\Desktop\AC501_SoC_GHRD\hps_isw_handoff\soc_system_hps_0
, 如下图所示:
打开之后,其他设置不用更改,直接点击 OK 来生成 BSP setting 文档以及文件夹,系统将在工程內产生一个 software 的文件夹,并生成一个 settings.bsp文档,如下图所示:
若中途出现下图所示的是否要覆盖存在的BSP目标目录,选择OK即可。
接下来在BSP Editor窗口点击 Generate 生成 preloader 的原始档以及 Makefile。当生成档案完成后,按下 Exit 按钮完成任务离开窗口。如下图所示:
进入C:\Users\wangxubo\Desktop\AC501_SoC_GHRD\software\spl_bsp\generated
文件夹并查看产生的文档。可以看到之前在 Platform Designer 中有关 HPS 的相关设定已经转换成.h 头文件以配置preloader source code 对应设置。如下图所示:
以 pinmux_config.h 为例,可以看到 HPS 的外设的配置使用情况,其中“ (1) ”代表该外设被使用,如下图所示:
2.3、编译 preloader 和 uboot
有了这些,就可以编译 U-Boot 和 Preloader 了。 回到 SoC EDS CommandShell 中, 使用 cd 命令将路径切换到 Quartus 工程目录下,例如本例的工程目录为 C:\Users\wangxubo\Desktop\AC501_SoC_GHRD
, 只需要输入命令(注意路径的斜线方向变了):
cd c:/users/wangxubo/Desktop/AC501_SoC_GHRD
- 1
然后使用 make uboot 命令, 就可以把 preloader 和 uboot 文件都编译出来。如果只需要编译 preloader,就使用 make prelaoder 好了。由于会重新编译一遍硬件工程,整个过程会比较漫长, 视用户的 PC 机性能,可能为 5~20 分钟左右。
编译完成后在 software\preloader\uboot-socfpga 目录下会找到 u-boot.img 文件,在 software\preloader\uboot-socfpga\spl 下会找到 u-boot-spl.bin。 如下图所示。
将 u-boot- spl.bin 文件复制,粘贴到向上两层的 preloader 目录中,替换原来的文件
然后在SoC EDS Command Shell 中, 使用 cd 命令将目录定位到此路径, 可以直接使用以下命令实现:
cd software/preloader
- 1
u-boot-spl.bin 为 binary 格式的文件,按照 Altera 的要求要按照特定格式添加文件头!需要使用到的工具为 mkpimage 工具。在 software/preloader 目录下, 使用 mkpimage 命令即可完成该操作,具体命令内容如下所示:
mkpimage –hv 0 -o preloader.img u-boot-spl.bin
- 1
执行很快就完成,完成之后文件夹下会产生一个 preloader.img 文件, 如下图所示。 该文件即可以用于更新 SD image 中的 preloader。
2.4、更新 preloader 和 uboot
我们也可以同时更新 u-boot.img 文件和 preloader.img 文件 。 将software\preloader\uboot-socfpga 目录下生成的 u-boot.img 文件也拷贝到software\preloader 中(直接替换旧的), 如下图所示。
然后使用 SoC EDS 中的工具 alt-boot-diskutil.exe 来完成 preloader 和 u-boot 镜像到 SD 卡的更新。请首先将 AC501-SoC 开发板的启动 SD 卡使用读卡器插接到 PC 机上,并确定其在电脑中的盘符,例如笔者的电脑上 SD 卡被识别为了 I 盘, 下图所示。
然后输入下列命令以完成 preloader 和 u-boot 镜像的更新(命令中最后一个表示盘符)
【注意这一步要重新开一个SOC EDS COMMAND SHELL,以管理员方式运行,不然会出现device open failed的情况】
alt-boot-disk-util -p preloader.img -b u-boot.img -a write -d I
- 1
执行成功后, 可以看到 Altera Boot Disk Utility was successful 的字样, 如下图所示,表明更新成功。
2.5、使用新的 Uboot 启动 SoC
更新成功后, 将 SD 卡从电脑弹出,然后插入到 AC501-SoC 开发板上, 给开发板上电,在串口终端上可以看到系统启动并打印一系列的信息。其中第一行就是 U-Boot 的相关信息,可以看到,使用的 U-Boot 版本为 2013.01.01 版本,编译时间为 Aug 27 2020 - 15:36:46。 与我们的操作时间一致,因此可以判定 U-Boot 更新成功。
之前的uboot启动,如下图
三、制作设备树
本小节介绍如何针对修改后的 Qsys 系统制作支持 Linux 系统启动并自动识别硬件的设备树文件。
3.1、设备树制作流程
设备树(Device Tree) 是一种有关硬件系统描述的数据结构,它可以描述整个系统上挂载了多少种类的硬件。通过 device tree 系统上的硬件信息都可以传递给 OS (linux)。如此便可以不用在 Kernel 内放置大量的冗长的代码。这样的特性对于硬件里面有 FPGA 的情况下提供了很大的弹性与灵活性。 IntelSoC FPGA Design 产生 Device Tree 的流程如下图所示。
当 Platform Designer 产生出 FPGA 的设计后 (.sopcinfo),可以使用 IntelSoC EDS 工具里的 Device Tree Generator 来产生 Device Tree 的源文档(dts)。它描述了有关 HPS 的外设还有选择使用到的 FPGA Soft IP 以及用户自定义的外设等信息。 .dtb 文件是.dts 文件被 Device Tree Compiler 编译后生成的二进制格式的 Device Tree 描述,可被 Linux 内核解析。通常在我们为开发板制作 NAND、 Sdcard 启动 image 时,会为.dtb 文件预留一个很小的存放区域(FAT 分区)。之后 bootloader 在引导 kernel 的过程中,会先读取该.dtb 到内存。更多关于 Device Tree 的介绍可以参考下面的链接:
https://rocketboards.org/foswiki/Documentation/GSRDDeviceTreeGenerator
3.2、准备所需文件
生产 dts 和 dtb 的操作很简单, Intel SoC EDS 工具里提供有完整的工具链,我们在生成时,只需要执行“make dts”和“make dtb”命令即可实现。 需要注意的是,生成 dts 文件需要有另外两个描述芯片和板级硬件的文件支持,在早期的 Quartus13.1 版本中,使用的是 hps_clock_info.xml 和 soc_system_board_info.xml 两个文件 , 不过到了 Quartus 14.0 版本 , 这两个文件就改变了, 不再使用 hps_clock_info.xml 文件, 而是以 hps_common_board_info.xml 文件代替。 在从Quartus 软件安装目录下的\embedded\examples\hardware\cv_soc_devkit_ghrd
目录下, 提供了这两个文件,不过这两个文件的内容是针对 Intel 官方出品的 SoC 板卡编写的, 里面包含了众多的硬件信息,并不完全适用于其他的板卡, 为此,AC501-SoC 开发板同样也提供了这两个文件。 AC501_SoC 开发板提供的这两个文件是通过修改官方板卡提供的文件的内容得到的,一些厂家板卡中有的内容,而 AC501-SoC 开发板上没有的资源,修改时选择了保留,方便用户根据该文件学习 xml 文件的编写方法, 理解 xml 文件和 dts 文件内容的对应关系。 由于这些资源在 AC501-SoC 板卡上没有实际的硬件支撑,所以操作系统启动时这些资源也不会得到有效的使用, 对系统的运行没有任何影响。
检查工程目录下是否有 Platform Designer 生成的 soc_system.sopcinfo 文件。 Device Tree Generate 将使用这 3 个文件来产生出.dts 文件。如下图所示:
3.3、生成 dts 文件
回到 SoC EDS Command Shell 窗口中, 将路径切换到 Quartus工程根目录下。 如果是接着上述更新 U-Boot.img 文件到 SD 卡的操作的,只需要执行“cd …/…/”即可回到工程目录下,如下图所示。
输入以下命令以产生.dts 文件
make dts
- 1
编译会报 8 个信息:
- 第一个是提示 alt_vip_itc 模块类型未知,由于 alt_vip_itc 核是一个单纯的将framereader 读取到的数据打包成 VGA 时序的 IP 核,其本身并不需要受 HPS 控制,因此其 dts 信息是否正确并不影响 HPS 上操作系统的启动和运行。
- 第 2、 3、 4个信息是提示 oc_iic 核的类型未知,而 oc_iic 核是我们添加的一个第三方 I2C 控制器,虽然该控制器在 Linux 系统中也已经有了驱动支持,但是由于该 IP 核的脚本信息中没有提供相应的匹配Linux 驱动的信息, 因此使用此种方式生成的 dts 文件也并不包含该 I2C 控制器的信息。 此种情况的直接影响就是 Linux 系统在启动时无法识别该控制器(在 /dev 目录下没有我们添加的i2c设备),也就无法自动添加其驱动程序, 并不影响系统的正常启动和运行。 如果希望Linux 系统在启动时能够自动加载该控制器的驱动,需要手动修改生成的 dts 文件,该部分内容将在讲解 dts 文件时候讲解。
- 后四个信息是xml 文件不对(hps_common_board_info.xml、soc_system_board_info.xml),在
hps_common_board_info.xml
中搜索第5个信息对应的height
,会看到如下图所示信息,也就刚好对应了第5、6、7、8信息,描述了官方开发板上的LCD显示屏的相关信息。当然还需要知道小梅哥的这个也是在官方原版的xml文件上修改的,我们可以查看官方原版的xml文件,其路径在quartus的安装目录下,我的路径为:D:\intelFPGA\17.1\embedded\examples\hardware\cv_soc_devkit_ghrd\hps_common_board_info.xml
。这里既然没用,我们可以直接删除!
再次make dts
,效果如下图
多了几个无用的信息而已,对于我们初学者不懂的话没必要管,不影响下一步。
在 Windows 中打开工程文件夹,可以看到.dts 文件已经被生成,如下图所示:
这里我们简单的介绍下,soc_system.dts文件,也可直接跳过,继续下面操作:
重点关注其中的 sopc0 节点,这是一个大节点,包括了利用Platform Designer添加的软IP,也包括了HPS本身的硬IP。
其下的子节点:hps_0_bridges,是我们在FPGA侧添加的外设。
3.4、生成 dtb 文件
接着输入下述命令产生 .dtb 文件:
make dtb
- 1
注:拷贝到SD卡的时候,需要将
soc_system.dtb
名字更改为socfpga.dtb
由于 dtb 文件中包含的信息是与一个具体的 Quartus 工程对应的, 在启动时, Linux 操作系统会根据 dtb 文件中的硬件描述去初始化 FPGA 侧添加的各种IP,因此 Linux 能够正常初始化 FPGA 侧外设的前提是 FPGA 中已经正常配置了这些 IP。 FPGA 在上电时,根据加载设置引脚的状态,可以从外部 EPCS 存储器或者由 HPS 的 FPGA 管理器加载配置文件。当使用 HPS 的 FPGA 管理器加载配置文件时,默认使用的是名为 soc_system.rbf 的二进制文件。
3.5、运行修改后的工程
生成好 dtb 文件之后,就可以将其更新到开发板的启动 SD 卡中了。 将开发板的 SD 卡使用读卡器连接到 PC 机上, 打开 SD 卡盘符,可以看到里面已经有4 个文件, 如下图所示。 其中, zImage 是 Linux 内核文件, soc_system.rbf 为FPGA 的配置文件,以支持 HPS 配置 FPGA。 socfpga.dtb 则是设备树文件,系统启动的时候,默认识别的设备树名称就为 socfpga.dtb, 因此,我们将上面生成的 socfpga.dtb 拷贝到 SD 卡中替换原本存在的 socfpga.dtb。 同时,将修改GHRD 工程后生成得到的 soc_system.rbf 文件也拷贝到 SD 卡中替换原本存在的soc_system.rbf 文件。
提醒一下:soc_system.rbf 存放于 AC501_SoC_GHRD\output_files 目录
替换完成后,如下图所示:
而后将 SD 卡安全弹出。插入开发板中, 给开发板上电,在串口终端中可以看到,系统开始启动。 在打印的众多启动信息中,可以看到如下图所示两条内容:
由于我们 AC501_SoC 提供的 SD 卡镜像中包含的 Linux 内核已经开启了对Altera UART 的驱动支持,因此 Linux 系统启动时,通过读取 dtb 文件中的信息, 已经自动识别到了 FPGA 侧添加的两个 UART 控制器, 并将其分别命名为了 ttyAL0 和 ttyAL1。
在系统启动完毕之后,输入 root 用户名以登录系统,然后输入 ls /dev 命令,可以查看系统中已有的设备, 同样可以看到名为 ttyAL0 和 ttyAL1 的两个设备。
小知识点:这里的AL的含义就指的是ALTER
之前的/dev目录如下图
至此,我们在 Platform Designer 中为 HPS 添加的 UART 串口就已经成为了Linux 系统中的标准 tty 外设,用户就可以编写简单的 tty 应用程序来使用该串口了。
下一节,我们来编写uart_1的应用程序,这一节太长了,结束了结束了。哈哈…
文章来源: recclay.blog.csdn.net,作者:ReCclay,版权归原作者所有,如需转载,请联系作者。
原文链接:recclay.blog.csdn.net/article/details/108256292
- 点赞
- 收藏
- 关注作者
评论(0)