1. 驱动章节实验环境搭建¶
本章的主要目的是搭建驱动章节所需的实验环境,后续章节将不在实验环境搭建上耗费太多的版面, 而是主要讲解设备驱动的原理。 本小节内容涉及的知识点较多,需要有一定的内核基础才可理解相关内容,若不理解部分知识点,跳过即可,可等到接触到相关知识再回头学习。
首先我们要明白程序最终是运行在板卡上,可以在板卡上编译或者在pc上使用交叉编译器进行编译, 需要下载内核源码或对应内核的头文件(Kernel Headers), 之后编译源码、编译驱动模块以及设备树等,最终将驱动模块和设备树拷贝到开发板上运行。
下方为笔者的开发环境示意图。
1 2 3 4 | 编程环境 编译环境 运行环境
PC(i5) SSH 服务器(E5) NFS 鲁班猫板卡
Windows10 ────────── Ubuntu20.04 ────────── Ubuntu22.04
VSCode
|
程序最终是运行在板卡上的,但编译环境不一定是板卡,这就涉及了编译结果的 文件传输
;板卡运行环境为arm64架构,而编译环境一般不是这架构,这就涉及了 交叉编译环境搭建
;
笔者使用的环境是PC,而服务器不在身边,这就需要 远程便携开发
。
如果您没有服务器,也没关系,可以用VMWare或者VirtualBox搭建个Ubuntu20.04虚拟机,也可以直接装双系统,这部分内容这里就不详细介绍了。
下面是用户普遍会用到的开发环境示意图。
1 2 3 4 | 编程环境 编程/编译环境 运行环境
PC 虚拟机 NFS 鲁班猫板卡
Windows10 ────────── Ubuntu20.04 ────────── Ubuntu22.04
VSCode VSCode
|
其中多数人可能会选择在虚拟机进行编程和编译,这也是可以的。
另外,驱动模块是具有独立功能的程序,它可以被单独编译,但不能独立运行, 在运行时它被链接到内核作为内核的一部分在内核空间运行。 也因此想要我们写的内核模块在某个版本的内核上运行,那么就必须在该内核版本上编译它。
1.1. 搭建编译环境¶
由于pc虚拟机或者服务器性能远远强于板卡,一般建议在虚拟机或者服务器上编译,在PC上可以使用VirtualBox或者VMWare,搭建ubuntu虚拟机,建议使用Ubuntu20.04或者ubuntu22.04版本。
在pc虚拟机或者服务器安装相关库和工具,执行以下命令:
#更新数据库并安装软件
sudo apt update
sudo apt install gcc make git bc libssl-dev liblz4-tool device-tree-compiler bison flex u-boot-tools gcc-aarch64-linux-gnu
#查看aarch64-linux-gnu-gcc版本
aarch64-linux-gnu-gcc -v
注意
aarch64-linux-gnu-gcc版本不能太低,太低可能会导致后续编译内核时报错。
1.1.1. 交叉编译器工具包¶
交叉编译器是后续编译内核时会用到的工具,该工具的选择会直接影响内核编译的结果。虽然上述已经通过 apt install gcc-aarch64-linux-gnu
下载了,但有可能存在安装的gcc-aarch64-linux-gnu交叉编译器版本太低等问题导致内核编译失败的问题。
1.1.2. 野火官方推荐的编译器¶
野火官方推荐的是gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu版本的编译工具链。
mkdir gcc-linaro && cd gcc-linaro
#获取编译工具链
git clone https://github.com/LubanCat/gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu.git
#修改~/.bashrc文件,永久保存环境变量
vim ~/.bashrc
#将下面的环境变量放在文件末尾,需要根据实际指定编译工具链的绝对路径
export PATH=/root/gcc-linaro/gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu/bin:$PATH
#重新加载配置
source ~/.bashrc
#查看编译工具链,如果COLLECT_LTO_WRAPPER变量为指定的路径,即配置成功
aarch64-none-linux-gnu-gcc -v
注意
注意10.3版本的编译器名字为aarch64-none-linux-gnu-,往后章节均使用aarch64-linux-gnu-,如果使用10.3版本编译器请自行修改名称,后续不重复说明
1.1.3. 其他版本编译器¶
不同版本的交叉编译的工具包,可从官网下载: https://mirrors.ustc.edu.cn/armbian-dl/_toolchain/
1.2. 获取内核源码¶
板卡使用的内核版本,可以使用命令 uname -a
查看。
获取内核源码,建议直接git克隆野火官方提供的内核源码,或者下载Lubancat-SDK源码,SDK源码中包含内核源码。
1.2.1. 直接克隆野火官方提供的内核源码¶
创建SDK文件夹,以H618为例:
mkdir LubanCat_H618_SDK && cd LubanCat_H618_SDK/
H618系列板卡用户执行以下命令获取内核源码:
#GitHub获取,-b参数指定linux-5.4.125分支
git clone -b linux-5.4.125 https://github.com/LubanCat/kernel-allwinner.git
#Gitee获取,-b参数指定linux-5.4.125分支
git clone -b linux-5.4.125 https://gitee.com/LubanCat/kernel-allwinner.git
为了后续步骤和教程统一,重命名内核源码目录名称:
mv kernel-allwinner/ kernel
1.2.2. 通过SDK获取内核源码¶
aw-image-build是野火科技基于armbian镜像构建脚本修改并定制的一套专用于LubanCat-AW系列板卡的镜像构建工具。
可以参考快速使用手册 《aw-image-build介绍》 章节进行源码获取。内核源码位于:
1 2 3 4 5 | # 内核源码目录如下所示
.
└── source
└── kernel
└── linux-5.4-h618
|
修改成统一学习环境,以H618为例:
# 创建SDK文件夹
mkdir LubanCat_H618_SDK && cd LubanCat_H618_SDK/
# 复制aw-image-build获取的源码,默认aw-image-build和LubanCat_H618_SDK同级
cp -r ../aw-image-build/source/kernel/linux-5.4-h618/ kernel
1.3. 内核源码目录结构¶

文件夹 |
作用 |
---|---|
arch |
这个文件夹包含了一个Kconfig文件,用于设置这个目录里的源代码编译所需的一系列设定。 支持的处理器架构都在它相应的文件夹中,如arm64、x86、riscv等。 /boot:内核需要的特定平台代码 /boot/dts:设备树文件 /configs:存放专用配置文件 /include:特定体系的头文件 /lib:通用函数在特定体系结构的文件 /mm:特定体系结构的内存管理文件 |
block |
块设备,是一些linux存储体系中关于块设备管理的代码,譬如说SD卡、iNand、Nand、硬盘等都是块设备。 |
crypto |
这个目录下放了一些各种常见的加密算法的源代码。 |
Documentation |
内核各部分的文档描述。 |
drivers |
驱动目录,里面分门别类的列出了linux内核支持的所有硬件设备的驱动源代码。 |
fs |
fs就是file system,里面包含Linux所支持的各种文件系统,如EXT、FAT、 NTFS、 JFFS2等。 |
include |
存放内核所需、与平台无关的头文件,与平台相关的头文件已经被移动到 arch 平台的include 目录 |
init |
内核初始化代码,这个目录下的代码就是linux内核启动时初始化内核的代码。 |
ipc |
ipc就是inter process commuication ,进程间通信,该目录下都是linux进程间通信的代码。 |
kernel |
kernel就是Linux内核,是Linux中最核心的部分,包括进程调度、定时器等,而和平台相关的一部分代码放在arch/*/kernel目录下。 |
firmware |
固件目录,保存用于驱动第三方设备的固件。 |
kernel |
这个文件夹中的代码控制内核本身,在该文件夹下有个”power”文件夹,这里的代码可以使计算机重新启动、关机和挂起。 |
lib |
lib是库的意思,lib目录下存放的都是一些公用的有用的库函数,注意这里的库函数和C语言的库函数不一样的,因为在内核编程中是不能用C语言标准库函数的,所以需要使用lib中的库函数,除此之外与处理器结构相关的库函数代码被放在arch/*/lib/目录下。 |
mm |
目录包含了所有独立于cpu体系结构的内存管理代码,如页式存储管理内存的分配和释放等,而与具体硬件体系结构相关的内存管理代码位于arch/*/mm目录下,例如arch/arm/mm/fault.c。 |
net |
网络协议栈相关代码,net目录下实现各种常见的网络协议。 |
scripts |
这个目录下全部是脚本文件,这些脚本文件不是linux内核工作时使用的,而是用了配置编译linux内核的。 |
security |
内核安全模型相关的代码,例如最有名的SELINUX。 |
sound |
ALSA、 OSS音频设备的驱动核心代码和常用设备驱动。 |
usr |
实现用于打包和压缩的cpio等。 |
此处仅列出一些常见的目录。
1.4. 编译内核¶
按照前面小节搭建编译环境并下载源码之后,进入内核源码的顶层目录,根据具体的板卡设置配置文件。
H618系列板卡用户执行以下命令编译内核源码:
1 2 3 4 5 6 7 8 9 | #清除之前生成的所有文件和配置
make mrproper
# 加载linux_h618_defconfig配置文件
# 这步执行之后,会将linux_h618_defconfig配置加载到.config
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- linux_h618_defconfig
# 编译内核,指定平台,指定交叉编译工具,使用16线程进行编译,线程可根据电脑性能自行确定
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- -j16
|
注意
如果内核编译报错,很大可能是编译器的问题,请参考 《交叉编译器工具包》 内容更换编译器。
1.5. 内核配置选项¶
menuconfig是linux里面的一个软件,可以配置uboot,kernel,rootfs,这里以kernel为例来配置,其他的配置menuconfig的使用是一样的。
在命令行进入内核根目录,执行以下命令进入menuconfig配置主界面
1 2 3 4 | # 加载配置文件
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- linux_h618_defconfig
# 打开menuconfig配置界面
make menuconfig
|
注意事项:
执行上述命令时,会先加载配置文件生成.config
Kconfig文件用于决定配置界面会有哪些配置选项
.config文件用于决定每个配置项的值(Y、M、N)
当.config文件存在时,它会根据.config文件设定默认项.
若不存在.config文件,则根据各级Kconfig文件来设定菜单项
使用菜单配置完成并保存后,会将配置的结果保存到.config文件
打开后menuconfig界面如下图所示:

下面分析一下defconfig、 .config 、kconfig 与makefile文件作用。
1.5.1. defconfig文件¶
一般由平台厂商提供,内核编译用做.config的参考。
文件位于:/kernel/arch/$(SRCARCH)/configs/xxx_defconfig
上述编译内核中的
linux_h618_defconfig
就是一个defconfig文件,make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- linux_h618_defconfig
指令的作用是将linux_h618_defconfig文件加载到.config文件
1.5.2. .config 文件¶
在内核编译时,主Makefile调用这个.config,用于的内核编译配置。
文件位于 :kernel/.config
可以通过defconfig文件进行加载/生成
可以通过kernel menuconfig进行配置/生成
1.5.3. Makefile 文件¶
路径:kernel/Makefile
顶层Makefile,用于内核源码编译,建议好好阅读一下此文件。
路径:kernel/arch/arm64/Makefile
该文件包含在顶层makefile中,因此用户可以添加自己的特定于体系结构的标志和依赖项。
1.5.4. Kconfig 文件¶
分布在各目录下的Kconfig构成了一个分布式的内核配置数据库,每个Kconfig分别描述了所属目录源文件相关的内核配置菜单。Kconfig是各种配置界面的源文件,内核的配置工具读取各个Kconfig文件,生成配置界面供开发人员配置内核。
文件位于:/kernel/arch/$(SRCARCH)/Kconfig
在内核配置make menuconfig(或xconfig等)时,从Kconfig中读出配置菜单,用户配置完后保存到.config(在顶层目录下生成)中。
1.6. 如何编译和加载内核驱动模块¶
1.6.1. 编译内核驱动模块¶
内核模块加载到内核,可以将内核模块编译成单独的模块,在内核启动后由用户手动动态加载, 也可以将模块直接编译进内核,在内核启动时就自动加载。测试一般是单独编译成内核模块,然后手动加载,方便调试,同时也节省时间。
野火提供了驱动教程的源码,可以执行以下命令获取:
# 从github获取
git clone https://github.com/LubanCat/lubancat_allwinner_code_storage
# 或者从gitee获取
git clone https://gitee.com/LubanCat/lubancat_allwinner_code_storage
获取到源码后,源码目录下的linux_driver文件夹就是存放驱动教程的例程文件,将 lubancat_allwinner_code_storage
放置到 内核代码同级目录
,原因是编译内核模块时,
驱动程序需要依赖编译好的Linux内核,驱动模块中的Makefile中指定了内核的路径,为方便使用例程,请放至同一目录结构下。

内核驱动模块对象所需的构建步骤和编译很复杂,它利用了linux内核构建系统的强大功能, 目前我们还不需要深入了解这部分知识,利用简单的Make工具就能编译出我们想要的内核驱动模块。 这里以编译helloworld内核模块为例,使用命令进入helloworld目录,然后使用make:
#进入helloworld驱动源码目录
cd lubancat_allwinner_code_storage/linux_driver/helloworld/
#编译
make
重要
Makefile中指定的目录 “KERNEL_DIR=../../../kernel/”要和实际编译内核时指定的输出目录一致,如果编译内核时没有指定特定输出目录,那么就将这个变量指定到内核源码的根目录,可以用绝对路径或者相对路径。 这里的环境是在PC上,使用交叉编译工具编译内核模块。
切换到helloworld目录下,直接执行make命令,即可编译程序。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | KERNEL_DIR=../../../kernel/
ARCH=arm64
CROSS_COMPILE=aarch64-linux-gnu-
export ARCH CROSS_COMPILE
obj-m := helloworld.o
all:
$(MAKE) -C $(KERNEL_DIR) M=$(CURDIR) modules
.PHONE:clean
clean:
$(MAKE) -C $(KERNEL_DIR) M=$(CURDIR) clean
|
第1行: 指定内核目录,根据自己编译内核时指定的输出目录,可以相对路径或者绝对路径,如果编译内核时没有指定特定输出目录,那么就将这个变量指定到内核源码的根目录。
第2行: arm64体系结构.
第3行: 指定交叉编译工具链。
第4行: 导出环境变量。
第6行: 表示以模块进行编译。
第8行: all只是个标号,可以自行定义,是make的默认执行目标。
第9行: $(MAKE)的MAKE是Makefile中的宏变量,要引用宏变量要使用符号。这里实际上就是指向make程序,所以这里也可以把$(MAKE)换成make。 make -C是make命令的一个选项,-C作用是changedirectory, -C dir 就是转到dir目录。M=$(CURDIR):返回当前目录。这句话的意思是:当make执行默认的目标all时,-C(KVDIR)指明跳转到内核源码目录下去执行那里的Makefile,-C $(KERNEL_DIR)指明跳转到内核源码目录下去执行那里的Makefile,M=(CURDIR)表示又返回到当前目录来执行当前的Makefile。
第11行: clean 就是删除后面这些由make生成的文件。

在helloworld/下,新增helloworld.ko文件,这就是编译生成的内核驱动模块。
1.6.2. 加载内核驱动模块¶
编译好内核驱动模块,可以通过多种方式将helloworld.ko拷贝到开发板,我们可以使用 NFS网络文件系统
、 scp命令
、 sftp命令
等。
其中NFS环境请搭建请参考Linux系列章节之 挂载NFS网络文件系统 章节。
scp命令用于Linux之间复制文件和目录,该命令基于ssh,需要搭建好ssh环境,scp命令格式如下:
scp local_file remote_username@remote_ip:remote_folder
例如:
scp helloworld.ko cat@192.168.103.129:/home/cat/
将helloworld.ko发送到192.168.103.129的/home/cat/目录下,192.168.103.129是开发板ip,需根据实际而定,开发板用户名为cat, 输入yes,然后输入密码进行验证,等待传输完成,这个时候我们开发板就有了helloworld.ko 这个文件。
安装卸载内核驱动模块使用insmod和rmmod命令:
#进入家目录
cd /home/cat/
# 加载内核模块
sudo insmod helloworld.ko
#查看当前加载的内核模块
lsmod
# 卸载内核模块
sudo rmmod helloworld.ko

查看加载的内核模块,可以使用命令lsmod,其他信息也可以到/sys/module目录下查看,例如:加载成功helloworld.ko模块后, 可以到/sys/module/helloworld下查看。
1.7. 如何编译和加载设备树¶
1.7.1. 编译设备树¶
Linux 3.x 之后的版本引入了设备树(Device Tree)的概念和机制。设备树是一种用于描述硬件平台的静态数据结构,包含了有关硬件设备、总线、中断控制器等信息的详细描述。 后面我们写的驱动需要依赖设备树,所以在这里先介绍如何编译设备树、加载设备树。 这里不做代码讲解,具体原理请参考后续 Linux设备树 章节
1.7.1.1. 使用内核工具编译设备树¶
在编译 Linux 内核时,会生成名为 dtc(Device Tree Compiler)的工具,该工具用于自动编译设备树源文件(.dts 或 .dtsi 文件)为二进制的设备树文件(.dtb 文件)。我们也可以使用命令 sudo apt install device-tree-compiler
下载dtc编译工具。
dtc工具使用示例如下:
# 编译 dts 为 dtb
内核目录/scripts/dtc/dtc -I dts -O dtb -o xxx.dtb xxx.dts
#也可以下载dtc工具进行编译
sudo apt install device-tree-compiler
dtc -I dts -O dtb -o xxx.dtb xxx.dts
内核使用dtc工具的命令大致如上所示,实际上设备树中有非常多的依赖关系,所以一般情况下, 设备树不仅仅只是通过一个dtc命令就能将编译出来的。以上为伪代码,仅供参考使用,了解即可。
1.7.1.2. 使用内核的构建脚本编译设备树¶
我们可以尝试着通过内核的构建脚本去编译设备树,我们所要用到的设备树文件都存放在 内核源码/arch/arm64/boot/dts/sunxi
里面。
前面提到了编译内核时会自动去编译设备树,但是编译内核很耗时,所以我们推荐使用如下命令只编译设备树。
在内核源码顶层目录执行以下命令:
#加载配置文件
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- linux_h618_defconfig
#使用dtbs参数单独编译设备树
make ARCH=arm64 -j4 CROSS_COMPILE=aarch64-linux-gnu- dtbs
编译内核时会去编译设备树,那么此时在没有修改、添加设备树的情况下使用构建脚本单独编译设备树是不会有任何输出的,我们可以手动修改设备树文件再进行编译测试。
例如修改 内核源码/arch/arm64/boot/dts/sunxi
下的 xxx.dts
文件再进行编译。找到已经编译成dtb文件对应的dts源文件,可简单在dts文件中加个空格,以防错误修改导致编译报错。
以下以修改sun50iw9-lubancat-a1.dts为例:

执行命令后会编译修改过的设备树,编译成功后生成的设备树文件(.dtb)位于源码目录下的 内核源码/arch/arm64/boot/dts/sunxi
。
1.7.2. 编译uboot deb包¶
注意
由于LubanCat-A0/A1板卡使用的全志v2018.07版本的u-boot需要使用内核设备树文件和全志的硬件配置文件sys_config.fex来共同生成系统的设备描述文件并打包到u-boot镜像中,并且u-boot和内核都使用这一设备描述文件,所以当我们在内核源码中修改了设备树文件后,需要先编译内核,再编译u-boot,最后将u-boot镜像更新到我们的板卡中。
如需更新内核设备树,参照: 《aw-image-build介绍》 章节,step1.Build Kernel和step2.Build U-boot部分内容。
由于编译完整内核时间较长,可以不按照step1.Build Kernel方式编译完整内核,而是直接使用内核的构建脚本单独编译设备树也可以,然后根据step2.Build U-boot编译uboot。

编译完设备树后再在SDK顶层目录执行 ./build.sh 打开配置界面,再选择step2.Build U-boot编译uboot。
guest@dev107:~/LubanCat_H618_SDK/aw-image-build$ ./build.sh
编译后生成的uboot deb位于SDK的build/debs/u-boot/目录下:
guest@dev107:~/LubanCat_H618_SDK/aw-image-build$ ls build/debs/u-boot/
lubancat-a1-uboot-current_1.2502stable_arm64.deb
1.7.3. 替换设备树(通过更新uboot)¶
以鲁班猫A1板卡为例,将生成的uboot deb包传到板卡,可以通过SCP或NFS拷贝到开发板上,然后进行安装。
#将生成的uboot deb传到板卡,并进行安装
sudo dpkg -i lubancat-*.deb
#信息输出如下
root@lubancat:/home/cat# sudo dpkg -i lubancat-*.deb
(Reading database ... 140594 files and directories currently installed.)
Preparing to unpack lubancat-a1-uboot-current_1.2502stable_arm64.deb ...
Unpacking lubancat-a1-uboot-current (1.2502stable) over (1.2502stable) ...
Setting up lubancat-a1-uboot-current (1.2502stable) ...
安装完成后通过nand-sata-install更新uboot,在板卡上执行如下命令打开配置界面:
sudo nand-sata-install
打开界面后选择”5 Install/update the bootloader on SD/eMMC”选项,然后一路确认即可。

完成以上操作后,重启板卡即可。
1.8. 如何编译和加载设备树插件¶
1.8.1. 编译设备树插件¶
Linux4.4以后引入了动态设备树(Dynamic DeviceTree)。设备树插件可以被动态的加载到系统中,供被内核识别。
重要
设备树插件和设备树不是互相替代的关系,而是互补的关系。设备树插件可以在主设备树定型的情况下, 再对主设备树未描述的功能进行动态的拓展。 比如A板的设备树没有开启串口1的功能,但B板需要开启串口1的功能,那么可以直接沿用A板的设备树, 并用设备树插件拓展出串口1,满足B板的需求。
1.8.1.1. 使用内核工具编译设备树插件¶
编译设备树插件和编译设备树类似,这里介绍内核中的dtc工具编译编译设备树插件的过程。
内核中将xxx.dts 编译为 xxx.dtbo的过程示例,仅供参考:
内核构建目录/scripts/dtc/dtc -I dts -O dtb -o xxx.dtbo xxx.dts
例如,将内核源码arch/arm64/boot/dts/sunxi/overlay/目录下的h618-lubancat-uart2-overlay.dts编译为h618-lubancat-uart2-overlay.dtbo
scripts/dtc/dtc -I dts -O dtb -o arch/arm64/boot/dts/sunxi/overlay/h618-lubancat-uart2-overlay.dtbo arch/arm64/boot/dts/sunxi/overlay/h618-lubancat-uart2-overlay.dts
执行编译命令后可以内核源码arch/arm64/boot/dts/sunxi/overlay/找到相应的dtbo文件。
当然和编译设备树一样,设备树插件的编译也涉及到依赖关系,所以编译过程也比较复杂。 不仅仅是使用一条命令就可以完成编译的,一般我们在内核目录下,执行make指定dtb选项,即可自动编译添加的设备树插件。
1.8.1.2. 使用内核的构建脚本编译设备树插件¶
设备树插件与设备树一样都是使用DTC工具编译,只不过设备树编译为.dtb。而设备树插件需要编译为.dtbo。 我们可以使用DTC编译命令编译生成.dtbo,但是这样比较繁琐、容易出错。
鲁班猫系列开发板许多外设硬件描述都是以dtbo插件的形式提供的,使用设备树插件配置硬件外设使用起来非常灵活。

如上图,这是一个设备树插件文件列表,用于指定在编译内核时要编译的设备树插件文件。在条件CONFIG_ARCH_SUNXI被启用时,鲁班猫系列板卡,将编译CONFIG_ARCH_SUNXI包含的设备树插件。
当大家尝试写设备树插件的时候,可以将自己的设备树插件添加到内核源码 arch/arm64/boot/dts/sunxi/overlays
目录下,
并修改 arch/arm64/boot/dts/sunxi/overlays/Makefile
文件,
添加编译选项,例如添加h618-lubancat-test-overlay.dts,对应的dts源码如下:
/dts-v1/;
/plugin/;
/ {
fragment@1 {
target = <&uart2>;
__overlay__ {
status = "okay";
};
};
};
以上实际是h618-lubancat-uart2-overlay.dts里面的内容,作用是将UART2设置为”okay”状态,表示将UART2外设接口启用,实际也可以复制其他插件内容进行测试,可以查看板卡的配置文件选择一个没有冲突的插件,在板卡中使用 cat /boot/uEnv.txt
进行查看。
添加设备树插件源文件到overlays目录下后,执行设备树的编译命令,设备树插件的编译也会同步完成。
在内核源码顶层目录执行以下命令:
#加载配置文件
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- linux_h618_defconfig
#使用dtbs参数单独编译设备树
make ARCH=arm64 -j4 CROSS_COMPILE=aarch64-linux-gnu- dtbs
如果修改或添加了新的设备树插件,在执行命令后可以在终端看到有相应的编译输出,修改或添加的dts编译为dtbo文件。
1.8.2. 加载设备树插件¶
野火Lubancat_AW系列板卡支持通过uboot加载设备树插件,供内核识别使用。
通过SCP或NFS将.dtbo设备树插件拷贝到开发板 /boot/dtb/sunxi/overlay/
目录下,下面操作都在开发板上进行。
root@lubancat:~# ls /boot/dtb/sunxi/overlay/
h618-lubancat-i2c2-overlay.dtbo h618-lubancat-spi1-overlay.dtbo
h618-lubancat-i2c4-overlay.dtbo h618-lubancat-uart2-overlay.dtbo
h618-lubancat-pwm1-overlay.dtbo h618-lubancat-uart5-overlay.dtbo
h618-lubancat-test-overlay.dtbo
将要加载的设备树插件写入到/boot/uEnv.txt配置文件中,系统启动过程中会自动读取uEnv.txt文件,从而加载指定的设备树插件, 如下所示:

要将设备树插件写入/boot/uEnv.txt,使用vim或者nano编辑器打开文件,参照着红框内容写即可,书写格式为“overlays=<设备树插件名称>”,当多个插件时需要使用空格隔开。
修改完成后保存、退出,执行reboot命令重启系统。 重启后正常情况下我们可以在“/proc/device-tree”或者“/sys/firmware/devicetree/base/”目录下找到设备节点同名的文件夹,证明设备树插件已经加载成功。如果没有出现相应的节点,很可能是与其他节点冲突,可以修改h618-lubancat-test-overlay.dts的内容为配置文件中其他插件的内容再进行测试。
以上测试插件开启的是UART2外设,可以查看是否注册/dev/ttyAS2从而判断插件是否加载成功。
root@lubancat:/home/cat# ls /dev/ttyAS2
/dev/ttyAS2