上一节,是使用小梅哥编译配置好的内核,所以我们配置好设备树之后就可以在Linux系统中,查看到i2c_2节点,这一节就来看看如何在Linux内核中配置开启想要的驱动以及编译相应的lInux内核。
SoC FPGA 上的 HPS 能够运行标准的 Linux 系统。而 Linux 系统是一个高度可裁剪的系统,支持用户根据自己实际的硬件平台,选择需要的驱动和功能,并编译得到 Linux 系统镜像。 通过此种方式,可以使得编译得到的 Linux系统镜像文件尺寸非常的小,以便于部署到各种嵌入式硬件板卡上。
开发基于 SoC FPGA 的嵌入式系统应用, 如果仅仅使用基于虚拟地址映射的方式开发 Linux 应用程序,无需开发 Linux 内核驱动和修改 Linux 内核配置,实际上是可以不用安装 Linux 操作系统作为主机环境的。 按照本书前面讲解的基于虚拟地址映射的方式,直接在 Windows 系统中使用 DS-5 开发软件进行 Linux 应用程序的编写和编译。 但是,如果需要编写 Linux 内核驱动,或者修改 Linux 内核的配置,则必须先获得一个 Linux 主机环境,通常情况下,可以通过以下三种方式获得 Linux 环境。
如果没有闲置的计算机,或者现有 Windows 系统的计算机有足够的硬盘空间,可以考虑划分一部分硬盘空间,用于安装 Linux 操作系统,最终形成双系统计算机。此种方式经济实惠,且对计算机硬件要求不太高。但是安装双系统有一定的风险, 一不小心有可能造成整个硬盘数据丢失。而且在开发过程使用到 Windows 工具时,需进行系统切换,不是很方便。
如果有足够的计算机可用,可以选择一台计算机全新安装 Linux 操作系统。此种方式不用考虑多系统并存的问题,且对计算机硬件硬件要求不太高。但是也存无法方便的使用 Windows 系统的问题。
如果计算机配置较高,可以考虑虚拟机方案。在 Windows 下安装虚拟机软件,然后通过虚拟机软件创建一台虚拟电脑,最后在虚拟电脑中安装 Linux操作系统;也可以安装 Linux,在 Linux 中安装虚拟机再安装 Windows。
常用的虚拟机软件有 VMware、 Virtual Box 和 Virtual PC 等,不同虚拟机软件的使用方法稍有不同。下文以 VMware 为例进行介绍。优点:安装和使用 Linux 都很方便;还可同时使用 Windows 系统。缺点:对计算机硬件要求高,特别是内存,推荐 4GB 及以上。在 Windows 下使用虚拟机,除了可以继续使用 Windows 下的工具之外,还有下列好处:
安装好虚拟机后,需要安装以下32位必要的支持库
sudo apt install libstdc++6
sudo apt install lib32stdc++6
sudo apt install lib32z1
要编译嵌入式 Linux 系统,需要有相应的 Linux 系统源码文件,而获取Intel SOC FPGA 的 Linux 源码有两种方法:
我们当然选择最简单的,直接从光盘里通过Filezilla拷贝即可,源码所在目录AC501-SoC开发板资料文件夹版\Linux内核源码\linux-socfpga-socfpga-4.5.zip
,完成后输入以下命令解压:
unzip linux-socfpga-socfpga-4.5
由于嵌入式系统资源匮乏,一般不能像 PC 一样安装本地编译器和调试器,不能在本地编写、编译和调试自身运行的程序,而需借助其它系统如 PC来完成这些工作,这样的系统通常被称为宿主机。
宿主机通常是 Linux 系统,并安装交叉编译器、调试器等工具;宿主机也可以是 Windows 系统,安装嵌入式 Linux 集成开发环境。在宿主机上编写和编译代码,通过串口、网口或者硬件调试器将程序下载到目标系统里面运行,系统示意图如下图所示。
所谓的交叉编译,就是在宿主机平台上使用某种特定的交叉编译器,为某种与宿主机不同平台的目标系统编译程序,得到的程序在目标系统上运行而非在宿主机本地运行。这里的平台包含两层含义:一是核心处理器的架构,二是所运行的系统,这样,交叉编译有 3 种情形:
实际上,在 PC 上进行非 Linux 的嵌入式开发,哪怕使用 IDE 集成环境如 Keil、 ADS、 Realview,都是交叉编译和调试的过程,只是 IDE 工具隐藏了细节,没有明确提出这个概念而已。
交叉编译器是在宿主机上运行的编译器,但是编译后得到的二进制程序却不能在宿主机上运行,而只能在目标机上运行。交叉编译器命名方式一般遵循“ 处理器-系统-gcc
”这样的规则,一般通过名称便可以知道交叉编译器的功能。例如下列交叉编译器:
ARMLinux 交叉编译器可以自行从源代码编译,也可以从第三方获取。 对于 Intel 的SoC FPGA, 厂家推荐使用的是 Linaro 编译器, 该编译器可以从 launchpad 网站或者 Linaro 官网下载得到。 由于之前已经讲解了在 Windows 系统中使用DS-5 中集成的 Linaro 交叉编译器编译 Linux 应用程序, 此时又需要在 Linux 系统中编译 Linux 内核,因此需保证两者所使用的交叉编译器版本相同。
在前面章节讲解基于虚拟地址映射的 Linux 应用程序编程时,使用的 17.1版本的 Quartus 软件配套的 DS-5 软件中自带的 arm-linux-gnueabihf 工具链。在软件安装目录下(D:\intelFPGA\17.1\embedded\ds-5\sw\gcc) 有一个说明文件,说明该编译器的版本为 2014.04 版本, 是 4.8.3 的版本。因此,在编译 Linux 内核时,也应该使用 2014.04 版本。
之前提到, Intel 会更新编译器和源码到 launchpad 网站,但是现在的 launchpad 网站上是没有 4.8.3 的版本的, launchpad 网站上对应的最新版本是 4.8.2。 但是该版本的软件 bug 较多,在编译 Linux 内核时会报“error:#error Your compiler is too buggy”的错误。 新版本的编译器需要到 linaro 官网下载,不过 Linaro 官网上最旧的版本都是 4.9-2016.02 了, 无法直接下载得到。 所以,如果需要使用 Quartus Prime 17.1 版本的软件中自带的编译器,请直接从AC501-SoC 开发板光盘中拷贝该版本编译器到 Ubuntu 系统中,再解压安装即可。交叉编译器所在光盘目录:AC501-SoC开发板资料文件夹版\配套软件\gcc-linaro-arm-linux-gnueabihf-4.8-2014.04_linux.tar.xz
。解压命令如下:
tar xvf gcc-linaro-arm-linux-gnueabihf-4.8-2014.04_linux.tar.xz
环境变量生效方法,可以参考:https://blog.csdn.net/ReCclay/article/details/107152005【别忘了顺带把ARCH和CROSS_COMPILE一起配置了】
正确配置环境变量后,输入arm-linux-gnueabihf-gcc -v
后如下图所示:
对内核进行正确配置后,才能进行编译。配置不当的内核,很有可能编译出错,或者不能正确运行。
进入 Linux 内核源码数顶层目录,然后输入 make menuconfig 命令, 可进入如下图所示的基于 Ncurses的 Linux 内核配置主界面( 注意:主机须安装 ncurses 相关库才能正确运行该命令并出现配置界面)。如果没有安装 ncurses 相关库,请在命令行中输入以下命令完成 ncurses 库的安装:
sudo apt install build-essential
sudo apt install libncurses5
sudo apt install libncurses5-dev
输入以下命令,打开图形界面配置内核,能打开说明库没少装,环境是OK的,然后暂时退出即可。
make menuconfig
基于 Ncurses 的 Linux 内核配置界面不支持鼠标操作,必须用键盘操作。基本操作方法:
在 Linux 系统源码的 arch/arm/configs
目录下,存放着很多处理器的内核配置文件, 这些一般由处理器厂家提供,方便用户根据自己的需求在对应的配置文件上进行简单的修改,以得到用户自定义的系统,因为从 0 开始配置一个适用的内核,不仅工作量巨大,而且很容易出错。
对于 Intel 的 SoC FPGA 芯片, Linux 源码中已经提供好了一个名为socfpga_defconfig 的配置文件,我们对内核的配置和修改,建议基于此配置文件进行,因此在进行配置前,需要先将该配置文件导入到默认配置文件.config中,操作方法很简单。
在终端输入 make socfpga_defconfig
命令来选择厂家提供的基本配置设置,如下图所示
然后就可以使用 menuconfig 命令打开内核配置界面了,输入 make menuconfig
命令打开内核配置界面。
关于内核的详细配置内容,本书不做介绍,这里仅选择几个与 AC501_SoC_GHRD 工程相关的设备驱动的使能方式进行介绍。
在 AC501_SoC_GHRD 工程中,添加了有 UART 串口外设,而 Linux 系统的驱动源码中也已经有对该串口控制器的驱动支持,因此可以通过使能 Linux 系统中的该驱动支持来快速实现对 FPGA 侧添加的 UART IP 的驱动。
另外 Linux 系统还支持 Altera JTAG UART, 为了后续万一用到时不用再重新配置内核,这里也一并使能。
依次进入 Device Drivers > Character devices > Serial drivers 选项中,在 AlteraJTAG UART support、 Altera UART support 和 Altera UART console support 选项前的<>中输入字符“y”以使能该选项。如下图所示
按两下 ESC 键返回上一层。
除了对 UART IP 核的驱动支持, 4.5 版本的 Linux 源码中还提供了对 SPI IP核的支持。因此可以通过使能 Linux 系统中的该驱动支持来快速实现对 FPGA 侧添加的 SPI IP 的驱动
首先进入 Device Drivers 中,在 SPI support 选项前面的[]中输入字符“y”以使能对 SPI 的支持,然后按下键盘回车键进入下一层。 在 Altera SPI Contorller 选项前的<>中输入字符“y”以使能该选项, 如下图所示:
在 AC501_SoC_GHRD 工程中,添加了一个开源的第三方 I2C 控制器“OC_I2C”, 该控制器在 4.5 版本的 Linux 内核中已有驱动支持,因此可以在内核配置中打开对该控制器的驱动编译。
依次进入 Device Drivers > I2C Support > I2C Hardware Bus support 选项中,在 OpenCores I2C Controller 选项前的<>中输入字符“y”以使能该选项。如下图所示:
在 AC501_SoC_GHRD 工程中,添加了有用于图形显示用的 FrameReader控制器,该控制器对应到 Linux 系统中应该为 Framebuffer 属性。 4.5 版本的Linux 源码中已经提供了对该 FremeReader 控制器的驱动支持, 通过使能该驱动,就可以在 AC501-SoC 开发板配套的 5 寸显示屏上显示图形和文字了。
依次进入 Device Drivers >Graphics support > Frame bufferDevices 选项中,先在Support for frame buffer devices选项前的<>中输入字符“y”以使能该选项,然后在Altera VIP Frame Reader framebuffer support 选项前的<>中输入字符“y”以使能该选项。如下图所示
另外,为了支持使用显示屏作为 console 终端,以在显示屏上可以直接登录用户并输入和反馈各种命令信息。可以在 Device Drivers >Graphics support >Console display driver support 选项中, 使能 Framebuffer Console support 选项,这样,当系统开机之后,就会在显示屏上显示登录界面,用户可以通过连接USB 键盘到开发板上以输入各种命令,就像在电脑上使用串口终端操作开发板一样。如下图所示
至此, 针对 AC501_SoC_GHRD 工程的 Linux 内核配置就完成了。连续按下 ESC 间直到弹出保存对话框, 选择 Yes 保存该配置, 如下图所示
配置完成后会将当前配置暂存在.config 文件中, 这是个临时文件。 为了将当前配置保存,以便于日后再次编译内核时候能直接使用本次配置好的内容,可以使用 savedefconfig 命令将当前配置信息存储起来,下次再需要按照此配置编译内核时, 就可以使用该配置文件了。 例如将该配置存储为 ac501_defconfig, 可以使用下述命令:
make savedefconfig && mv defconfig arch/arm/configs/ac501_defconfig
保存完成后,会在 arch/arm/configs/路径下存在一个名为 ac501_defconfig 的文件,如下图所示
这样 ,当下次需要对 ac501 开发板的内核配置进行编译时,输入make ac501_defconfig
命令, 将该配置文件的内容更新到源码根目录的.config 文件中,然后就可以使用 make 命令来按照此配置编译内核了。 当然,也可以使用 make menuconfig
命令来打开配置界面重新修改配置。
输入 make zImage -j4
命令开始编译内核, 编译过程视用户的 PC 性能, 大概耗时 5~20 分钟。编译完成之后, 会生成内核的 zImage 镜像文件, 该文件默认存放在 linux-socfpga/arch/arm/boot 下,如下图所示。
将 zImage 文件拷贝到 AC501-SoC 开发板的 SD 卡中, 拷贝AC501_SoC_GHRD 工程生成的 dtb 文件和 rbf 文件到启动 SD 卡中, 设置MSEL[4:0]=5’b00000,然后启动 AC501-SoC 开发板, 串口中开始打印启动信息。在众多的启动信息中,以下几条较为重要:
1、 内核信息, 在打印 Starting kernel 信息之后的第二行,开始打印内核的详细信息,包括内核版本、编译主机、编译器版本、编译时间, 如下图所示。可以看到,该内核版本为 4.5, 编译主机正是笔者所用 Ubuntu 系统的账户,gcc 交叉编译器为 4.8.3,最能证明该内核就是我们刚刚编译出来的内核的信息就是时间,显示该内核编译时间为 Sun Aug 30 00:05:32 CST 2020, 与上面一张图中显示的内核编译时间相同。
2、 设备驱动加载, 在众多的启动信息之中,有下面三条设备驱动加载信息值得关注。如下图所示,这三条信息详细内容分别为:
第一条,表明识别到了 altvipfb 设备并加载了驱动, 创建的设备名称为 fb0;
第二条,表明识别到了 Altera UART 设备并加载了驱动,创建的设备名称为 ttyAL0;
第三条,表明识别到了 spi_altera 控制器,由于 SPI 的属性是总线而非设备,因此没有创建设备节点
使用 ls 命令查看 dev 目录中的文件,可以看到, fb0 设备和 ttyAL0 设备的存在,如下图所示
如果使用厂家提供的 socfpga_defconfig 配置文件编译得到的内核(AC501-SoC 开发板光盘中已经提供了该内核镜像), 由于没有使能上述驱动,是不会打印这些设备驱动加载信息的, 也不会在/dev 目录下创建设备节点。更不会点亮液晶显示屏。