《嵌入式驱动(二):驱动编写基本概念》
版本号
uboot 2016.03 kernel 4.1.15 busybox
一、基本概念:
1. 驱动分类
1)字符设备驱动:按照单个字符扫描设备信息
2)块设备驱动:按照块(512字节)扫描设备信息,用于存储设备
3)网络设备驱动:需要网络协议栈支持TCP/IP、CAN
2. 驱动编译
1) 静态编译
将驱动代码加入到zImage的内核中
在合适的内核目录下编写驱动代码 hello.c(/drive/char/)
修改Kconfig,新增配置项
make menuconfig 选中该配置项
对应配置项的CONFIG_XXX 会加入.config文件中‘
在驱动代码对应的Makefile中加入编译规则 obj-$(CONFIG_XXX ) += hello.o
2)动态编译
将驱动代码以模块的方式编译,动态加入内核或者从内核中去除
编写hello.c
修改Kconfig,新增配置项
通过make menuconfig 选择 M,以模式形式编译
对应配置项的CONFIG_XXX 会加入.config文件中 CONFIG_XXX =m
在Makefie中 obj-$(CONFIG_XXX ),以模块编译
make modules 内核会编译所有模块生成一个.ko驱动文件
将驱动文件动态加载到执行的内核中,从内核中去除该驱动模块
二、重点
1. uboot如何编译的?uboot的功能?
1)解压uboot压缩包,并进入uboot源码目录
tar -zxvf uboot.tar.gz
cd uboot
2)uboot图形界面是基于ncurses库编写的,所以需要先安装该库
sudo apt-get install libncurses5-dev
3)编译uboot源码
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- distclean //清楚原来编译内容,包括.config
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- mx6ull_alientek_emmc_defconfig //用默认配置生成.config,y表示加入编译
make V=0 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j16 //编译
ARCH:指定目标硬件架构
CROSS_COMPILE:设置交叉编译工具链
V=0:控制编译输出的详细程度,0表示启动静默/精简输出模式,1表示完整的编译命令,便于调
试。
2. 内核如何编译?如何裁剪?
编译:
1) 先利用apt-get工具集下载安装lzop工具(必须保证apt-get源配置,请参考《apt-get源设置》,而且Ubuntu可以上公网,请参考《双网卡网络配置》)
sudo apt-get install lzop
安装成功,后续可通过该工具生成zImage文件
2) 将《驱动资料包\源码\内核》内核文件拷贝到Ubuntu系统中,并对文件进行解压缩。
tar -zxvf linux-imx-rel_imx_4.1.15_2.1.0_ga_alientek.tar.gz
3)编译内核
cd linux-imx-rel_imx_4.1.15_2.1.0_ga_alientek/
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- distclean //清除旧源
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- imx_alientek_emmc_defconfig //生成新的.config
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig //微调
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- all -j16 //编译
distclean:表示清除之前的编译内容
imx_alientek_emmc_defconfig:将该配置作为内核的.config配置
menuconfig:通过图形界面配置.config
all -j16:通过16核编译代码
ARCH=arm:编译arm32位平台
CROSS_COMPILE=arm-linux-gnueabihf-:设置编译工具链
结果文件主要有2个:
内核镜像文件:arch/arm/boot/zImage
设备树文件:arch/arm/boot/dts/imx6ull-alientek-emmc.dtb文件
裁剪:通过make menuconfig进行微调
3. 根文件系统如何制作?如何自启动?涉及哪些脚本?
1)将源码拷贝到Ubuntu主机下。(我们可以从busybox官网下载源码,也可以直接使用我下载好的源码,文件在《驱动资料包\工具\busybox》目录下)
2)解压文件
tar -vxjf busybox-1.29.0.tar.bz2
3)修改busybox顶层的Makefile
cd busybox-1.29.0/
vim Makefile
4) 修改文件中的内容
修改
CROSS_COMPILE ?=
为
CROSS_COMPILE ?= arm-linux-gnueabihf-
修改
ARCH ?= $(SUBARCH)
为
ARCH ?= arm
5) 配置busybox
make defconfig //使用默认配置
make menuconfig //打开图形化配置
6)通过图形界面配置busybox工具
配置路径如下:
Location:
-> Settings
-> Build static binary (no shared libs)
Location:
-> Settings
-> vi-style line editing commands
Location:
-> Linux Module Utilities
-> Simplified modutils
Location:
-> Linux System Utilities
-> mdev (16 kb) //确保下面的全部选中,默认都是选中的
7) 创建一个用来存放生成根文件系统的目录,并编译busybox
mkdir /home/linux/nfs/rootfs //创建存放
根文件系统的目录
make //编译
make install CONFIG_PREFIX=/home/linux/nfs/rootfs //安装
ls -l /home/linux/nfs/rootfs //查看根文
件系统是否创建成功
8)此时的文件系统还缺少了一些运行的库文件,需要将工具链中的libc库拷贝过去
cd /home/linux/nfs/rootfs
mkdir lib
cp ~/tools/opt/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/arm-linux-
gnueabihf/libc/lib/*so* /home/linux/nfs/rootfs/lib/ -d
cp ~/tools/opt/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/arm-linux-
gnueabihf/libc/lib/*.a /home/linux/nfs/rootfs/lib/ -d
9)将符号链接库删除,并拷贝真实的库文件
rm /home/linux/nfs/rootfs/lib/ld-linux-armhf.so.3
cp ~/tools/opt/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/arm-linux-
gnueabihf/libc/lib/ld-linux-armhf.so.3 /home/linux/nfs/rootfs/lib
10)将工具链下的lib库拷贝过去
cp ~/tools/opt/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/arm-linux-
gnueabihf/lib/*so* /home/linux/nfs/rootfs/lib/ -d
cp ~/tools/opt/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/arm-linux-
gnueabihf/lib/*.a /home/linux/nfs/rootfs/lib/ -d
11)将工具链的usr/lib库拷贝过去
mkdir /home/linux/nfs/rootfs/usr/lib -p
cp ~/tools/opt/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/arm-linux-
gnueabihf/libc/usr/lib/*so* /home/linux/nfs/rootfs/usr/lib -d
cp ~/tools/opt/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/arm-linux-
gnueabihf/libc/usr/lib/*.a /home/linux/nfs/rootfs/usr/lib -d
12)进入根目录文件系统查看这两个目录的大小
cd /home/linux/nfs/rootfs
du ./lib ./usr/lib -sh
与上图所示大小一样即为正确。
13) 创建其余文件夹
mkdir dev
mkdir proc
mkdir mnt
mkdir sys
mkdir tmp
mkdir root
mkdir lib/modules
14) 我们还需要完善下根我们系统中的配置文件,这些配置文件可以进一步完善Linux系统中的功能
1. 创建/etc/init.d/rcS文件,并将文件修改为如下内容,该文件是一个shell脚本,Linux内核启动后需要启动的一些服务都可以通过该脚本进行配置
mkdir ~/nfs/rootfs/etc/init.d -p
touch ~/nfs/rootfs/etc/init.d/rcS
vim ~/nfs/rootfs/etc/init.d/rcS
修改文件内容如下:
#!/bin/sh
PATH=/sbin:/bin:/usr/sbin:/usr/bin:$PATH
LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/lib:/usr/lib
export PATH LD_LIBRARY_PATH
mount -a
mkdir /dev/pts
mount -t devpts devpts /dev/pts
echo /sbin/mdev > /proc/sys/kernel/hotplug
mdev -s
2. 修改文件权限
chmod 0777 ~/nfs/rootfs/etc/init.d/rcS
3. 创建/etc/fstab文件,并将文件修改为如下内容,在rcS脚本中执行mount -a,挂载所有文件系统,就会找到fstab文件,并进行文件挂载。
touch ~/nfs/rootfs/etc/fstab
vim ~/nfs/rootfs/etc/fstab
修改内容如下:
#
proc /proc proc defaults 0 0
tmpfs /tmp tmpfs defaults 0 0
sysfs /sys sysfs defaults 0 0
4. 创建/etc/inittab文件,该文件指定启动后一些代码的运行方式。
touch ~/nfs/rootfs/etc/inittab
vim ~/nfs/rootfs/etc/inittab
修改文件内容如下:
#etc/inittab
::sysinit:/etc/init.d/rcS
console::askfirst:-/bin/sh
::restart:/sbin/init
::ctrlaltdel:/sbin/reboot
::shutdown:/bin/umount -a -r
::shutdown:/sbin/swapoff -a
以上内容的格式为:
<id>:<runlevels>:<action>:<process>
<id>:每个指令的标识符,不能重复。对于busybox而言<id>用来指定启动进程的控制tty,一般
我们将串口或者LCD屏幕设置为控制tty。
<runlevels>:对busybox来说此项说明完成没用
<action>:动作,用于指定<process>可能使用到的动作。如下图所示
<process>:具体的动作,如程序、脚本、命令等。
action动作可配置为如下参数:
15) 接下来就可以通过nfs挂载测试了。
根文件系统(rootfs)构建工具的实体信息:
busybox
:用于生成轻量级、最基本的根文件系统(特点是缺少库、缺少软件);
buildroot
、yocto
:可选择安装某些库、某些软件(用来扩展根文件系统的功能)。
用一张图来表示这个过程
开机自启动:代码写在/etc/init.d/rcS或者/etc/profile
4.总结

5. 内核驱动静态编译和动态编译的区别?
静态编译
将驱动代码直接编译进内核映像(如zImage),成为内核的一部分。驱动随内核启动自动加载,无法单独卸载或更新。适用于核心功能或必须常驻的驱动。
优点:无需手动加载,性能略高;
缺点:需重新编译内核才能更新驱动。
动态编译
将驱动编译为独立模块(.ko文件),可动态加载或卸载。适用于非必需或需频繁调试的驱动。
优点:灵活性高,便于调试;
缺点:需手动管理模块依赖。
关键差异
集成方式:静态编译直接嵌入内核,动态编译生成独立模块。
维护性:动态编译支持热插拔,静态编译需全内核更新。
使用场景:核心驱动用静态,可选功能或调试阶段用动态。