【SoC FPGA学习】十三、编译嵌入式 Linux 系统内核

上一节,是使用小梅哥编译配置好的内核,所以我们配置好设备树之后就可以在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 下的工具之外,还有下列好处:

  • 一台电脑可以同时存放多台虚拟机,这样就可以存在多个不同版本的Linux 系统;
  • 在硬件允许的情况下,甚至可以同时运行多台虚拟机;
  • 安装好的虚拟机可以任意复制和拷贝,方便在不同电脑之间迁移和扩散。

安装好虚拟机后,需要安装以下32位必要的支持库

sudo apt install libstdc++6
sudo apt install lib32stdc++6
sudo apt install lib32z1

二、 获取 Intel SOC FPGA 的 Linux 源码

要编译嵌入式 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 集成开发环境。在宿主机上编写和编译代码,通过串口、网口或者硬件调试器将程序下载到目标系统里面运行,系统示意图如下图所示。

【SoC FPGA学习】十三、编译嵌入式 Linux 系统内核_第1张图片
所谓的交叉编译,就是在宿主机平台上使用某种特定的交叉编译器,为某种与宿主机不同平台的目标系统编译程序,得到的程序在目标系统上运行而非在宿主机本地运行。这里的平台包含两层含义:一是核心处理器的架构,二是所运行的系统,这样,交叉编译有 3 种情形:

  • 目标系统与宿主机处理器相同,运行不同的系统;
  • 目标系统与宿主机处理器不同,运行相同的系统;
  • 目标系统与宿主机处理器不同,运行不同的系统。

实际上,在 PC 上进行非 Linux 的嵌入式开发,哪怕使用 IDE 集成环境如 Keil、 ADS、 Realview,都是交叉编译和调试的过程,只是 IDE 工具隐藏了细节,没有明确提出这个概念而已。

交叉编译器是在宿主机上运行的编译器,但是编译后得到的二进制程序却不能在宿主机上运行,而只能在目标机上运行。交叉编译器命名方式一般遵循“ 处理器-系统-gcc”这样的规则,一般通过名称便可以知道交叉编译器的功能。例如下列交叉编译器:

  • arm-none-eabi-gcc,表示目标处理器是 ARM,不运行操作系统,仅运行前后台程序;
  • arm-uclinuxeabi-gcc,表示目标处理器是 ARM,运行 uClinux 操作系统;
  • arm-none-linux-gnueabi-gcc,表示目标处理器是 ARM,运行 Linux 操作系统;
  • mips-linux-gnu-gcc,表示目标处理器是 MIPS,运行 Linux 操作系统。进行 ARM Linux 开发,通常选择 arm-linux-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后如下图所示:

【SoC FPGA学习】十三、编译嵌入式 Linux 系统内核_第2张图片

四、配置编译Linux内核

对内核进行正确配置后,才能进行编译。配置不当的内核,很有可能编译出错,或者不能正确运行。

4.1、快速配置内核

进入 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

【SoC FPGA学习】十三、编译嵌入式 Linux 系统内核_第3张图片
基于 Ncurses 的 Linux 内核配置界面不支持鼠标操作,必须用键盘操作。基本操作方法:

  • 通过键盘的方向键移动光标,选中的子菜单或者菜单项高亮;
  • 按 TAB 键实现光标在菜单区和功能区切换;
  • 子菜单或者选项高亮,将光标移功能区选中回车:
  • 如果是子菜单,按回车进入子菜单;
  • 如果是菜单选项, 按空格可以改变选项的值:
  • 对于 bool 型选项, [*]表示选中, [ ]表示未选中
  • 对于 tristate 型选项, <*>表示静态编译, 表示编译为模块,< >表示未选中。
  • 对于 int、 hex 和 string 类型选项,按回车进入编辑菜单。
  • 连按两次 ESC 或者选中回车,将退回到上一级菜单;
  • 按斜线( /)可启用搜索功能,填入关键字后可搜索全部菜单内容
  • 配置完毕,将光标移动到配置界面末尾,选中“ Save an AlternateConfiguration File”后回车,保存当前内核配置,默认配置文件名为.config.

在 Linux 系统源码的 arch/arm/configs 目录下,存放着很多处理器的内核配置文件, 这些一般由处理器厂家提供,方便用户根据自己的需求在对应的配置文件上进行简单的修改,以得到用户自定义的系统,因为从 0 开始配置一个适用的内核,不仅工作量巨大,而且很容易出错。

对于 Intel 的 SoC FPGA 芯片, Linux 源码中已经提供好了一个名为socfpga_defconfig 的配置文件,我们对内核的配置和修改,建议基于此配置文件进行,因此在进行配置前,需要先将该配置文件导入到默认配置文件.config中,操作方法很简单。

在终端输入 make socfpga_defconfig 命令来选择厂家提供的基本配置设置,如下图所示

在这里插入图片描述
然后就可以使用 menuconfig 命令打开内核配置界面了,输入 make menuconfig 命令打开内核配置界面。

关于内核的详细配置内容,本书不做介绍,这里仅选择几个与 AC501_SoC_GHRD 工程相关的设备驱动的使能方式进行介绍。

4.1.1、使能 Altera UART 驱动

在 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”以使能该选项。如下图所示

【SoC FPGA学习】十三、编译嵌入式 Linux 系统内核_第4张图片

按两下 ESC 键返回上一层。

4.1.2、使能 Altera SPI 驱动

除了对 UART IP 核的驱动支持, 4.5 版本的 Linux 源码中还提供了对 SPI IP核的支持。因此可以通过使能 Linux 系统中的该驱动支持来快速实现对 FPGA 侧添加的 SPI IP 的驱动

首先进入 Device Drivers 中,在 SPI support 选项前面的[]中输入字符“y”以使能对 SPI 的支持,然后按下键盘回车键进入下一层。 在 Altera SPI Contorller 选项前的<>中输入字符“y”以使能该选项, 如下图所示:

【SoC FPGA学习】十三、编译嵌入式 Linux 系统内核_第5张图片

【SoC FPGA学习】十三、编译嵌入式 Linux 系统内核_第6张图片

4.1.3、使能 OC_I2C 控制器驱动

在 AC501_SoC_GHRD 工程中,添加了一个开源的第三方 I2C 控制器“OC_I2C”, 该控制器在 4.5 版本的 Linux 内核中已有驱动支持,因此可以在内核配置中打开对该控制器的驱动编译。

依次进入 Device Drivers > I2C Support > I2C Hardware Bus support 选项中,在 OpenCores I2C Controller 选项前的<>中输入字符“y”以使能该选项。如下图所示:

【SoC FPGA学习】十三、编译嵌入式 Linux 系统内核_第7张图片

4.1.4、使能 Framereader 驱动

在 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”以使能该选项。如下图所示

【SoC FPGA学习】十三、编译嵌入式 Linux 系统内核_第8张图片
另外,为了支持使用显示屏作为 console 终端,以在显示屏上可以直接登录用户并输入和反馈各种命令信息。可以在 Device Drivers >Graphics support >Console display driver support 选项中, 使能 Framebuffer Console support 选项,这样,当系统开机之后,就会在显示屏上显示登录界面,用户可以通过连接USB 键盘到开发板上以输入各种命令,就像在电脑上使用串口终端操作开发板一样。如下图所示

【SoC FPGA学习】十三、编译嵌入式 Linux 系统内核_第9张图片
至此, 针对 AC501_SoC_GHRD 工程的 Linux 内核配置就完成了。连续按下 ESC 间直到弹出保存对话框, 选择 Yes 保存该配置, 如下图所示

【SoC FPGA学习】十三、编译嵌入式 Linux 系统内核_第10张图片

4.2、保存内核配置文件

配置完成后会将当前配置暂存在.config 文件中, 这是个临时文件。 为了将当前配置保存,以便于日后再次编译内核时候能直接使用本次配置好的内容,可以使用 savedefconfig 命令将当前配置信息存储起来,下次再需要按照此配置编译内核时, 就可以使用该配置文件了。 例如将该配置存储为 ac501_defconfig, 可以使用下述命令:

make savedefconfig && mv defconfig arch/arm/configs/ac501_defconfig

保存完成后,会在 arch/arm/configs/路径下存在一个名为 ac501_defconfig 的文件,如下图所示
【SoC FPGA学习】十三、编译嵌入式 Linux 系统内核_第11张图片

这样 ,当下次需要对 ac501 开发板的内核配置进行编译时,输入make ac501_defconfig 命令, 将该配置文件的内容更新到源码根目录的.config 文件中,然后就可以使用 make 命令来按照此配置编译内核了。 当然,也可以使用 make menuconfig 命令来打开配置界面重新修改配置。

4.3、编译内核

输入 make zImage -j4 命令开始编译内核, 编译过程视用户的 PC 性能, 大概耗时 5~20 分钟。编译完成之后, 会生成内核的 zImage 镜像文件, 该文件默认存放在 linux-socfpga/arch/arm/boot 下,如下图所示。

【SoC FPGA学习】十三、编译嵌入式 Linux 系统内核_第12张图片

五、使用内核启动开发板

将 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、 设备驱动加载, 在众多的启动信息之中,有下面三条设备驱动加载信息值得关注。如下图所示,这三条信息详细内容分别为:

【SoC FPGA学习】十三、编译嵌入式 Linux 系统内核_第13张图片

  • 1、[ 0.167064] altvipfb ff200100.vip: fb0: altvipfb frame buffer device at 0x1ee00000+0x177000
  • 2、[ 0.741325] ff200060.serial: ttyAL0 at MMIO 0xff200060 (irq = 20, base_baud = 3125000) is a Altera UART
    [ 0.751001] ff200020.serial: ttyAL1 at MMIO 0xff200020 (irq = 21, base_baud = 3125000) is a Altera UART
  • 3、[ 0.766719] spi_altera ff200040.spi: base e0a58040, irq 22

第一条,表明识别到了 altvipfb 设备并加载了驱动, 创建的设备名称为 fb0;
第二条,表明识别到了 Altera UART 设备并加载了驱动,创建的设备名称为 ttyAL0;
第三条,表明识别到了 spi_altera 控制器,由于 SPI 的属性是总线而非设备,因此没有创建设备节点

使用 ls 命令查看 dev 目录中的文件,可以看到, fb0 设备和 ttyAL0 设备的存在,如下图所示

【SoC FPGA学习】十三、编译嵌入式 Linux 系统内核_第14张图片

如果使用厂家提供的 socfpga_defconfig 配置文件编译得到的内核(AC501-SoC 开发板光盘中已经提供了该内核镜像), 由于没有使能上述驱动,是不会打印这些设备驱动加载信息的, 也不会在/dev 目录下创建设备节点。更不会点亮液晶显示屏。

你可能感兴趣的:(#,SoC,FPGA学习之Cyclone,V)