《嵌入式驱动(二):驱动开发基本概念》

版本号

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源码目录

cs 复制代码
tar -zxvf uboot.tar.gz
cd uboot

2)uboot图形界面是基于ncurses库编写的,所以需要先安装该库

cs 复制代码
sudo apt-get install libncurses5-dev

3)编译uboot源码

cs 复制代码
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可以上公网,请参考《双网卡网络配置》)

cs 复制代码
sudo apt-get install lzop

安装成功,后续可通过该工具生成zImage文件

2) 将《驱动资料包\源码\内核》内核文件拷贝到Ubuntu系统中,并对文件进行解压缩。

cs 复制代码
tar -zxvf linux-imx-rel_imx_4.1.15_2.1.0_ga_alientek.tar.gz

3)编译内核

cs 复制代码
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)解压文件

cs 复制代码
tar -vxjf busybox-1.29.0.tar.bz2

3)修改busybox顶层的Makefile

cs 复制代码
cd busybox-1.29.0/
vim Makefile

4) 修改文件中的内容

cs 复制代码
修改
CROSS_COMPILE ?=
为
CROSS_COMPILE ?= arm-linux-gnueabihf-
cs 复制代码
修改
ARCH ?= $(SUBARCH) 
为
ARCH ?= arm

5) 配置busybox

cs 复制代码
make defconfig          //使用默认配置
make menuconfig         //打开图形化配置

6)通过图形界面配置busybox工具

配置路径如下:

cs 复制代码
Location: 
    -> Settings 
        -> Build static binary (no shared libs)
cs 复制代码
Location: 
    -> Settings 
        -> vi-style line editing commands
cs 复制代码
Location: 
    -> Linux Module Utilities
        -> Simplified modutils
cs 复制代码
Location: 
    -> Linux System Utilities 
        -> mdev (16 kb) //确保下面的全部选中,默认都是选中的

7) 创建一个用来存放生成根文件系统的目录,并编译busybox

cs 复制代码
mkdir /home/linux/nfs/rootfs                                        //创建存放
根文件系统的目录
make                                                                //编译
make install CONFIG_PREFIX=/home/linux/nfs/rootfs                   //安装
ls -l /home/linux/nfs/rootfs                                        //查看根文
件系统是否创建成功

8)此时的文件系统还缺少了一些运行的库文件,需要将工具链中的libc库拷贝过去

cs 复制代码
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)将符号链接库删除,并拷贝真实的库文件

cs 复制代码
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库拷贝过去

cs 复制代码
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库拷贝过去

cs 复制代码
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)进入根目录文件系统查看这两个目录的大小

cs 复制代码
cd /home/linux/nfs/rootfs
du ./lib ./usr/lib -sh

与上图所示大小一样即为正确。

13) 创建其余文件夹

cs 复制代码
mkdir dev
mkdir proc
mkdir mnt
mkdir sys
mkdir tmp
mkdir root
mkdir lib/modules

14) 我们还需要完善下根我们系统中的配置文件,这些配置文件可以进一步完善Linux系统中的功能

  1. 创建/etc/init.d/rcS文件,并将文件修改为如下内容,该文件是一个shell脚本,Linux内核启动后需要启动的一些服务都可以通过该脚本进行配置
cs 复制代码
mkdir ~/nfs/rootfs/etc/init.d -p
touch ~/nfs/rootfs/etc/init.d/rcS
vim ~/nfs/rootfs/etc/init.d/rcS

修改文件内容如下:

cs 复制代码
#!/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
  1. 修改文件权限
cs 复制代码
chmod 0777 ~/nfs/rootfs/etc/init.d/rcS
  1. 创建/etc/fstab文件,并将文件修改为如下内容,在rcS脚本中执行mount -a,挂载所有文件系统,就会找到fstab文件,并进行文件挂载。
cs 复制代码
touch ~/nfs/rootfs/etc/fstab
vim ~/nfs/rootfs/etc/fstab

修改内容如下:

cs 复制代码
#<file system>  <mount point>   <type>  <options>   <dump>  <pass>
proc            /proc           proc    defaults    0       0
tmpfs           /tmp            tmpfs   defaults    0       0
sysfs           /sys            sysfs   defaults    0       0
  1. 创建/etc/inittab文件,该文件指定启动后一些代码的运行方式。
cs 复制代码
touch ~/nfs/rootfs/etc/inittab
vim ~/nfs/rootfs/etc/inittab

修改文件内容如下:

cs 复制代码
#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:用于生成轻量级、最基本的根文件系统(特点是缺少库、缺少软件);

buildrootyocto:可选择安装某些库、某些软件(用来扩展根文件系统的功能)。

用一张图来表示这个过程

开机自启动:代码写在/etc/init.d/rcS或者/etc/profile

4.总结

  1. 内核驱动静态编译和动态编译的区别?

静态编译

将驱动代码直接编译进内核映像(如zImage),成为内核的一部分。驱动随内核启动自动加载,无法单独卸载或更新。适用于核心功能或必须常驻的驱动。

优点:无需手动加载,性能略高;

缺点:需重新编译内核才能更新驱动。

动态编译

将驱动编译为独立模块(.ko文件),可动态加载或卸载。适用于非必需或需频繁调试的驱动。

优点:灵活性高,便于调试;

缺点:需手动管理模块依赖。

关键差异

集成方式:静态编译直接嵌入内核,动态编译生成独立模块。

维护性:动态编译支持热插拔,静态编译需全内核更新。

使用场景:核心驱动用静态,可选功能或调试阶段用动态。

相关推荐
s9123601013 小时前
RUST map_while 还是fillter_map
arm开发
来自嵌入式的zyz3 小时前
STM32学习-UART串口通信:物理层/协议层/UART基本架构/代码实战
stm32·嵌入式硬件·学习
La Pulga4 小时前
【STM32】USART串口(上)
c语言·stm32·单片机·嵌入式硬件·mcu
茯苓gao4 小时前
STM32G4 电流环闭环(二) 霍尔有感运行
笔记·stm32·单片机·嵌入式硬件·学习
涂山苏苏⁠4 小时前
STM32软件I2C读写AT24C64
stm32·单片机·at24c64
京雨4 小时前
关于RISC-V 中断处理的分析
单片机·嵌入式硬件·risc-v
fatfishccc4 小时前
(四)优雅重构:洞悉“搬移特性”的艺术与实践
java·驱动开发·intellij-idea·软件研发·后端开发·代码重构·搬移
cellurw4 小时前
Day51 时钟系统与定时器(EPIT/GPT)
单片机·嵌入式硬件·gpt
lingzhilab5 小时前
零知IDE——基于STM32F407VET6和MCP2515实现CAN通信与数据采集
stm32·单片机·嵌入式硬件