回顾:
1.uboot的logo显示
目的
场合
原则
显示原理
图像->像素->颜 {MOD}->RGB
软件操作显存
画点/画线/画矩形/画圆/画LOGO
2.linux内核
问:uImage从何而来?
2.1.明确:嵌入式linux系统软件三部分
bootloader:uboot
linux内核:uImage
根文件系统rootfs
2.2.linux内核特点(吹牛)
2.3.linux内核七大功能
2.4.linux内核源码的操作
1.获取源码
2.获取正确的交叉编译器
3.验证源码是否正确
make distclean
make ABC_defconfig
make uImage
编译通过:
1.源码没毛病
2.版本配合
3.此时源码仅仅支持参考板,还不一定能够运行在自己的开发板上
一定要获取到硬件差异(硬件工程师)
4.根据硬件差异对源码进行修改
从以下两个方面对源码进行检查修改:
1.从内核源码的配置角度
make menuconfig
System Type->
//三个检查
Boot optios->
//检查内核的启动参数到底用谁的
Device Driver->
//各类硬件外设的驱动
Norflash/Nandflash驱动
输入设备驱动
键盘
触摸屏
鼠标
游戏摇杆
摄像头驱动
LCD显示屏驱动
声卡驱动
I2C总线驱动
SPI总线驱动
1-Wire总线驱动
USB驱动
TF卡/SD卡/EMMC驱动
File System->
//文件系统
EXT4
VFAT
NTFS
CRAMFS
UBIFS
JFFFS2
YAFFS2
NFS
2.从内核源码的跟硬件相关的源代码角度
切记只需关注一个跟开发板相关的硬件信息的源代码即可
此源代码又称平台相关代码:
内核源码根目录/arch/arm/plat-s5p6818/x6818/device.c
此文件务必仔细的多多看,里面记录了大量的硬件外设的硬件信息
例如:I2C外设的设备地址等
案例:打开X6818平台文件,慢慢品味此文件的奥秘
cd /opt/kernel
vim arch/arm/plat-s5p6818/x6818/device.c
仔细阅读!
vim arch/arm/plat-s5p6818/x6818/device.c +439
将四个LED灯的硬件信息代码注释掉
保存退出
vim arch/arm/plat-s5p6818/x6818/device.c +399
将:
#define GSLX680_I2C_BUS (1)
修改为:
#define GSLX680_I2C_BUS (2)
说明:将触摸屏GLSX680芯片连接到CPU的I2C总线编号由第2个改成第3个
保存退出
make uImage -j2/j4/j8
cp arch/arm/boot/uImage /tftpboot
下位机测试:
重启下位机进入uboot命令行执行
tftp 48000000 uImage
bootm 48000000
系统启动完毕,查看呼吸灯是否还在闪烁
查看触摸屏是否还能正常操作
注意:实验做完,将触摸屏的I2C总线编号再次修改为1
2.5.问:linux内核的配置菜单如何实现呢?
如何在已有的菜单中添加自己的代码编译菜单
答:明确:内核的配置菜单的作用就是便于用户通过
菜单的形式向内核uImage添加或者删除某个功能
某个硬件设备驱动程序
要实现此功能,只需Kconfig和Makefile即可
1.linux内核Kconfig的基本语法
Kconfig功能就是生成一个菜单选项
常用的关键字:
config:用于生成一个菜单选项
tristate:指示此菜单选项的操作方式有三种
按Y键选中为*/按M键选中为M/按N键不选
bool:指示此菜单选项的操作方式有两种
按Y键选中为*/按N键不选
help:指示此菜单选项的帮助信息
注意:
按Y键选中为*:表示选中选项,并且将这个选项对应的
源代码和uImage编译在一起(在一起)
按M键选中为M: 表示选中选项,并且将这个选项对应的
源代码和uImage分开单独编译(分家)
按N键不选中:不会编译对应的源代码
例如:
config HELLO_WORLD
(TAB)tristate "hello,world"
(TAB)help
"this is a test msg"
说明:
config HELLO_WORLD:最终生成一个菜单选项
选项的名称为:CONFIG_HELLO_WORLD
总结:
config A:将来生成的菜单选项为:CONFIG_A
CONFIG_A将来是给Makefile文件使用,Makefile文件
使用格式:obj-$(CONFIG_A) += 源文件.o
说明如下:
1.如果按Y键选中为*,那么CONFIG_A=y
展开:obj-y += 源文件.o
表示将源码和uImage编译在一起
2.如果按M键选中为M,那么CONFIG_A=m
展开: obj-m += 源文件.o
表示将源码和uImage分开编译
3.如果按N键不选中,那么CONFIG_A=空
展开:空
表示源码不进行编译
案例1:向内核添加LED驱动程序,实现开关灯操作
目前采用将驱动和uImage编译在一起的方式
实施步骤:
上位机执行:
1.获取LED驱动程序和测试程序:
ftp://porting/led_drv.tar.bz2/
led_drv.c //LED驱动程序
led_test.c //LED应用测试程序
2.拷贝驱动到内核源码中
cp led_drv.c /opt/kernel/drivers/char/
3.添加LED的配置菜单
vim /opt/kernel/drivers/char/Kconfig 添加如下内容
config TARENA_LED
(TAB键)tristate "tarena led driver"
(TAB键)help
"this is a led driver"
保存退出
内心有个想法:将来生成的选项:CONFIG_TARENA_LED
4.添加LED驱动的编译支持
vim /opt/kernel/drivers/char/Makefile 添加如下内容:
obj-$(CONFIG_TARENA_LED) += led_drv.o
保存退出
5.配置内核添加LED驱动
cd /opt/kernel
make menuconfig
Device Drivers->
Character devices --->
//按Y键选择为*
<*> tarena led driver (NEW)
保存退出
vim .config //搜索CONFIG_TARENA_LED检查是否等于y
make uImage -j2/j4/j8
cp arch/arm/boot/uImage /tftpboot
注意:此时此刻的uImage就有了LED驱动程序
6.交叉编译测试程序
cp led_test.c /opt/rootfs/ //拷贝测试程序到根文件系统rootfs
cd /opt/rootfs/
arm-cortex_a9-linux-gnueabi-gcc -o led_test led_test.c
下位机测试:
进入uboot命令行执行:
tftp 48000000 uImage
bootm 48000000 //前提是内核根据NFS找根文件系统
下位机的linux系统启动完毕,执行:
cd /
ls
led_test
./led_test on //开灯
./led_test off //关灯
案例2:向内核添加LED驱动程序,实现开关灯操作
采用将驱动和uImage编译分开编译
上位机执行:
1.配置内核添加LED驱动
cd /opt/kernel
make menuconfig
Device Drivers->
Character devices --->
//按M键选择为M
tarena led driver (NEW)
保存退出
vim .config //搜索CONFIG_TARENA_LED检查是否等于m
make uImage -j2/j4/j8 //单独重新编译内核源码
cp arch/arm/boot/uImage /tftpboot
注意:此时此刻的uImage就没有了LED驱动程序
2.单独编译内核LED驱动
cd /opt/kernel
make modules //采用模块化编译
ls drivers/char/led_drv.ko -lh //查看单独编译的LED驱动程序的目标文件
注意:内核源码采用模块化编译,对应的二进制文件名称为xxx.ko
led_drv.c->led_drv.ko
cp drivers/char/led_drv.ko /opt/rootfs/ //拷贝驱动的目标文件到根文件系统rootfs
下位机执行:
进入uboot命令执行:
tftp 48000000 uImage //此时uImage没有LED驱动
bootm 48000000
下位机的linux系统启动完毕,执行:
cd /
ls
led_drv.ko(驱动二进制文件) led_test(应用测试程序)
insmod led_drv.ko //安装驱动程序到uImage,insmod=insert module
lsmod //查看安装的驱动程序
./led_test on
./led_test off
rmmod led_drv //从uImage中卸载安装的驱动程序
//卸载时无需添加.ko后缀
*************************************************
3.根文件系统rootfs
问:上位机的根文件系统/opt/rootfs
向下位机烧写的根文件系统镜像rootfs_ext4.img
从何而来?
3.1.明确:根文件系统rootfs特点
根文件系统rootfs仅仅是一个代名词而已,不代表任何东西和意义
根文件系统rootfs包含的内容(cd /; ls看到的内容)有:
bin目录:各种命令
sbin目录:各种超级用户命令
lib目录:各种库
etc目录:各种服务配置
usr目录:各种命令
...
以上这些内容聚集在一起形成了根文件系统rootfs
3.2.根文件系统rootfs中包含的内容总体分两部分
必要目录和可选目录
切记必要八大目录如下:
bin目录:各种命令,例如:ls,cd等
sbin目录:各种超级用户命令,例如:mknod等
lib目录:各种库,例如:libc*
etc目录:各种服务配置:etc/default/tftd-hpa等
usr目录:各种命令,例如:top等
dev目录:硬件设备对应的设备文件
proc目录:作为procfs虚拟文件系统的入口
sys目录:作为sysfs虚拟文件系统的入口
可选目录:
home:用户主目录
tmp:临时目录
var:临时目录
mnt:U盘/TF卡/SD卡的挂节点(入口)
问:有了必要目录和可选目录,每一个目录下的内容
(各种命令,各种库)如何添加呢(总不能自己编写)?
答:利用大名鼎鼎的开源软件busybox
3.3.谈谈busybox的特点(吹牛)
1.是一款著名的开源软件,外号“瑞士军刀”
官网:www.busybox.net
2.busybox跟硬件信息不相关
3.不要指望busybox提供根文件系统所有的软件
busybox仅仅提高各种命令
4.建议实际开发最好自己利用busybox制作一个根文件系统
而不是使用官方的根文件系统rootfs
3.4.利用busybox制作根文件系统rootfs的流程
1.获取busybox源码
从www.busybox.net直接下载获取即可
ftp://porting/busybox-1.21.1.tar.bz2
2.获取正确的交叉编译器
确保交叉编译器的版本和busybox的版本门当户对
3.busybox源码的交叉编译
3.1.源码解压缩
cp busybox-1.21.1.tar.bz2 /opt/
cd /opt
tar -xvf busybox-1.21.1.tar.bz2 //得到busybox源码目录:busybox-1.21.1
mv busybox-1.21.1 busybox //重命名
3.2.修改Makefile
cd /opt/busybox //进入busybox源码根目录
vim Makefile +190
将
ARCH ?= $(SUBARCH)
修改为:
#指定将来根文件系统运行在ARM架构
ARCH=arm
保存退出
vim Makefile +164
将
CROSS_COMPILE ?=
修改为
#指定交叉编译器
CROSS_COMPILE=arm-cortex_a9-linux-gnueabi-
保存退出
3.3.配置busybox源码
cd /opt/busybox
make menuconfig
Linux Module Utilities --->
//按N键去除选项(insmod/lsmod/rmmod精简版命令)
[*] Simplified modutils (NEW)
去除以上选项,立马出现完整版的命令选项:
[*] insmod (NEW) │ │
[*] rmmod (NEW) │ │
[*] lsmod (NEW)
[*] Pretty output (NEW)
[*] Blacklist support │ │
[*] modprobe (NEW) │ │
[*] depmod (NEW)
保存退出
注意:目前busybox提供的命令已经足够使用
3.4.正式交叉编译源码
cd /opt/busybox
time make -j2/j4/j8
make install //安装编译busybox生成的各种二进制文件
//也就是将编译生成的各种二进制文件统一
拷贝到某个目录下
ls _install/ //查看编译生成的内容
linuxrc bin sbin usr //验证了busybox仅仅提高各种命令
ls _install/bin/* -lh
ls _install/sbin/* -lh
ls _install/usr/bin/* -lh
ls _install/usr/sbin/* -lh
结论:所有的命令本质就是一个软连接文件
最终都连接到_install/bin/busybox
也就是编译busybox本质就是生成了一个
可执行文件bin/busybox
3.5.创建必要目录和可选目录
mv /opt/rootfs /opt/rootfs_bak //备份原先的根文件系统
cp /opt/busybox/_install /opt/rootfs -frd
cd /opt/rootfs //进入自己制作的根文件系统的根目录
//创建必要目录
mkdir dev lib etc proc sys
//创建可选目录
mkdir home tmp var mnt
3.6.添加部署必要的动态库
明确:
1.动态库添加到根文件系统的lib必要目录
2.要拷贝的动态库来自于交叉编译器
3.获取一个应用程序运行时所需的动态库:
cd /opt/rootfs
//获取busybox可执行程序的所需的动态库
arm-cortex_a9-linux-gnueabi-readelf -d bin/busybox 内容如下:
共享库:[libm.so.6] //标准数学运算库
共享库:[libc.so.6] //标准C库
结论:busybox所需的动态库为:libm.so.6和libc.so.6