1.为什么要使用交叉编译
树莓派中已经安装了gcc工具链,可在树莓派中直接编译源代码生成可执行文件。于此同时,PC机上也可使用gcc工具链生成可执行代码,但是和树莓派上的gcc工具不同,PC机上的gcc工具生成intel或amd芯片上可执行的代码,但树莓派却是arm系列的芯片,显然存在不小的差异。那么使用交叉工具链便可在PC机上开发树莓派中可执行程序。
虽然树莓派的主频可达700MHz远高于一般的嵌入式系统,但相比于PC机其性能还是差些,使用交叉工具链可节约开发时间。在编译链接同等规模的代码时,PC机所用的时间应少于树莓派所用时间,通过交叉编译的方法可以提高效率。
当然,树莓派官方已经为我们提供了移植好的Linux和相关的编译工具链,可以从github.com/raspberrypi 下载所需内容。
2.树莓派上的操作(树莓派B+)
首先树莓派升级:
sudo apt-get update
sudo apt-get upgrade
sudo rpi-update(升级树莓派内核到最新版)
sudo reboot
zcat /proc/config.gz > .config(拷贝树莓派相关配置)
通过samba服务器移动.config文件到PC桌面
3.PC端的操作
打开PC上的虚拟机,我用的是Debian7。
创建树莓派Linux和工具链下载目录:mkdir /home/xfw/rpi
切换到该目录下:cd /home/xfw/rpi
通过git下载先相关内容,时间较长,一般开两个终端同时下:
git clone git://github.com/raspberrypi/linux.git RpiLinux
git clone git://github.com/raspberrypi/tools.git RpiTools
下载github.com/raspberrypi/firmware/extra/Module.symvers到rpi/下
下载完之后,rpi/下将出现两个目录和一个文件:RpiLinux、 RpiTools、Module.symvers
进入RplLinux目录:cd RpRplLinux
清理下,以便重编译:make mrproper
将PC桌面的.config文件传到/home/xfw/rpi/RpiLinux下
指定平台和交叉编译工具链:
nano /home/xfw/rpi/RpiLinux/Makefile
修改:ARCH ?= arm
CROSS_COMPILE ?= ../RpiTools/arm-bcm2708/arm-bcm2708hardfp-linux-gnueabi/bin/arm-bcm2708hardfp-linux-gnueabi-
在RpiLinux/下:make modules_prepare
移动之前下载的文件Module.symvers到RpiLinux/下
4.简单的驱动--Hello world
在rpi/目录下创建learndriver子目录,作为编写的驱动模块的存放位置。创建hello目录,分别创建hello.c和Makefile文件。相关代码如下:
hello.c
#include <linux/init.h>
#include <linux/module.h>
MODULE_LICENSE("Dual BSD/GPL");
static int __init hello_init(void)
{
printk(KERN_ALERT "Hello world\n");
return 0;
}
static void __exit hello_exit(void)
{
printk(KERN_ALERT "Hello world exit.\n");
}
module_init(hello_init);
module_exit(hello_exit);
Makefile文件:
ifeq ($(KERNELRELEASE),)
KERNELDIR ?= /home/xfw/rpi/RpiLinux
PWD := $(shell pwd)
all:
make -C $(KERNELDIR) M=$(PWD) modules
clean:
rm -rf *.o *~ core .depend .*.cmd *.mod.c .tmp_versions
.PHONY: clean
else
obj-m := hello.o
Endif
解释:这个Makefile在一次典型的建立中要被读 2 次. 在第一次读取执行此Makefile时,KERNELRELEASE没有被定义,所以make将读取执行else之后的内容,如果make的目标是clean,直接执行clean操作,然后结束。当make的目标为all时,-C $(KDIR)指明跳转到内核源码目录下读取那里的Makefile;M=$(PWD) 表明然后返回到当前目录继续读入、执行当前的Makefile。当从内核源码目录返回时,KERNELRELEASE已被定义,kbuild也被启动去解析kbuild语法的语句,make将继续读取else之前的内容。else之前的内容为kbuild语法的语句,指明模块源码中各文件的依赖关系,以及要生成的目标模块名。
obj-m := hello.o表示编译连接后将生成param.ko模块。如果你有一个模块名为 module.ko, 是来自 2 个源文件( 姑且称之为, file1.c 和 file2.c ), 正确的书写应当是:
obj-m := module.o
module-objs := file1.o file2.o
编辑完成后,在learndriver/hello/目录下,执行操作:make,将生成hello.ko文件。将该文件通过samba服务器复制到树莓派/home/driver/hello下,树莓派上终端cd到/home/driver/hello目录下,执行:sudo insmod hello.ko,没有信息说明模块已经安装。
查看模块信息:
至于信息为何没有打印到终端,我也不大清楚。查看用以下命令查看系统日志:
dmesg | tail -8
或cat /var/log/kern.log | tail -10
很多人都说在/var/log/messages下,但打开发现不在。
5.驱动模块相关操作命令:
insmod / modprobe 加载驱动
rmmod 卸载驱动
lsmod 查看系统中所有已经被加载了的所有的模块以及模块间的依赖关系
modinfo 获得模块的信息
查看已经加载的驱动模块的信息:
lsmod 能够显示驱动的大小以及被谁使用
cat /proc/modules 能够显示驱动模块大小、在内核空间中的地址
cat /proc/devices 只显示驱动的主设备号,且是分类显示
/sys/modules 下面存在对应的驱动的目录,目录下包含驱动的分段信息等等。