跳到主要内容

第5章 开发板的第1个驱动实验

详细的手把手教学视频请看

https://www.bilibili.com/video/BV1zV411U7H9?p=8

https://www.bilibili.com/video/BV1zV411U7H9?p=9

单独编译加载第一个驱动。

5.1 前提

为什么编译驱动程序之前要先编译内核?

  • 驱动程序要用到内核文件:

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

  • 编译驱动时用的内核、开发板上运行到内核,要一致:

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

  • 更换板子上的内核后,板子上的其他驱动也要更换:

板子使用新编译出来的内核时,板子上原来的其他驱动也要更换为新编译出来的。所以在编译我们自己的第1个驱动程序之前,要先编译内核、模块,并且放到板子上去。

5.2 编译内核

不同的开发板对应不同的配置文件,配置文件位于内核源码arch/arm/configs/目录。kernel的编译过程如下:

cd /home/book/100ask_imx6ull-sdk/Linux-4.9.88
book@100ask:~/100ask_imx6ull-sdk/Linux-4.9.88$ make mrproper
book@100ask:~/100ask_imx6ull-sdk/Linux-4.9.88$ make 100ask_imx6ull_defconfig
book@100ask:~/100ask_imx6ull-sdk/Linux-4.9.88$ make zImage -j4
book@100ask:~/100ask_imx6ull-sdk/Linux-4.9.88$ make dtbs
book@100ask:~/100ask_imx6ull-sdk/Linux-4.9.88$ cp arch/arm/boot/zImage ~/nfs_rootfs

编译步骤参考如图 5.1,编译完成zImage后才可编译设备树文件。

图 5.1 编译zImage

编译完成后生成的文件如图 5.2所示:

图 5.2 编译zImage完成

编译完成后,在arch/arm/boot目录下生成zImage内核文件, 在arch/arm/boot/dts目录下生成设备树的二进制文件100ask_imx6ull-14x14.dtb。把这2个文件复制到/home/book/nfs_rootfs目录下备用(后面使用adb命令把文件下载到开发板),如图 5.3:

图 5.3 将zImage和dtb复制某个目录备用

5.3 编译安装内核模块

5.3.1 编译内核模块

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

book@100ask: cd ~/100ask_imx6ull-sdk/Linux-4.9.88/
book@100ask:~/100ask_imx6ull-sdk/Linux-4.9.88$ make modules

内核模块编译完成后如图 5.4所示:

图 5.4 内核模块编译完成

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

可以先把内核模块安装到nfs目录(/home/book/nfs_rootfs)。

注意:后面会使用tree命令查看目录结构,如果提示没有该命令,需要执行以下命令安装tree命令:

sudo apt install tree

执行以下命令安装模块:

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

如图 5.5,把模块安装在nfs目录“/home/book/nfs_rootfs/”下:

图 5.5 安装模块到nfs_rootfs

安装好驱动后的/home/book/nfs_rootfs/目录结构如图 5.6所示:

图 5.6 安装模块后的nrf_rootfs

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

假设:在Ubuntu的/home/book/nfs_rootfs目录下,已经有了zImage、dtb文件,并且有lib/modules子目录(里面含有各种模块)。

接下来要把这些文件复制到开发板上,在Ubuntu上使用adb命令:

cd  /home/book/nfs_rootfs
adb push zImage /boot
adb push 100ask_imx6ull-14x14.dtb /boot
adb push lib/modules /lib

最后,在开发板上执行“sync”命令,再重启开发板,它就使用新的zImage、dtb、模块了。

5.5 编译led驱动

01_all_series_quickstart/

05_嵌入式Linux驱动开发基础知识/

source/02_led_drv/02_led_drv_for_boards/100ask_imx6ull_src_bin

可以在Ubuntu中下载Git仓库,或者从Windows上通过filezilla把源码传到Ubuntu。

首先,进入100ask_imx6ull_src_bin目录,修改Makefile文件“KERN_DIR”为自己的内核所在路径。如图 5.7红框所示,如果你的内核源码不在此目录则根据你的实际情况进行修改:

图 5.7 修改源码SDK路径

注意:有些学员并不按照前面的文档编译内核,而是使用Buildroot来编译内核,那么led驱动程序的Makefile中要指定KERN_DIR为如下目录:

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

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

图 5.8 编译模块驱动

此时,使用ADB命令把这两个文件下载到开发板:

adb  push   100ask_led.ko   /root
adb push ledtest /root

5.6 在开发板安装驱动模块

5.6.1 关闭系统默认cpu状态灯

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

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

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

5.6.2 安装驱动模块

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

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

安装完成后可以执行lsmod 命令来查看是否安装成功,如图 5.9所示:

图 5.9 执行lsmod验证

如果你没有更新板子上的内核,会出现类似如图 5.10所示错误:

图 5.10 不更新内核时的错误提示

可以强行安装驱动程序,比如使用“insmod -f hello_drv.ko”这样的命令,它会提示说“内核已经被污染了”,但是不影响学习、不影响使用,如图 5.11所示:

图 5.11 内核污染提示

5.7 执行测试程序

驱动模块安装成功后,就可以使用测试程序来控制led灯的状态,如图 5.12所示,操作led灯时可同时观察开发板串口旁的灯是否有亮灭的变化。

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

图 5.12 操控LED