正点原子 发表于 2022-1-23 11:31:29

《领航者ZYNQ之嵌入式Linux开发指南_V2.0》第三十六章 驱动静态

1)实验平台:正点原子领航者V2 ZYNQ开发板
2)章节摘自【正点原子】《领航者ZYNQ之嵌入式Linux开发指南_V2.0》
3)购买链接:https://detail.tmall.com/item.htm?id=609032204975
4)全套实验源码+手册+视频下载地址:http://www.openedv.com/thread-329957-1-1.html
5)正点原子官方B站:https://space.bilibili.com/394620890
6)正点原子FPGA技术交流QQ群:90562473







第三十六章 驱动静态编译
       前面所有章节的驱动实验当中,我们都是将驱动代码编译成.ko驱动模块,然后在linux系统下使用insmod或modprobe命令加载驱动模块之后进行测试;驱动开发工程师将驱动代码编译成.ko驱动模块可以很方便的进行驱动调试,所以在驱动调试阶段一般都选择将其编译为模块,这样我们修改驱动以后只需要编译一下驱动代码即可,不需要编译整个Linux源代码;而且在调试的时候只需要加载或者卸载驱动模块即可,不需要重启整个系统。总之,将驱动编译为模块最大的好处就是方便开发,当驱动开发完成,确定没有问题以后就可以将驱动编译进Linux内核中,当然也可以不编译进Linux内核中,具体看自己的需求以及设备的特点来决定!
       那么本章将给大家介绍如何将驱动源码编译进Linux内核中,这里我把它叫做静态编译,本章就以上一章(第三十五章)驱动实验为例,将驱动源码编译进linux内核中。

       1.1修改Makefile
       首先将上一章实验目录16_asyncnoti下的驱动源文件asyncnoti.c拷贝到linux内核源码目录drivers/char目录下,如下所示:

图 36.1.1 拷贝驱动源文件到内核源码目录
       /home/zynq/linux/kernel/linux-xlnx-xilinx-v2018.3是笔者内核源码所在目录,linux内核源码目录下的drivers文件夹中存放了驱动相关的代码,此目录根据驱动类型的不同,分门别类进行整理,比如drivers/i2c就是I2C相关驱动目录,drivers/gpio就是GPIO相关的驱动目录,而char目录下存放的就是字符设备相关的驱动代码,所以这里我们将驱动源文件asyncnoti.c拷贝到了drivers/char目录。
       打开drivers/char目录下的Makefile文件,将asyncnoti.c文件添加进来,如下所示:

图 36.1.2 将asyncnoti.o添加到Makefile文件中
       内核源码drivers目录下的各个子目录以及子目录的子目录中一般都会存在一个Makefile文件,在这些Makefile文件中我们会看到很多“obj-$(CONFIG_XXX)+= xxxx.o”,例如图 36.1.2中所示。CONFIG_XXX变量一般可以取3个不同的值:y、m、n;所以将$(CONFIG_XXX)替换之后也就是定义了三个变量obj-y、obj-m、obj-n。
       当我们编译内核源码的时候,obj-y变量中所有的xxxx.o所对应的xxxx.c文件都会被编译进内核镜像;当在内核源码目录执行“make modules”编译内核模块的时候,obj-m变量中所有的xxxx.o文件对应的xxxx.c源文件会被编译成.ko驱动模块文件;而obj-n变量中所有的xxxx.o文件对应的xxxx.c源文件既不会编译进内核镜像文件,也不会编译成驱动模块。所以由此可以知道CONFIG_XXX好比是一个“选择器”,你可以选择将源文件编译进内核中,也可以选择编译成一个.ko驱动模块文件,也可以不编译。
       在图 36.1.2中我们将“obj-$(CONFIG_ASYNCNOTI)+= asyncnoti.o”添加到了Makefile文件的最后,CONFIG_ASYNCNOTI可以自定义,但是不能和其它名字冲突,一般就是“CONFIG_”加上.c源文件的大写字母;将内容添加到Makefile文件之后保存退出即可!
       1.2修改Kconfig
       打开内核源码drivers/char目录下的Kconfig文件,添加如下内容:

图 36.2.1 修改Kconfig文件
       关于Kconfig文件的语法在15.2.2小节中给大家介绍过,这里不再说明!“config ASYNCNOTI”其实就是CONFIG_ASYNCNOTI变量的配置项,用于配置CONFIG_ASYNCNOTI变量的值是y、m还是n。tristate表示三态,也就是可以将CONFIG_ASYNCNOTI变量的值设置为y、m或者n中的任何一个,后边携带的字符串信息表示的是对该config配置项的一个描述信息。
   “default y”表示该配置项的默认值是y,关于Kconfig文件的语法如果大家有什么不懂的可以看看15.2.2小节。在Kconfig文件中添加配置项之后,当我们在内核源码目录执行“make menuconfig”的时候就可以通过图形化界面的方式对其进行配置了。
       1.3menuconfig配置
      在内核源码目录下执行下面这些命令进入到menuconfig配置界面:
make distclean                                                                                                                              // 清理整个工程
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- xilinx_zynq_defconfig      // defconfig
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig                              // menuconfig
图 36.3.1 执行menuconfig图形化配置界面命令
       进入menuconfig图形化界面之后,找到Character devices配置界面:
Device Drivers--->
      Character devices--->如下图所示:

图 36.3.2 Character devices配置界面
       在图 36.3.2中可以看到我们在上一个小节为asyncnoti.c驱动源文件添加的配置项“Character device key driver support”,“<*>”尖括号里边的“*”符号表示该配置项默认是选中的,也就是配置为“y”;将光标移动到该配置条目上,分别按键盘上的“Y”、“M”、“N”键可以分别选择将该驱动编译进内核、编译成单独的驱动模块、不编译驱动源文件。因为本章我们需要将驱动编译进内核中,所以这里选“Y”即可!
       对于menuconfig界面中的每一个配置项,都可以查看它的help帮助信息,如下所示:

图 36.3.3 menuconfig配置项帮助信息
       从图 36.3.3中可以知道,该配置项就是我们在图 36.2.1中所加入到Kconfig文件中的配置项。按回车键退出帮助页面,保存当前配置,然后退出menuconfig界面。
       1.4编译测试
       为了验证我们加入的asyncnoti.c驱动源文件在内核启动的时候会自动运行,我们可以在asyncnoti.c文件的驱动入口函数mykey_init中加入打印语句,如下所示:

图 36.4.1 加入打印语句
       修改完成之后保存退出即可,接下来就可以进行编译了,执行下面这条命令编译内核源码得到zImage镜像文件:
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- zImage -j16       编译完成之后,如下所示:

图 36.4.2 内核源码编译完成
       编译得到的zImage文件所在目录为arch/arm/boot/zImage,将zImage文件拷贝到开发板SD启动卡的Fat分区中,替换旧的zImage镜像文件,然后重新启动开发板;系统在启动过程当中就会自动运行asyncnoti.c驱动模块,打印信息如下所示:

图 36.4.3 内核启动打印信息
       图 36.4.3中标识出来的打印信息就是我们在asyncnoti.c驱动源文件中加入的打印信息,所以可以证明我们的驱动程序已经成功运行了,那么接下来可以进行驱动程序的测试工作了;输入用户名和密码登录开发板linux系统,进入到根文件系统/lib/modules/4.14.0-xilinx目录下,执行下面这条命令运行上一章的驱动测试程序asyncKeyApp:
./asyncKeyApp /dev/key       按下或者松开开发板的PS_KEY0按键,终端就会打印相应的信息,如下所示:

图 36.4.4 运行驱动测试程序
       测试的效果跟上一章测试情况是一样的,说明的驱动工作正常。测试完成之后按住键盘Ctrl+C组合键退出asyncKeyApp测试程序。将驱动代码静态编译到linux内核中之后,我们就不需要使用insmod或modprobe等方式加载.ko驱动模块了,内核启动的过程中会自动运行驱动程序!

页: [1]
查看完整版本: 《领航者ZYNQ之嵌入式Linux开发指南_V2.0》第三十六章 驱动静态