作者:华清远见讲师
在树莓派的系统中,提供了很多的现成的驱动程序和资源,尽管这样,还是远远不能适用于大部分情况下的设计使用,所以在使用某些设备时,需要自行编写或者修改一些驱动,以适用于想要控制的设备。
1.开发环境和准备
(1)我的开发环境为ubuntu 14.04。
(2)连接树莓派查询系统版本
命令: uname -a
说明:方式很多,可以只接在Raspberry Pi桌面系统中的终端输入此命令查询;也可以在windows环境下使用SSH远程登陆树莓派查询;也可以再Linux环境下远程登陆树莓派进行查询。我选择的是最后一种情况,因为我的Linux环境是真机安装。
在Linux下安装Putty:
命令:sudo apt-get install putty
安装完成后,就可以直接可以使用了。
执行命令: sudo putty
如下图:
如上图所示,界面和再windows环境下的一模一样,所以直接登陆即可,最后查询到所使用的树莓派系统的版本好,如下图:
如上图可知,我的Raspber Pi系统为Linux raspberrypi 4.1.12-v7+版本。这一点很重要,将决定需要编译的内核版本。
2.获取内核源码,交叉编译工具链和固件
(1)获取Raspber Pi系统内核源码
树莓派官方将树莓派相关的大部分资源都放在了GitHub上,所以只需再GitHub的相应板块找到即可,如下图:
链接地址为:https://github.com/raspberrypi
所以直接在Linux栏目中就能找到相关的内核源码了。
链接地址:https://github.com/raspberrypi/linux/tree/rpi-4.1.y
如下图:
如上图,即为4.1版本的内核源码了,如果为其他版本可以再下拉框自行选择。将其克隆下来:
命令: git clone --depth=1 https://github.com/raspberrypi/linux/
如果网络不稳定或较慢的话,直接选择Download ZIP下载压缩包即可,下载成功后再解压。因为git不支持断点下载。
不过不知道出了什么问题,我直接下载的zip压缩文件有问题,不能编译通过,所以只能使用克隆的方式。
(2)获取交叉编译工具链
同样的在GitHub的RaspberryPi板块也提供了tools工具资源,如下图:
链接地址:https://github.com/raspberrypi/tools/tree/master/arm-bcm2708
如上图可见tools再板块上的路径,再路径下找到相应交叉编译工具链,可知树莓派官方提供了3种交叉编译工具链(最下方的是同一个工具链,只是针对32bit系统和64bit系统做了区分),先将其克隆下来。
命令: git clone https://github.com/raspberrypi/tools
(3)获取固件
同样的是再GitHub的Raspberripi板块获取,如下图:
如上图所示,即为相应的固件了,直接克隆下来即可。
命令:git clone https://github.com/raspberrypi/firmware
3.获取当前树莓派系统的配置文件
这里很有必要说明是,在raspberrypi系统的3.x版本以前,树莓派系统默认存在/proc/config.gz文件,但是更新到4.x版本之后,/proc/config.gz文件默认不存在了,所以我们需要先获取到这个文件。
执行命令:sudo modprobe configs
执行以上命令之后,会在/proc/目录下生成config.gz文件。然后将此文件从树莓派系统内拷贝到我们的PC平台(有很多种方法,比如U盘,NFS系统文件共享,TCP,samba等等)。
然后在需要编译的内核的顶层目录下执行命令:
命令:zcat config.gz > .config
目的是生成.config配置文件
4.编译前的准备
(1)确定树莓派系统内的编译器版本。
在putty上使用命令 cat /proc/version查询树莓派系统的编译器的 版本号。如下图:
如上图所知,gcc编译器的版本号为4.8.3版本,并且更新时间为2014年3月3日。
(2)选择编译工具链的版本,因为下载到的交叉编译工具链有三个版本,所以应该选择其中一个,但是考虑到版本的匹配问题(如果编译器的版本和原有系统的版本不一样的话,有可能会出现一些莫名奇妙的问题,特别是在开发驱动时)。下面查看各个编译器的版本。
arm-bcm2708hardfp-linux-gnueabi编译器:切换到tools/arm-bcm2708/arm-bcm2708hardfp-linux-gnueabi/bin/目录下,
使用命令:./arm-bcm2708hardfp-linux-gnueabi-gcc –v
如上图可见此编译器为4.7.1版本,并且也能看到更新的时间。但是版本比现有系统的版本要低了。
arm-bcm2708-linux-gnueabi编译器:切换到tools/arm-bcm2708/arm-bcm2708-linux-gnueabi/bin/目录下,
使用命令:./arm-bcm2708-linux-gnueabi-gcc –v
如上图可见,此编译器也为4.7.1版本,只是更新时间不同。
gcc-linaro-arm-linux-gnueabihf-raspbian编译器:切换到tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian/bin/目录下,
使用命令:./arm-linux-gnueabihf-gcc –v
如上图可见,此编译其为4.8.3版本,并且更新时间为20140106.并且适用于32bitPC平台。
再看gcc-linaro-arm-linux-gnueabihf-raspbian-x64 编译器:切换到tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin/目录,使用命令:./arm-linux-gnueabihf-gcc –v
如上图,可知此版本的编译器和逼着树莓派系统的编译器版本是同一个版本,所以理当使用它进行编译。不过呢这是64bit PC平台的编译器,如果是32为平台的电脑,使用gcc-linaro-arm-linux-gnueabihf-raspbian编译器即可。我现在的环境是32bit的环境,再记录本文前,我已经使用64bit PC平台编译过了!没问题。
(3)安装编译工具链
在这里我并没有将gcc-linaro-arm-linux-gnueabihf-raspbian编译工具链安装在我的环境上,因为我已经安装过其他版本的用来开发其他产品的工具了。为了不引起冲突,我不进行这一套工具链的安装,而是直接选择简单暴力的方式,将工具链添加到Makefile中。
切换到所编译内核的顶层目录,并打开目录下的Makefile文件,修改如下图:
没错,我直接添加了绝对路径的交叉编译工具链,但是为了能够还原,所以我对原始的进行了备份。这和将编译器安装再环境中是等价的,只是这个比较简单粗暴。
5.开始编译
(1)执行命令:make bcm2835_defconfig
在这里以bcm2835_defconfig举例,主要是生成.config配置文件。可以自行选择合适的,或者拷贝树莓派系统里的,上面也讲到了获取树莓派系统配置的文件,如果使用从树莓派copy过来的.config文件,则此步省略!
(2)执行命令: KERNEL=kernel7
(3)执行命令:make zImage modules dtbs
这句就是真正的编译了,等等完成吧!如果电脑满足要求的话,可以再make的后面加上-j2,-j4,-j6,-j8等等,表示使用多少个线程进行编译,可以提高编译速度,等待成功吧。编译成功后,在路径arch/arm/boot/下会生成zImage镜像文件。
zImage 是 Compressed kernel image 文件,它是一种可执行的镜像文件,但是对于树莓派系统的构建而言,这还不是我们最终想要的,所以还需要将其转换为kernel.img文件。
(4)安装编译的模块驱动
执行命令:mkdir modules
执行命令:sudo make INSTALL_MOD_PATH=modules modules_install
在源码顶层目录下的modules会生成相关的驱动库。
(5)镜像转换
kernel.img镜像是通过工具将zImage转换而来的!而工具存在于前文所下载的工具包里。工具名为mkimage,切换到工具目录(具体情况根据自己存放的目录路径确定,找到工具即可),如下图:
然后执行命令:./imagetool-uncompressed.py ../../../kernel/linux/arch/arm/boot/zImage
注:命令的执行,视自己的存放路径而言,注意路径即可。
命令执行成功后,会在当前目录下生成kernel.img文件,如下图:
如上图生成的kernel.img文件即为所需要的树莓派内核所需要的镜像文件了。
6.备份firmware
(1)创建备份目录
命令:mkdir backup
(2)备份
当插入SD卡后,立即就被识别了,可以将SD卡设备挂载到某目录上进行访问,也可以直接访问。默认在/media/wrw/目录下(madia目录为PC平台下根目录下的子目录,wrw为当前登陆用名子=字的子目录)会看到两个目录,此即为SD卡的两个分区(分别是fat32属性的分区和ext4属性的分区),如下图:
如上图可知,boot目录为fat32分区的目录,另一个为ext4分区的目录。而我们要备份的是boot目录,因为ext4分区的目录其实就是作为树莓派再运行是的跟文件系统。
执行命令:cd /media/wrw/boot/ 切换到目录,
执行命令:sudo cp *.elf *.bin ~/Reapberry_Pi/kernel/backup/
执行命令:ls ~/Reapberry_Pi/kernel/backup/ 查询是否备份成功,
执行命令: sudo rm *.elf *.bin
因为kernel可以通过在/boot/config.txt中进行设定,所以可以先不拷贝出来。
7.升级RPi的kernel、Firmware和lib
(1)修改前面生成的kernel.img文件的名称。
因为我前面打包编译好的zImage内核镜像时,直接打包成了kernel.img这个名称,为了区别于SD卡的内核名称,现在为它重命名,如下图:
如上图,改名为kernel_new.img。
(2)将新内核镜像拷贝到SD卡的fat32分区,即在这里是拷贝到名为boot的分区。
执行命令:sudo cp kernel_new.img /media/wrw/boot/
(3)修改树莓派系统的配置文件。
在SD卡的FAT32分区,存在一个名为config.txt的文件。
在/media/wrw/boot目录下执行命令:sudo vim config.txt
如下图:
在config.txt文件的前面添加“kernel=kernel_new.img”这行,如果原来有的话,就修改一下。这样系统就会引导到我们刚刚拷入的kernel_new.img镜像;或者是直接将目录中的kernel.img通过命令rm删除,然后将kernel_new.img改名为kernel.img。
(4).解压前面下载的Firmware固件压缩包
执行命令:unzip firmware-master.zip
执行命令:cd firmware-master/
boot/
(5)升级firmware固件
执行命令:sudo cp bootcode.bin fixup.dat fixup_cd.dat start.elf /media/wrw/boot/
执行命令:cd ../hardfp/opt/
现在开始操作第二分区,即xt4分区,再我这里它的名为“13d368bf-6dbf-4751-8ba1-88bed06bef77”,不过名字不是最重要的。
执行命令:sudo cp -r vc/ /media/wrw/13d368bf-6dbf-4751-8ba1-88bed06bef77/opt/
命令含义是,将新固件的vc库复制到树莓派系统的根文件系统下的opt子目录下,注意,这里如果使用的是arm-bcm2708-linux-gnueabi编译器,非硬浮点,那么在拷贝vc时,应该拷贝的是firmware-master/opt/目录下的vc。
(6)升级模块驱动lib。
切换到前面在Linux内核源码目录下创建的module目录下。
执行命令:cd ../../../kernel/linux/modules/ 这是我的路径,可根据自己的路径进行调整。
将modules目录下的lib目录copy到树莓派根文件系统下,
执行命令:sudo cp -r lib/ /media/wrw/13d368bf-6dbf-4751-8ba1-88bed06bef77/
8.享用新的kernel
将SD卡插回树莓派!就可以看到其可以正常启动了。那么代表这树莓派raspberrypi操作系统内核源码的编译成功。这样,后面就可以自由的添加各种驱动了。
文章源自华清远见嵌入式学院:http://www.embedu.org/