嵌入式linux/鸿蒙开发板(IMX6ULL)开发流程(四)

10 更新(构建) bootloader、内核、文件系统

10.1 准备

Linux平台上有许多开源的嵌入式linux系统构建框架(框架的意思就是工具),这些框架极大的方便了开发者进行嵌入式系统的定制化构建,目前比较常见的有OpenWrt, Buildroot, Yocto,等等。其中Buildroot功能强大,使用简单,而且采用了类似于linux kernel的配置和编译框架,所以受到广大嵌入式开发人员的欢迎。
本章重点介绍使用Buildroot_2019.02LTS版构建文件系统和u-boot, kernel镜像的方法,并从这三个部分入手,描述如何使用Buildroot构建一个适合100ask_imx6ull系列开发板的嵌入式Linux系统
在构建文件系统时,还简要介绍了如何通过Buildroot将QT5图形系统集成到文件系统中, 方便用户后续开发QT5的应用程序。
注意:确保Ubuntu能ping通外网(比如:ping news.qq.com)。确保可以下载源码、配置工具链。

10.2 解压编译bootloader

10.2.1 Bootloader介绍(u-boot)

Bootloader是在操作系统运行之前运行的一段代码,用于引导操作系统。通常每个操作系统都有一组专属的引导加载程序。引导加载程序通常可以通过多种方式引导操作系统内核,还有各种命令用于调试或修改内核运行环境。
U-Boot是一个开源的主引导加载程序,用于引导设备的操作系统内核,并含有多种命令以便调试系统。它适用于多种计算机体系结构,包括68k,ARM,Blackfin,MicroBlaze,MIPS,Nios,SuperH,PPC,RISC-V和x86。
U-boot官网 请点击
源码下载页面 请点击
Git仓库地址 请点击
uboot更多使用讲解请参考页面 请点击
NXP官方uboot源码Git地址: 请点击
注意:我们使用的版本针对板子进行过修改,u-boot官网下载的源码不能直接使用。

10.2.2 编译u-boot镜像

不同的开发板对应不同的配置文件,配置文件位于 u-boot源码的configs/ 目录。
对于IMX6ULL MINI EMMC版,u-boot的编译过程如下(编译uboot前必须先配置好工具链等开发环境)其它步骤和IMX6ULL Pro版保持一样:

book@100ask: ~/100ask_imx6ull-sdk$ cd Uboot-2017.03
book@100ask: ~/100ask_imx6ull_mini-sdk/Uboot-2017.03$ make distclean
book@100ask: ~/100ask_imx6ull_mini-sdk/Uboot-2017.03$ make  mx6ull_14x14_evk_defconfig 
book@100ask: ~/100ask_imx6ull_mini-sdk/Uboot-2017.03$ make

在这里插入图片描述
编译完成后生成的文件如下图所示。
在这里插入图片描述
编译完成之后生成u-boot-dtb.imx,可以用于TF卡启动和EMMC启动。为方便学习,建议优先选择从TF卡启动。
将u-boot-dtb.imx文件拷贝到我们的开发板内,执行如下命令进行更新。

root@100ask:~]# echo 0 > /sys/block/mmcblk1boot0/force_ro     
root@100ask:~]# dd if=u-boot-dtb.imx of=/dev/mmcblk1boot0 bs=512 seek=2 
root@100ask:~]# echo 1 > /sys/block/mmcblk1boot0/force_ro  

10.3编译Linux Kernel

10.3.1 Linux内核介绍

Linux内核(英语:Linux kernel)是一种开源的类Unix操作系统宏内核。整个Linux操作系统家族基于该内核部署在传统计算机平台(如个人计算机和服务器,以Linux发行版的形式)和各种嵌入式平台,如路由器、无线接入点、专用小交换机、机顶盒、FTA接收器、智能电视、数字视频录像机、网络附加存储(NAS)等。工作于平板电脑、智能手机及智能手表的Android操作系统,它的底层操作系统也是Linux。尽管在桌面计算机的占用率较低,但基于Linux的操作系统统治了几乎从移动设备到主机的其他全部领域。实际Linux的发行版Ubuntu,其易用性也逐渐接近Windows。
Linux kernel官网:请点击
linux Kernel维基百科:请点击
在线阅读linux kernel源码:请点击
Git仓库地址: 请点击
更多关于Linux内核资料请参考页面:请点击
NXP官方kernel源码Git仓库地址: 请点击

上述Git仓库是专为100ask_imx6ull系列开发板制定的Linux内核,它有如下特性:
在这里插入图片描述在这里插入图片描述

10.3.2 编译内核镜像

不同的开发板对应不同的配置文件,配置文件位于内核源码arch/arm/configs/目录。

kernel的编译过程如下(编译内核前需要先配置好工具链等一些环境变量):

book@100ask:~/100ask_imx6ull-sdk$ cd Linux-4.9.88
book@100ask:~/100ask_imx6ull_mini-sdk/Linux-4.9.88$ make mrproper
book@100ask:~/100ask_imx6ull_mini-sdk/Linux-4.9.88$ make 100ask_imx6ull_mini_defconfig
book@100ask:~/100ask_imx6ull_mini-sdk/Linux-4.9.88$ make zImage -jN //N表示根据CPU个数,来加速编译系统
book@100ask:~/100ask_imx6ull_mini-sdk/Linux-4.9.88$ make dtbs
book@100ask:~/100ask_imx6ull_mini-sdk/Linux-4.9.88$ cp arch/arm/boot/zImage ~/nfs_rootfs
book@100ask:~/100ask_imx6ull_mini-sdk/Linux-4.9.88$ cp arch/arm/boot/dts/100ask_myir_imx6ull_mini.dtb  ~/nfs_rootfs

编译步骤参考如下,编译完成zImage后才可编译设备树文件。
在这里插入图片描述

编译完成后生成的文件如下图所示
在这里插入图片描述

编译成功后,可以得到这些文件:内核文件arch/arm/boot/zImage,设备树文件arch/arm/boot/100ask_imx6ull_mini.dtb。
把这2个文件复制到/home/book/nfs_rootfs目录下备用。

在这里插入图片描述

10.3.3 编译内核模块

10.3.3.1 编译内核模块

无论是哪个版本的IMX6ULL开发板,编译内核模块的命令是一样的。

进入内核源码目录后,就可以编译内核模块了:

book@100ask:~$ cd  ~/100ask_imx6ull_mini-sdk/Linux-4.9.88/
book@100ask:~/100ask_imx6ull_mini-sdk/Linux-4.9.88$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf-  modules

在这里插入图片描述在这里插入图片描述

10.3.4 安装内核模块到Ubuntu某个目录下备用

可以先把内核模块安装到nfs根文件系统(/home/book/nfs_rootfs为安装目录)。
注意:下面会执行tree命令,如果提示没有该命令,需要执行“sudo apt install tree”命令安装tree工具(前提是Ubuntu能上网)。

执行以下命令:

book@100ask:~$ cd ~/100ask_imx6ull_mini-sdk/Linux-4.9.88
book@100ask:~/100ask_imx6ull_mini-sdk/Linux-4.9.88$ sudo make  ARCH=arm INSTALL_MOD_PATH=/home/book/nfs_rootfs  modules_ins

如下图,把模块安装在nfs所在目录 /home/book/nfs_rootfs/ 目录下:
在这里插入图片描述安装后的的/home/book/nfs_rootfs/目录结构如下图所示:
在这里插入图片描述

10.4 安装内核和模块到开发板上

除了烧写整个系统或更新部分系统内讲解的方法,还有以下方法。
假设:执行上述命令后,在Ubuntu的/home/book/nfs_rootfs目录下已经有了zImage、dtb文件,并且有lib/modules子目录(里面含有各种模块)。

下面,要把这些文件复制到开发板上。

如果你使用的是VMware桥接方式,假设Ubuntu IP为192.168.1.100,在开发板上执行以下命令:

mount -t nfs -o nolock,vers=3 192.168.1.100:/home/book/nfs_rootfs /mnt
cp  /mnt/zImage  /boot
cp  /mnt/*.dtb   /boot
cp  /mnt/lib/modules  /lib  -rfd

最后重启开发板,它就使用新的zImage、dtb、模块了。

10.5 使用Buildroot构建根文件系统

10.5.1 Buildroot简介

制作根文件系统有归多种方法:
① 使用Busybox手工制作
Busybox本身包含了很了Linux命令,但是要编译其他程序的话需要手工下载、编译,如果它需要某些依赖库,你还需要手工下载、编译这些依赖库。
如果想做一个极简的文件系统,可以使用Busybox手工制作。
② 使用Buildroot自动制作
它是一个自动化程序很高的系统,可以在里面配置、编译内核,配置编译u-boot、配置编译根文件系统。在编译某些APP时,它会自动去下载源码、下载它的依赖库,自动编译这些程序。
Buildroot的语法跟一般的Makefile语法类似,很容易掌握。
③ 使用Yocto
NXP、ST等公司的官方开发包是使用Yocto,但是Yocto语法复杂,并且Yocto动辄10GB,下载安装都很困难,普通笔记本编译可能需要2-3天甚至更久,非常不适合初学者(我们不推荐使用yocto构建文件系统)。

基于上述特点,我们选择Buildroot。
Buildroot是一组Makefile和补丁,可简化并自动化地为嵌入式系统构建完整的、可启动的Linux环境(包括bootloader、Linux内核、包含各种APP的文件系统)。Buildroot运行于Linux平台,可以使用交叉编译工具为多个目标板构建嵌入式Linux平台。Buildroot可以自动构建所需的交叉编译工具链,创建根文件系统,编译Linux内核映像,并生成引导加载程序用于目标嵌入式系统,或者它可以执行这些步骤的任何独立组合。例如,可以单独使用已安装的交叉编译工具链,而Buildroot仅创建根文件系统。
参考网址
Buildroot用户手册 请点击
Buildroot源码下载位置 请点击
目录结构的位置以及作用请参考网址请点击
学习更多关于buildroot知识请参考 请点击
百问网提供的Buildroot现支持如下包:

busybox	taglib	libopenh264	qt5_gl_available
skeleton_init_systemd	tremor	libopusenc	qt5_jscore_available
alsa_utils	libarchive	libtheora	qt5
bluez_alsa	zlib	libvpx	qt5_version_latest
faad2	libzlib	libyuv	qt5base
ffmpeg	has_zlib	live555	qt5base_network
flac	libassuan	mediastreamer	qt5base_concurrent
fluidsynth	libgcrypt	x264	qt5base_sql
gstreamer1	libgpg_error	x264_cli	qt5base_sqlite_none
jack2	Libgpgme	libcurl	qt5base_test
lame	Libksba	libnice	qt5base_xml
mjpegtools	Openssl	libnl	qt5base_gui
musepack	libopenssl	libpcap	qt5base_widgets
pulseaudio	sqlite	libshout	qt5base_opengl
twolame	libconfig	libsoup	qt5base_opengl_es2
wavpack	libconfuse	libsrtp	qt5base_opengl_lib
bzip2	libfuse	libtirpc	qt5base_linuxfb
lz4	liblockfile	neon	qt5base_eglfs
xz	bayer2rgb_neon	ortp	qt5base_default_qpa=""
gdb	bullet	rtmpdump	qt5base_printsupport
gdb_server	cairo	bctoolbox	qt5base_fontconfig
gdb_debugger	cairo_pdf	elfutils	qt5base_harfbuzz
gdb_tui	cairo_png	glibmm	qt5base_gif
spidev_test	cairo_svg	libb64	qt5base_jpeg
strace	fontconfg	libbsd	qt5base_png
libtool	freetype	libcap	qt5base_dbus
cifs_utils	gdk_pixbuf	libcroco	qt5base_icu
dosfstools	giflib	libevdev	qt5base_openssl
e2fsprogs	harfbuzz	libffi	qt5base_tslib
mmc_utils	jasper	libglib2	qt5canvas3d
nfs_utils	jpeg	libical	qt5charts
glmark2_flavor_any	kmsxx	libnpth	qt5connectivity
libva_utils	libdrm	libsigc	qt5declarative
fb_test_app	libmediaart	liburcu	qt5declarative_quick
fbdump	libpng	llvm	qt5enginio
fbset	libraw	mpdecimal	qt5graphicaleffects
 	librsvg	protobuf	qt5imageformats
psplash	libsvg	tzdata	qt5location
xkeyboard_config	libsvg_cairo	icu	qt5multimedia
dbus	libva	libfribidi	qt5quickcontrols
evtest	opencv3	ncurses	qt5quickcontrols2
 	has_libegl	pcre	qt5script
gptfdisk	has_libgles	pcre2	qt5scxml
i2c_tools	openjpeg	popt	qt5sensors
iostat	pango	readline	qt5serialbus
linux_serial_test	pipewire	slang	qt5serialport
memtool	pixman	bluez_tools	qt5svg
parted	tiff	bluez5_utils	qt5virtualkeyboard
spi_tools	wayland	bmon	qt5webchannel
sysstat	webp	iperf3	qt5websockets
uboot_tools	dtc	iproute2	qt5xmlpatterns
has_udev	libaio	iw	attr
usbmount	libgudev	lrzsz	keyutils
usbutils	libinput	mii_diag	kmod
luajit	libpciaccess	mjpg_streamer	kmod_tools
python3	libusb	mosquitto	start_stop_daemon
alsa_lib	libxkbcommon	net_tools	swupdate
fdk_aac	mtdev	openobex	systemd
libcodec2	tslib	openssh	util_linux
libcuefile	expat	pppd	myir_hmi_gui
libreplaygain	json_glib	rpcbind	rs485read
libsamplerate	jsoncpp	tcpdump	
libsndfile	libxml2	wget	
libvorbis	bitstream	wireless_tools	
mp4v2	libass	opkg	
opus	libcamera	bash	
portaudio	libmms	gnupg2	
sbc	libmpeg2	gnupg2_gpgv	
speex	libogg	lockfile_progs	

10.5.2 系统特征讲解

我们都做了哪些改进?


我们基于buildroot官方 2020.02长期支持版本进行适配imx6ull开发板,在此基础上针对ST yocto发行系统做了大量的裁剪,在保证最小系统的基础上增加对qt5.12 库的支持,同时也支持opencv3编程 mqtt库 swupdate ota升级等等比较常用的应用,我们也会提供如何在buildroot新增自己的软件包教程,同时源码保存在gitee上,链接地址为 请点击 大家可以在上面提交issue 或者pull request。

什么是init系统服务?


init(为英语:initialization的简写)是 Unix 和 类Unix 系统中用来产生其它所有进程的程序。它以守护进程的方式存在,其进程号为1。Linux系统在引导时加载Linux内核后,便由Linux内核加载init程序,由init程序完成余下的引导过程,比如加载运行级别,加载服务,引导Shell/图形化界面等等。

什么是systemv守护进程?


System V(缩写为SysV)在大多数Linux发行版中使用最广泛,在systemv中,有一个第一个程序在内核加载后运行。该程序称为init。Init做一些事情,其中之一就是加载一系列脚本来启动各种系统服务,例如网络,ssh守护程序等。
System V中的运行级别描述了某些状态。例如:
运行级别0:暂停
运行级别1:单用户模式
运行级别6:重新启动
systemv的问题在于它需要仔细调整。假设您有一个要在启动时运行的网络文件系统(NFS)客户端。在网络正常工作之前运行NFS没有任何意义。因此,您必须确保它等待启动,直到网络已经正常工作为止。Systemv init这样做的方法是为服务启动设置严格的顺序。每个服务都分配有一个优先级编号,init会按优先级顺序启动服务。如果需要确保网络连接后启动服务,则必须手动为服务分配更高的优先级。这必须由某人(通常是软件包维护者)针对计算机上运行的每项服务来完成。
在这里插入图片描述

所有System V初始化脚本都存储在/etc/rc.d/init.d/或/etc/init.d目录中。这些脚本用于控制系统的启动和关闭。通常,您会在这个目录找到启动ssh服务器或网络的脚本,使用/etc/init.d/S50sshd start 开启某个服务或者使用/etc/init.d/S50sshd stop关闭某个服务。

什么是systemd守护进程?


systemd这一名字源于Unix中的一个惯例:在Unix中常以“d”作为系统守护进程(英语:daemon,亦称后台进程)的后缀标识。除此以外,systemd亦是借代英文术语D体系,而这一术语即是用于描述一个人具有快速地适应环境并解决困难的能力。
systemd是Linux电脑操作系统之下的一套中央化系统及设置管理程序(init),包括有守护进程、程序库以及应用软件,由Lennart Poettering带头开发。其开发目标是提供更优秀的框架以表示系统服务间的依赖关系,并依此实现系统初始化时服务的并行启动,同时达到降低Shell的系统开销的效果,最终代替现在常用的System V与BSD风格init程序。目前绝大多数的Linux发行版都已采用systemd代替原来的System V。
在这里插入图片描述

将service(服务)、target(运行模式,类似于运行级别)、mount、timer、snapshot、path、socket、swap等称为Unit。比如,一个auditd服务(就是auditd.service)就是一个Unit,一个multi-user.target运行模式也是一个Unit,其中不同的服务通过 systemctl 来进行统一管理,例如重启一个sshd服务,需要执行 systemctl restart sshd 命令,同样的如果添加一个启动程序需要自己定义一个 service服务才可以。

你可以用我们提供的buildroot做些什么?


快速实现自己的想法,增加自己的应用,学习了解busybox以及各种包是如何编译生成,用于调试内核或者应用程序等等。

10.5.3 扩展学习

深入了解学习更多关于buildroot知识请参考 请点击

buildroot下进入menuconfig包选择配置配置界面

book@100ask:~/100ask_stm32mp157_pro-sdk/Buildroot_2020.02.x$ make menuconfig 

buildroot下单独编译内核

book@100ask:~/100ask_stm32mp157_pro-sdk/Buildroot_2020.02.x$ make  linux-rebuild 

buildroot下进入内核make menuconfig配置选项界面

book@100ask:~/100ask_stm32mp157_pro-sdk/Buildroot_2020.02.x$ make linux-menuconfig

buildroot下单独编译u-boot

book@100ask:~/100ask_stm32mp157_pro-sdk/Buildroot_2020.02.x$ make uboot-rebuild

buildroot下单独编译某个软件包

book@100ask:~/100ask_stm32mp157_pro-sdk/Buildroot_2020.02.x$ make <pkg>-rebuild

buildroot下进入busybox配置界面

book@100ask:~/100ask_stm32mp157_pro-sdk/Buildroot_2020.02.x$ make busybox-menuconfig

buildroot下生成系统sdk,最后生成的目录在output/images/目录下

book@100ask:~/100ask_stm32mp157_pro-sdk/Buildroot_2020.02.x$ make sdk

10.6 构建IMX6ULL MINI EMMC版的根文件系统

10.6.1 配置文件说明

在这里插入图片描述

10.6.2 编译系统

使用以下命令编译出的文件,可以烧写到imx6ull mini emmc版的emmc上或者SD卡上,下面我们以开发板默认出厂系统镜像为例进行说明:

book@100ask:~/100ask_imx6ull_mini-sdk/Buildroot_2020.02.x$ make 		100ask_imx6ull_mini_ddr512m_systemV_qt5_defconfig
book@100ask:~/100ask_imx6ull_mini-sdk/Buildroot_2020.02.x$ make all

注意:机器性能不同,编译时间不同。性能差的电脑,有可能需要等待5 ~ 6个小时。

10.6.3 镜像文件

编译成功后文件输出路径为 output/images

在这里插入图片描述

可以参考章节《烧写整个系统或更新部分系统》把上面编译出来的emmc.img、zImage、u-boot-dtb.imx、100ask_imx6ull_mini.dtb等文件烧写到 Flash上。
这儿得参考一下视频了。怎么把最新编译的文件拖拽出来,并且放在烧写工具的file目录内。最后把文件烧录进开发板。

深入了解学习更多关于buildroot知识请参考 请点击

10.7开发板使用NFS根文件系统

注意:所谓根文件系统就是类似Windows的C盘,里面存放有必须的APP、库文件、配置文件。通过NFS可以把Ubuntu的某个目录,当作板子的“C盘”──Linux中称之为根文件系统。

Buildroot编译完成之后生成的rootfs.tar.bz2,可以解压之后放到NFS服务器上作为NFS ROOT文件系统供开发板使用。使用NFS文件系统,便于程序的开发调试。所谓NFS服务器,就是我们在VMWare上运行的Ubuntu。
使用NFS根文件文件系统之前时,我们一般还会在u-boot使用tftpboot命令从Ubuntu或Windows中下载内核文件zImage和设备树文件,所以:使用VMware桥接网络时:Ubuntu上既要配置NFS服务,也要配置TFTP服务。
对于Ubuntu,如果你按照《安装Ubuntu软件》章节来安装过Ubuntu的软件,那么NSF和TFTP服务都安装好了。
也可以手工安装这些服务,请参考《在Ubuntu中安装、配置NFS》章节安装NFS服务,参考《Ubuntu安装TFTP服务》章节安装TFTP服务。

10.7.1 准备好文件

使用NFS根文件系统时,涉及3个文件:zImage、设备树(比如100ask_imx6ull-14x14.dtb)、rootfs.tar.bz2(解压到Ubuntu某个目录,比如/home/book/nfs_rootfs)。
在U-Boot中通过tftpboot命令从Ubuntu/Windows中下载内核文件zImagen、100ask_imx6ull-14x14.dtb,设置Uboot启动参数使用Ubuntu的某个目录(比如/home/book/nfs_rootfs)作为根文件系统。

拷贝内核和设备树文件到tftp目录


如果使用VMware桥接网络,将出厂镜像或者自行编译的zImage和设备树文件100ask_imx6ull-14x14.dtb,拷贝到Ubuntu的 /home/book/tftpboot 目录。

把根文件系统压缩包解压到NFS目录


把使用buildroot构建得到的根文件系统rootfs.tar.bz2(在buildroot系统output/images目录下),复制、解压到Ubuntu的/etc/exports文件中指定的目录里,即复制到/home/book/nfs_rootfs目录下,并解压(注意:解压时要用sudo):

book@100ask:~/100ask_imx6ull-sdk/Buildroot_2020.02.x/output/images$ cp -rf  rootfs.tar.bz2  ~/nfs_rootfs/
book@100ask:~/100ask_imx6ull-sdk/Buildroot_2020.02.x/output/images$ cd ~/nfs_rootfs
book@100ask:~/nfs_rootfs$ sudo tar  xjf  rootfs.tar.bz2 

10.7.2 进入uboot界面

使用mobaxterm工具打开开发板串口,此时将开发板上电,在打印u-boot时按下任意键进入uboot界面。
在这里插入图片描述

对于IMX6ULL MINI EMMC版,可以进入uboot 使用dhcp 命令获取IP,如果无法动态获取IP可以通过参考下图使用 reset命令来重启系统,重启系统后会提示发现Net设备,此时就可以继续执行tftp命令和nfs挂载命令启动系统。

在这里插入图片描述

10.7.2.1 测试开发板与Ubuntu/Windows是否联通

查看Ubuntu系统IP地址,如下图所示在Ubuntu系统终端里使用 ifconfig查看所有网络设备的信息,获取到当前网卡设备的IP地址为 192.168.1.244 (也就意味着改IP地址的网段是192.168.1.1)

在这里插入图片描述

先在u-boot中设置开发板IP为192.168.1.112,然后在u-boot中使用ping命令测试开发板与Ubuntu系统是否连通(出现“alive”就表示联通):命令如下:

=> setenv ipaddr 192.168.1.112
=> ping 192.168.1.224	

如果提示 host is alive 就表示开发板和Ubuntu系统可以互通,截图示例如下所示。

10.7.2.2 使用网络启动文件系统

注意:Uboot只能使用eth0,网线必须接入eth0,如下:
在这里插入图片描述

先在Ubuntu的TFTP目录中放入zImage和设备树文件,再在/home/book/nfs_rootfs目录下解压好根文件系统。
然后在U-Boot控制台执行以下命令启动单板,假设Ubuntu IP是192.168.1.224:

=> setenv serverip 192.168.1.224     //设置服务器的IP地址,这里指的是Ubuntu主机IP
=> setenv ipaddr 192.168.1.112		 //设置开发板的IP地址。
=> setenv nfsroot /home/book/nfs_rootfs   //设置nfs文件系统所在目录。
=> run netboot			//设置完成后,运行网络启动系统命令

在这里插入图片描述

11.开发板的第1个APP实验

11.1获取程序

请按上一章节使用GIT下载源码、使用repo下载工具链,并配置了交叉编译工具链。
从Git仓库驱动源码相关文件,在Ubuntu终端上执行如下命令。

git  clone  https://e.coding.net/weidongshan/01_all_series_quickstart.git

代码获取示意图如下所示。
在这里插入图片描述

使用GIT下载所有源码后,本节源码位于如下目录:

01_all_series_quickstart\
	04_嵌入式Linux应用开发基础知识\source\01_hello

注意:如果已经使用GTI下载过源码,就不需要重复下载了,否则会有如下图提示:
在这里插入图片描述

hello.c的源码如下:


01 #include <stdio.h>
02
03 /* 执行命令: ./hello weidongshan
04  * argc = 2
05  * argv[0] = ./hello
06  * argv[1] = weidongshan
07  */
08
09 int main(int argc, char **argv)
10 {
    
    
11      if (argc >= 2)
12              printf("Hello, %s!\n", argv[1]);
13      else
14              printf("Hello, world!\n");
15      return 0;
16 }
17

11.2 安装开发环境

假设你已经在Ubuntu中下载了源码、设置了交叉编译工具链。前面章节都已经提过。

11.3 编译程序

在Ubuntu中可以执行以下命令编译、执行:

$ gcc -o hello hello.c
$ ./hello
Hello, world!
$ ./hello weidongshan
Hello, weidongshan!

上述命令编译得到的可执行程序hello可以在Ubuntu中运行,但是如果把它放到ARM板子上去,它是无法执行的。因为它是使用gcc编译的,是给PC机编译的,里面的机器指令是x86的。
我们要想给ARM板编译出hello程序,需要使用交叉编译工具链,比如:

$ arm-buildroot-linux-gnueabihf-gcc -o hello hello.c

这样编译出来的hello程序才可以在ARM板子上运行。
先把编译生成的 hello 文件拷贝到Ubuntu nfs服务目录下,备用:

$ cp  hello   /home/book/nfs_rootfs

11.4 上传程序到开发板并运行

开发板启动后通过nfs挂载Ubuntu目录的方式,将相应的文件拷贝到开发板上。

如果你使用的是VMware桥接方式,假设Ubuntu IP为192.168.1.100,在开发板上执行以下命令:

[root@imx6ull:~]# mount -t nfs -o nolock,vers=3 192.168.1.100:/home/book/nfs_rootfs /mnt
[root@imx6ull:~]# cp  /mnt/hello  ./hello

最后,执行如下操作添加可执行权限,并运行它:

[root@imx6ull:~]# chmod +x hello
[root@imx6ull:~]# ./hello

12.开发板的第1个驱动实验

12.1 前提

请按前面第八章使用GIT下载源码、使用repo下载工具链,并配置了交叉编译工具链。

为什么编译驱动程序之前要先编译内核?
① 驱动程序要用到内核文件:
比如驱动程序中这样包含头文件:#include <asm/io.h>,其中的asm是一个链接文件,指向asm-arm或asm-mips,这需要先配置、编译内核才会生成asm这个链接文件。

② 编译驱动时用的内核、开发板上运行到内核,要一致:
开发板上运行到内核是出厂时烧录的,你编译驱动时用到内核是你自己编译的,这两个内核不一致时会导致一些问题。
所以我们编译驱动程序前,要把自己编译出来到内核放到板子上去,替代原来的内核。

③ 更换板子上的内核后,板子上的其他驱动也要更换:
板子使用新编译出来的内核时,板子上原来的其他驱动也要更换为新编译出来的。

所以在编译我们自己的第1个驱动程序之前,要先编译内核、模块,并且放到板子上去。

12.2 获取led驱动源码

从Git仓库驱动源码相关文件,在Ubuntu终端上执行如下命令。

git  clone  https://e.coding.net/weidongshan/01_all_series_quickstart.git

代码获取示意图如下所示。
在这里插入图片描述

使用GIT获取到源码后,可查看本节源码所在目录,目录位置如下:

01_all_series_quickstart/05_嵌入式Linux驱动开发基础知识 \
/source/02_led_drv/02_led_drv_for_boards/100ask_imx6ull_src_bin

12.3 编译内核镜像

不同的开发板对应不同的配置文件,配置文件位于内核源码arch/arm/configs/目录。
IMX6ULL MINI EMMC版
kernel的编译过程如下(编译内核前需要先配置好工具链等一些环境变量):

book@100ask:~/100ask_imx6ull_mini-sdk/Linux-4.9.88$ make mrproper
book@100ask:~/100ask_imx6ull_mini-sdk/Linux-4.9.88$ make 100ask_imx6ull_mini_defconfig
book@100ask:~/100ask_imx6ull_mini-sdk/Linux-4.9.88$ make zImage -jN //N表示根据CPU个数,来加速编译系统
book@100ask:~/100ask_imx6ull_mini-sdk/Linux-4.9.88$ make dtbs
book@100ask:~/100ask_imx6ull_mini-sdk/Linux-4.9.88$ cp arch/arm/boot/zImage ~/nfs_rootfs
book@100ask:~/100ask_imx6ull_mini-sdk/Linux-4.9.88$ cp arch/arm/boot/dts	/100ask_myir_imx6ull_mini.dtb  ~/nfs_rootfs

编译成功后,可以得到这些文件:内核文件arch/arm/boot/zImage,设备树文件arch/arm/boot/100ask_imx6ull_mini.dtb。
把这2个文件复制到/home/book/nfs_rootfs目录下备用。
在这里插入图片描述

12.4 编译安装内核模块

12.4.1 编译内核模块

IMX6ULL MINI EMMC版
进入内核源码目录后,就可以编译内核模块了:

book@100ask:~$ cd  ~/100ask_imx6ull_mini-sdk/Linux-4.9.88/
book@100ask:~/100ask_imx6ull_mini-sdk/Linux-4.9.88$ make ARCH=arm CROSS_COMPILE=arm-buildroot-linux-gnueabihf- modules

在这里插入图片描述

12.4.2 安装内核模块到Ubuntu某个目录下备用

可以先把内核模块安装到nfs根文件系统(/home/book/nfs_rootfs为安装目录)。
注意:下面会执行tree命令,如果提示没有该命令,需要执行“sudo apt install tree”命令安装tree工具(前提是Ubuntu能上网)。

IMX6ULL MINI EMMC版
执行以下命令:

book@100ask:~$ cd ~/100ask_imx6ull_mini-sdk/Linux-4.9.88
book@100ask:~/100ask_imx6ull_mini-sdk/Linux-4.9.88$ sudo make  ARCH=arm INSTALL_MOD_PATH=/home/book/nfs_rootfs  modules_ins

在这里插入图片描述安装后的的/home/book/nfs_rootfs/目录结构如下图所示:
在这里插入图片描述

12.5 安装内核和模块到开发板上

注意:很多种更新开发板文件的方法,开发过程中最常用的是NFS。
假设:执行上述命令后,在Ubuntu的/home/book/nfs_rootfs目录下已经有了zImage、dtb文件,并且有lib/modules子目录(里面含有各种模块)。
下面,要把这些文件复制到开发板上。
如果你使用的是VMware桥接方式,假设Ubuntu IP为192.168.1.100,在开发板上执行以下命令:

mount -t nfs -o nolock,vers=3 192.168.1.100:/home/book/nfs_rootfs /mnt
cp  /mnt/zImage  /boot
cp  /mnt/*.dtb   /boot
cp  /mnt/lib/modules  /lib  -rfd

最后重启开发板,它就使用新的zImage、dtb、模块了。

12.6 编译led模块

注意:编译驱动程序前,需要先编译内核,因为驱动程序要用到内核中的一些文件。
注意:安装驱动程序前,需要先更新内核,就是把你编译出来的zImage放到开发板上去并重启。否则安装你新编译的驱动时,内核会提示如下错误:你的驱动会污染(taint)内核,版本不匹配不允许使用某些函数。
注意:编译内核,所以你要复制的是(参考第二篇)

/home/book/100ask_imx6ull-sdk/Linux-4.9.88/arch/arm/boot/zImage。

注意:如果要使用Buildroot目录中这个output/images/zImage文件时,驱动程序Makefile中要指定KERN_DIR为如下目录:

KERN_DIR = /home/book/100ask_imx6ull-sdk/Buildroot_2019.02/output/build/linux-origin_master

不更新内核时,会出现类似如下错误:

在这里插入图片描述

你当然可以强行安装驱动程序,比如使用“insmod -f hello_drv.ko”这样的命令,它会提示说“内核已经被污染了”,但是不影响学习、不影响使用,如下:
在这里插入图片描述

如果不想看到这些提示污染的信息,就需要把在Ubuntu上编译出来的zImage复制到开发板的/boot目录下,并且把Ubuntu上编译出来的各种模块复制到开发板的/lib/modules目录下。
之所以也要更新/lib/modules目录,是你更新了zImage,它就跟/lib/modules下的驱动不匹配了,所以/lib/modules也要用新编译出来的。

注意:编译led模块之前,先按上一小节设置交叉编译工具链,编译内核,把内核zImage和其他模块放到开发板上。

然后进入如下目录,修改Makefile文件KERN_DIR为自己的内核所在路径:

01_all_series_quickstart/05_嵌入式Linux驱动开发基础知识 \
/source/02_led_drv/02_led_drv_for_boards/100ask_imx6ull_src_bin

如下图红框所示,我的内核源码所在目录为 /home/book/100ask_imx6ull-sdk/Linux-4.9.88 (默认目录),如果你的内核源码不在此目录则根据你的实际情况进行修改。
在这里插入图片描述

修改完内核所在目录后,就可以编译led模块驱动了,如下图 红框1 所示,执行 make all命令就可以编译,编译完成后会生成 100ask_led.ko ledtest 两个文件。

在这里插入图片描述

此时,我们可以把这两个文件拷贝到 Ubuntu nfs服务 目录下,备用:

cp  100ask_led.ko   ledtest   ~/nfs_rootfs

12.7 开发板安装驱动模块

12.7.1 下载编译好的内核镜像和驱动模块到开发板

开发板启动后通过nfs挂载Ubuntu目录的方式,将相应的文件拷贝到开发板内。
如果你使用的是VMware桥接方式,假设Ubuntu IP为192.168.1.100,在开发板上执行以下命令:

[root@imx6ull:~]# mount -t nfs -o nolock,vers=3 192.168.1.100:/home/book/nfs_rootfs /mnt
[root@imx6ull:~]# cp  /mnt/100ask_led.ko   ./
[root@imx6ull:~]# cp  /mnt/ledtest        ./

12.7.2 关闭系统默认cpu状态灯

可能开发板上的led灯已被设置为 CPU状态灯(可以看到绿色LED在闪),我们需要将其关闭,才可以使用我们的驱动对其进行操作,关闭方法如下所示:

[root@imx6ull:~]# echo none >  /sys/class/leds/cpu/trigger

我们后面出厂的开发板,已经把CPU状态灯禁止了,所以上述命令可能出错:这没影响。

12.7.3 安装驱动模块

在开发板串口终端上执行如下命令,即可安装相应的驱动模块。

[root@imx6ull:~]# insmod 100ask_led.ko

安装完成后可以执行lsmod 命令来查看是否安装成功。
在这里插入图片描述

12.8 执行测试程序

驱动模块安装成功后,执行先前编译好的测试程序,来控制led灯的状态,如下图所示,操作led灯时可同时观察开发板串口旁的灯是否有亮灭的变化。

[root@imx6ull:~]# chmod  +x  ./ledtest
[root@imx6ull:~]# ./ledtest
Usage: ./ledtest <dev> <on | off>
[root@imx6ull:~]# ./ledtest /dev/100ask_led0 on    //打开led0灯
[root@imx6ull:~]# ./ledtest /dev/100ask_led0 off	//关闭led0灯

Guess you like

Origin blog.csdn.net/weixin_45840087/article/details/121342960