本篇文章主要讲解嵌入式板卡中Linux系统是如何正确测试、使用的,其中内容包含有U-Boot编译、U-Boot命令和环境变量说明、Linux内核编译、xtra驱动编译、系统信息查询、程序开机自启动说明、NFS使用说明、TFTP使用说明、TFTP NFS的系统启动测试说明、inux设备驱动说明等,其中案例源码部分公开。
此外,本篇文章测试板卡采用创龙科技TL335x-EVM-S开发板,它是一款基于TI Sitara系列AM3352/AM3354/AM3359 ARM Cortex-A8高性能低功耗处理器设计的开发板,其接口资源丰富,引出双路千兆网口、LCD、HDMI、GPMC、CAN等接口,方便用户快速进行产品方案评估与技术预研,应用在通讯管理、数据采集、人机交互、运动控制、智能电力等典型领域。
前 言
本说明文档适用开发环境如下:
Windows开发环境:Windows 7 64bit、Windows 10 64bit
Linux开发环境:Ubuntu 14.04.3 64bit
虚拟机:VMware15.1.0
U-Boot:U-Boot-2017.01
Kernel:Linux-4.9.65、Linux-RT-4.9.65
Linux Processor SDK:ti-processor-sdk-linux-rt-am335x-evm-04.03.00.05
Linux系统软件相关文件在产品资料“4-软件资料Linux”目录下,包括了U-Boot、Kernel、Filesystem和Makesdboot四个文件夹(具体如下表)。系统支持Linux内核和Linux-RT实时内核,默认提供的是Linux内核。如对系统实时性要求较高,可切换为Linux-RT内核。
表 1
U-Boot | image | U-Boot镜像文件 |
---|---|---|
src | U-Boot源码压缩包 | |
U-Boot特性说明文件 | ||
Kernel | image | Linux内核镜像、驱动模块压缩包、设备树文件 |
src | Linux内核源码 | |
Linux内核特性说明文件 | ||
Filesystem | 文件系统压缩包 | |
文件系统特性说明文件 | ||
Makesdboot | 系统启动卡制卡工具包 | |
系统启动卡制卡脚本文件 |
如需使用apt-get命令从网络中安装工具,请先确保网络连接正常。
U-Boot编译
安装、清理U-Boot源码
在Ubuntu中执行如下命令创建U-Boot源码安装目录。
Host# mkdir -p /home/tronlong/AM335x/U-Boot-2017.01
图 1
将产品资料“4-软件资料LinuxU-Bootsrc”目录下的U-Boot源码压缩包文件“u-boot-2017.01-[Git系列号]-[版本号].tar.gz”复制到“/home/tronlong/AM335x/”工作目录下,并执行如下命令将其解压至U-Boot源码安装目录。
Host# cd /home/tronlong/AM335x
Host# tar -zxvf u-boot-2017.01-gfe9f099-v2.3.tar.gz-C U-Boot-2017.01/
图 2
图 3
确保已配置好Linux Processor SDK交叉编译工具链后,进入U-Boot源码安装目录,执行如下命令清理U-Boot源码。
Host# cd U-Boot-2017.01/
Host# make CROSS_COMPILE=arm-linux-gnueabihf- ARCH=arm distclean
图 4
清理命令删除的文件范围从小到大依次为:make clean < make mrproper < make distclean。命令具体解析如下:
表 2
命令参数 | 解析 |
---|---|
CROSS_COMPILE=arm-linux-gnueabihf- | 指定编译所用交叉编译器 |
ARCH=arm | 指定硬件框架为ARM架构 |
make clean | 删除大多数的编译生成文件,但会保留配置文件 |
make mrproper | 删除所有的编译生成文件,同时删除配置文件 |
make distclean | 删除所有的编译生成文件,同时删除配置文件以及各种备份文件和补丁文件,清除最完整 |
配置U-Boot编译选项
执行如下命令对U-Boot编译选项进行配置。
此命令通过U-Boot源码中的“configs/am335x_evm_s_emmcboot_defconfig”文件对U-Boot编译选项进行配置,并保存编译选项配置信息至当前目录新生成的.config文件中。
Host# make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- am335x_evm_s_emmcboot_defconfig
图 5
如需修改U-Boot的编译配置选项,可继续执行“make menuconfig”命令打开图形化配置界面。此命令通过读取新生成的.config文件,以图形界面的方式提供U-Boot编译选项配置查看和修改方法。如无需修改U-Boot编译选项配置,可跳过此步骤。
menuconfig是一套图形化的配置工具,需要ncurses库支持。ncurses库提供了一系列的API函数供调用者生成基于文本的图形界面,因此需要先执行如下命令通过网络安装ncurses库。
Host# sudo apt-get install libncurses5-dev
图 6
执行如下命令启动menuconfig配置界面。
Host# make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig
图 7
图 8
可通过键盘的方向键选中对应菜单栏。在<Select>被选中的情况下,可按Enter键进入子菜单。菜单选项中蓝色高亮的字母代表此菜单选项的快捷键,可在键盘上按下对应的字母快速选中对应的菜单选项。
每个菜单选项前的括号内容表示当前菜单选项的配置状态。选中对应的菜单选项后,按下Y键,会将相应的选项配置编译到U-Boot中,同时菜单选项前面变为< * >。按下N键,不会将相应的选项配置编译到U-Boot中。按下M键,会将相应的选项配置编译为模块,菜单选项前面变为< M >。如需搜索,可按下/键打开搜索框,然后输入要搜索的内容。
配置完毕后,选中<Save>,按Enter键保存配置选项。然后选中<Exit>,按Enter键退出。
编译U-Boot镜像
执行如下命令,通过网络安装U-Boot设备树编译工具device-tree-compiler。
Host# sudo apt-get install device-tree-compiler
Host# sudo apt-get update
图 9
执行如下命令进行U-Boot编译。
Host# make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j 4
图 10
编译完成后会在U-Boot源码根目录下生成U-Boot镜像文件MLO、u-boot.img(如下图所示)。U-Boot启动过程可分第一阶段和第二阶段,其中MLO是启动第一阶段镜像文件,u-boot.img是启动第二阶段镜像文件。
图 11
将编译生成的MLO和u-boot.img文件拷贝到Linux系统启动卡BOOT分区目录,替换Linux系统启动卡BOOT分区目录下原有的对应文件。使用替换U-Boot镜像文件后的Linux系统卡启动系统,U-Boot镜像文件即可生效。
从Linux系统启动卡启动U-Boot
评估板断电,将替换U-Boot镜像文件后的Linux系统启动卡插入评估板Micro SD卡槽,根据评估底板丝印将拨码开关拨为00010(1~5),此档位为SD卡启动模式。
通过Micro USB线连接评估板USB TO UART3(调试串口)到PC机USB端口,然后将评估板上电,串口调试终端将会打印类似下图U-Boot启动信息,说明Linux系统启动卡U-Boot启动成功。
图 12
U-Boot命令和环境变量说明
评估板上电启动后,在U-Boot倒计时结束之前按下空格键进入U-Boot命令行模式,执行help或者?命令,可查看当前U-Boot所支持的命令。
U-Boot> help
图 13
表 3
命令 | 解析 |
---|---|
setenv | 设置或者修改环境变量的值 |
saveenv | 用于保存修改后的环境变量(默认保存到SPI FLASH的MTD2分区) |
env default -f -a | 恢复默认环境变量 |
printenv | 输出当前U-Boot环境变量信息 |
boot | 读取环境变量bootcmd(U-Boot启动的命令集合)来启动Linux系统 |
help或? | 查看当前U-Boot支持的命令 |
执行命令setenv或“env default -f -a”修改的是运行空间中的环境变量值,须使用saveenv命令将修改后的环境变量保存起来。否则U-Boot重启后,将会使用以前的环境变量值。环境变量修改完成后,执行boot命令,即可使用修改后的U-Boot环境变量启动。
U-Boot> env default -f -a
U-Boot> saveenv
U-Boot> boot
图 14
在U-Boot命令行中执行printenv命令可查看环境变量,如下提供主要U-boot环境变量的解析说明。不同版本的U-Boot,环境变量可能会有所不同,内容仅供参考。
/*芯片类型为arm*/
arch=arm
/*mmc启动参数*/
args_mmc=run finduuid;setenv bootargs console=${console} ${optargs} root=PARTUUID=${uuid} rw rootfstype=${mmcrootfstype}
/*串口波特率为115200*/
baudrate=115200
/*板卡系列*/
board=am335x
/*板卡名称*/
board_name=tl335x-evm
/*系统启动时,会先判断环境变量dofastboot是否为1;若为1,则执行fastboot命令。判断boot_fit环境变量是否为1;若为1,则执行update_to_fit命令。否则,系统会采用默认的U-Boot环境变量,并按run mmcboot、run emmc_linux_boot、run_emmc_android_boot的顺序进行启动*/
bootcmd=if test ${boot_fit} -eq 1; then run update_to_fit;fi;run boottestcount; run logo_display; run findfdt; run init_console; if test $bootmode = MMC0; then run envboot; run mmcboot;else run spiboot; fi;
/*U-Boot启动次数*/
bootcount=0
/*启动延时时间,单位:秒*/
bootdelay=1
/*内核镜像、设备树镜像路径*/
bootdir=/boot
/*内核镜像名称*/
bootfile=zImage
/*内核镜像大小*/
bootm_size=0x10000000
/*Linux系统启动卡的启动分区*/
bootpart=0:2
/*调试串口为UART3,波特率为115200n8*/
console=ttyO3,115200n8
/*cpu类型为armv7*/
cpu=armv7
/*扫描SD卡是否已插入,若SD卡中有U-Boot启动脚本,则使用脚本中的U-Boot环境变量启动,否则采用默认的U-Boot环境变量进行启动*/
envboot=mmc dev ${mmcdev}; if mmc rescan; then echo SD/MMC found on device ${mmcdev};if run loadbootscript; then run bootscript;else if run loadbootenv; then echo Loaded env from ${bootenvfile};run importbootenv;fi;if test -n $uenvcmd; then echo Running uenvcmd ...;run uenvcmd;fi;fi;fi;
/*dtb文件读取地址*/
fdt_addr_r=0x88000000
/*dtb文件加载地址*/
fdtaddr=0x88000000
/*dtb文件名,下面的findfdt命令中会根据board_name进行设置*/
fdtfile=undefined
/*根据环境变量board_name设置环境变量fdtfile */
findfdt=setenv fdtfile tl335x-evm.dtb; if test $fdtfile = undefined; then echo WARNING: Could not determine device tree to use; fi;
finduuid=part uuid mmc ${bootpart} uuid
/*查看mmc bootpart分区*/
finduuid=part uuid mmc ${bootpart} uuid
/*内核镜像读取地址*/
kernel_addr_r=0x82000000
/*内核镜像加载地址*/
loadaddr=0x82000000
loadimage=load ${devtype} ${bootpart} ${loadaddr} ${bootdir}/${bootfile}
/*SD卡或eMMC启动时,先再次扫描SD卡或eMMC,确保mmc设备能正常工作后,从mmc设备的系统启动分区中的bootdir目录加载bootfile(zImage内核镜像)。然后运行mmcloados进行加载系统*/
mmcboot=mmc dev ${mmcdev}; setenv devnum ${mmcdev}; setenv devtype mmc; if mmc rescan; then echo SD/MMC found on device ${mmcdev};if run loadimage; then if test ${boot_fit} -eq 1; then run loadfit; else run mmcloados;fi;fi;fi;
/*从第一个mmc设备启动*/
mmcdev=0
mmcloados=run args_mmc; if test ${boot_fdt} = yes || test ${boot_fdt} = try; then if run loadfdt; then bootz ${loadaddr} - ${fdtaddr}; else if test ${boot_fdt} = try; then bootz; else echo WARN: Cannot load the DT; fi; fi; else bootz; fi;
/*引导的rootfs文件系统类型为EXT4格式*/
mmcrootfstype=ext4 rootwait
Linux内核编译
安装、清理内核源码
在Ubuntu中执行如下命令创建内核源码安装目录。
Host# mkdir -p /home/tronlong/AM335x/Kernel/Linux-4.9.65
图 15
将产品资料“4-软件资料LinuxKernelsrc”目录下的内核源码压缩包文件“linux-rt-4.9.65-[Git系列号]-[版本号].tar.gz”复制到“/home/tronlong/AM335x/”工作目录下,并在“/home/tronlong/AM335x/”目录执行如下命令将其解压至内核源码安装目录。
Host# tar -xvf linux-rt-4.9.65-gfc51450-v2.4.tar.gz -C Kernel/Linux-4.9.65/
图 16
确保已配置好Linux Processor SDK交叉编译工具链后,进入内核源码安装目录,执行如下命令清理内核源码。
Host# cd Kernel/Linux-4.9.65/
Host# make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- distclean
图 17
配置内核编译选项
执行如下命令对内核编译选项进行配置。
此命令通过内核源码中的“arch/arm/configs/tisdk_am335x-evm_defconfig”文件对内核编译选项进行配置,并保存编译选项配置信息至当前目录新生成的.config文件中。
Host# make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- tisdk_am335x-evm_defconfig
图 18
我司默认配置的是Linux内核(推荐使用)。如对系统实时性要求较高,则需编译为Linux-RT内核,或需修改内核编译选项配置,可继续执行“make menuconfig”命令打开图形配置界面。此命令通过读取当前目录的.config文件,以图形界面的方式提供内核编译配置查看和修改方法。如无需修改内核编译选项配置,可跳过此步骤。
Host# make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig
图 19
图 20
可通过键盘的方向键选中对应菜单栏。在<Select>被选中的情况下,可按Enter键进入子菜单。菜单选项中蓝色高亮的字母代表此菜单选项的快捷键,可在键盘上按下对应的字母快速选中对应的菜单选项。
每个菜单选项前的括号内容表示当前菜单选项的配置状态。选中对应的菜单选项后,按下Y键,会将相应的选项配置编译到内核中,同时菜单选项前面变为< * >。按下N键,不会将相应的选项配置编译到内核中。按下M键,会将相应的选项配置编译为内核模块,菜单选项前面变为< M >。如需搜索,可按下/键打开搜索框,然后输入要搜索的内容。
在图形配置界面中,进入“Kernel Features -> Preemption Model”路径,选中“Fully Preemptible Kernel (RT)”选项,即可配置为Linux-RT内核,此时菜单选项前面变为( X )。
图 21
配置完毕后,选中<Save>,按Enter键保存配置选项。然后选中<Exit>,按Enter键退出。
编译内核镜像、内核模块
内核编译前,请先执行如下命令从网络安装lzop压缩工具。
Host# sudo apt-get install lzop
图 22
在内核源码安装目录下,执行如下命令编译内核镜像。命令中的“-j 4”是一个编译选项,它指定操作系统使用多少线程去执行编译,可加快编译速度。如不加编译选项,则默认使用单线程进行编译。
Host# make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- zImage -j 4
图 23
首次编译内核耗时较长,大约需要5~10min。编译完成后,将会在内核源码安装目录“arch/arm/boot/”路径下,生成内核镜像文件zImage。
图 24
我司提供的内核镜像、内核模块进行了版本管理,而本地重新配置与编译生成的内核镜像,其版本号将与我司提供的内核镜像版本号不一致。如直接使用本地重新生成的内核镜像替换默认提供的内核镜像,因文件系统中的内核模块与新的内核镜像版本不一致而无法正常安装内核模块。因此,本地首次需重新编译内核模块使其与新的内核镜像版本一致。如本地再次配置与编译生成内核镜像时,则无须同时编译内核模块,即内核模块仅需重新编译一次。
在内核源码安装目录下执行如下命令编译内核模块。
Host# make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- modules -j 4
图 25
编译完成后,将在各驱动源码目录下生成对应的驱动安装文件。例如Watchdog驱动,其源码为“drivers/watchdog/omap_wdt.c”,如已将该驱动配置为内核模块,则编译完成后将会生成“drivers/watchdog/omap_wdt.ko”驱动安装文件。
图 26
编译设备树文件
表 4
设备树(Device Tree) | 一种用来描述硬件资源的数据结构,可描述处理器核心、时钟、中断控制器、IO控制器、SPI控制器、I2C控制器、存储设备等驱动单位。 |
---|---|
*.dts文件 | ASCII文本格式设备树源文件。 |
*.dtsi文件 | 为了减少代码的冗余,设备树将dts文件中的共同部分提炼保存在dtsi文件中,供不同的dts文件使用。 |
*.dtb文件 | 二进制基础设备树文件,由DTC(Device Tree Compiler)工具编译dts文件生成。 |
*.dtbo文件 | 二进制动态设备树文件,由DTC(Device Tree Compiler)工具编译dts文件生成。 |
我司提供的设备树源文件位于内核源码“arch/arm/boot/dts/”目录下,包括了基础设备树文件和动态设备树文件。
基础设备树文件主要描述评估板的基础硬件设备(比如LED、KEY等通用外设),系统启动时自动加载其对应的dtb文件。动态设备树文件主要描述评估板特定驱动单位,在对特定驱动单位进行操作时,需在文件系统下手动加载其对应的dtbo文件。
图 27
表 5
文件类型 | 文件名称 | 说明 |
---|---|---|
基础设备树文件 | tl335x-evm-s-emmc.dts | TL335x-EVM-S评估板(eMMC版本)基础设备树文件 |
tl335x-evm-s-emmc-hdmi.dts | TL335x-EVM-S评估板(eMMC版本) HDMI显示设备树文件 | |
tl335x-usb-device.dts | TL335x-EVM-S评估板的USB DEVICE模式设备树文件 | |
tl335x-evm-s-nandflash.dts | TL335x-EVM-S评估板(NAND FLASH版本)基础设备树文件 | |
tl335x-evm-s-nandflash-hdmi.dts | TL335x-EVM-S评估板(NAND FLASH版本) HDMI显示设备树文件 | |
动态设备树文件 | tl335x-evm-lcd-overlay.dts | TL335x-EVM-S评估板 LCD显示动态设备树文件 |
tl335x-evm-tl3106h-overlay.dts | TL335x-EVM-S评估板 TL3106模块测试动态设备树文件 | |
tl335x-evm-lcd-g121sn01-overlay.dts | TL335x-EVM-S评估板 12.1英寸LVDS显示屏动态设备树文件 |
如设备树文件不作改动,则无须重新编译生成二进制设备树文件,即可使用默认提供的dtb、dtbo文件进行开发。如设备树文件有所改动,则需重新编译生成二进制设备树文件。编译命令格式如下:
dtb设备树文件:make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- *.dtb
dtbo设备树文件:make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- *.dtbo
*代表dts文件名的前缀,命令会根据前缀在内核源码“arch/arm/boot/dts/”目录下找到对应的dts文件进行编译,生成dtb或dtbo文件。
以tl335x-evm-s-emmc.dts、tl335x-evm-lcd-overlay.dts为例,请在内核源码安装目录下,执行如下命令在内核源码目录“arch/arm/boot/dts/”路径中编译生成dtb文件tl335x-evm-s-emmc.dtb和dtbo文件tl335x-evm-lcd-overlay.dtbo。如需编译其他设备树文件,替换命令中对应前缀即可。
Host# make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- tl335x-evm-s-emmc.dtb
Host# make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- tl335x-evm-lcd-overlay.dtbo
图 28
安装镜像到Linux系统启动卡
将重新编译生成的内核镜像zImage复制到Linux系统启动卡rootfs分区boot目录下。
将重新编译生成的基础设备树dtb文件复制到Linux系统启动卡rootfs分区boot目录下。
将重新编译生成的动态设备树dtbo文件复制到Linux系统启动卡rootfs分区“lib/firmware/”目录下。
将Linux系统启动卡通过读卡器插到PC机,并将其成功挂载到Ubuntu系统,本次操作演示的Linux系统启动卡挂载路径为“/media/tronlong/rootfs/”。进入内核源码安装目录,执行如下命令将重新编译生成的内核模块驱动安装.ko文件安装到Linux系统启动卡rootfs分区“lib/modules/<kernel_release>/”目录下的相关路径中。如本地没有使用版本管理工具,<kernel_release>一般为4.9.65-rt23。
Host# sudo make ARCH=arm modules_install INSTALL_MOD_PATH=/media/tronlong/rootfs/
图 29
由于内容篇幅过长,本篇文章分为上中下三章分享,欢迎查阅。