1).简介
设备树(DeviceTree)是一种用来描述系统硬件的数据结构,一些硬件设备设计机制就是可被系统发现的(如PCIExpress或者USB总线),而有一些则不是(尤其是内存映射外设)。对于后一种情况,不同于X86架构系统采用BIOS和操作系统沟通硬件拓扑信息,ARMLinux通常情况是将硬件设备描述硬编码到系统内核(LinuxKernel)中,但由于ARM嵌入式设备的多样和离散性,即便如此也不能保证覆盖到所有设备,而且长久以来给ARMLinux内核代码维护造成了很大负担;基于这种情况,设备树的概念就被提出,将ARMSOC和板卡硬件平台描述信息从内核独立出来成为设备树文件,通过bootloader传递给内核来识别当前平台设备并加载相应的资源和驱动,这样就把ARM嵌入式Linux内核统一起来,更好的利于内核维护,而对于广泛的ARM嵌入式设备系统维护和迁移也更方便和有效率。
设备树机制从Linux内核3.2版本左右开始采用,其不仅可以定义ARMSoC内部内存映射外设,还可以定义整个板卡,下面就以ToradexColibriVF61计算机模块搭配ColibriEvaBoard为例来展示设备树的具体应用,另外关于设备树的更深入介绍,请参考这里。
2).设备树文件说明
ToradexARM计算机模块工业产品级EmbeddedLinux源代码下载及编译指南请见这里,其中设备树文件位于Kernel源代码arch/arm/boot/dts/目录下。
设备树通常由多级别的多个设备树文件构成,一个设备树文件(dts和dtsi)可以包含另外一个可包含设备树文件(dtsi),如一个板卡级设备树文件(dts)一般会包含其所使用的SoC级别的设备树文件(dtsi)。如上图所示,为了支持Toradex产品,定义了三个级别的设备树文件:载板级别,模块基本以及SoC级别,这些区别也体现在了设备树文件的命名上面。
载板级别的设备树文件(如vf610-colibri-eval-v3.dts)定义自ColibriEvaBoard载板,但基于Colibri模块的标准定义,同样也兼容于其他Colibri载板(如Iris载板);不过如果用户针对自己应用定制了载板,则需要对应定制化设备树文件以便使能非默认定义功能设备(如第二个网口)或者关闭一些无用的设备。
设备树文件(dts)最后要被编译成设备树二进制文件(dtb)以供Linux内核启动加载所使用,所需的编译器也都集成在Linux源文件里面可以直接调用,从后面的示例可以看到具体的编译方法。
设备树文件的基本单元是node,一个设备树文件只能有一个rootnode(/),其他node按照parent/childnode以树状结构分布,每个node里面包含一些property/value来描述该node特性,如下面是一个UART设备的描述;另外低级别设备树文件的定义可以在更高级别的设备树文件中重新定义或者更改,最后生成的二进制文件以最后一次定义为准,因此我们定制化设备树文件时候通常只定制修改最高级别的载板级设备树文件即可;更详细的关于设备树文件语法的说明请见这里。
3).定制设备树文件
本文以ColibriVF61计算机模块和Evaboard载板为例,定制设备树文件以使能GPIO和CANbus。ColibriVybird系列产品设备树文件的架构如下图所示:
a).创建新的载板级别设备树文件,这里为了方便直接复制vf610-colibri-eval-v3.dts
----------------------------------------------------------------------------------------
$cparch/arm/boot/dts/vf610-colibri-eval-v3.dtsarch/arm/boot/dts/vf610-colibri-my-carrier.dts
----------------------------------------------------------------------------------------
b).编辑设备树文件vf610-colibri-my-carrier.dts,将默认配置为PWM设备管脚配置为GPIO
----------------------------------------------------------------------------------------
$vivf610-colibri-my-carrier.dts
----------------------------------------------------------------------------------------
//添加下面内容于设备树文件中
c).配置编译环境并编译新的设备树文件
./安装交叉编译ToolChain,请从这里下载
----------------------------------------------------------------------------------------
$tarxvfgcc-linaro-4.9-2014.11-x86_64_arm-linux-gnueabihf.tar.xz
$ln-sgcc-linaro-4.9-2014.11-x86_64_arm-linux-gnueabihfgcc-linaro
----------------------------------------------------------------------------------------
./配置环境变量
----------------------------------------------------------------------------------------
$exportARCH=arm
$exportPATH=~/gcc-linaro/bin/:$PATH
$exportCROSS_COMPILE=arm-linux-gnueabihf-
----------------------------------------------------------------------------------------
./修改arch/arm/boot/dts/Makefile文件,插入"vf610-colibri-my-carrier.dtb"
----------------------------------------------------------------------------------------
dtb-$(CONFIG_SOC_VF610)+=\
vf500-colibri-eval-v3.dtb\
vf610-colibri-eval-v3.dtb\
vf610-colibri-my-carrier.dtb\
vf500-colibri-dual-eth.dtb\
vf610-colibri-dual-eth.dtb\
vf610-cosmic.dtb\
vf610-twr.dtb
----------------------------------------------------------------------------------------
./编译设备树文件,源代码根目录linux-toradex下,生成的文件可以在arch/arm/boot/dts/下找到
----------------------------------------------------------------------------------------
$makecolibri_vf_defconfig
$makedtbs
----------------------------------------------------------------------------------------
4).部署新的设备树文件并测试
a).将新的设备树文件"vf610-colibri-my-carrier.dtb"放置到目标板ColibriVF61Linux系统/boot目录下
b).如下修改目标板uboot环境变量
----------------------------------------------------------------------------------------
$setenvfdt_board'my-carrier'
$saveenv
----------------------------------------------------------------------------------------
c).重启后则系统加载新的设备树文件
下面两个截图分别是更改前和更改后使用Toradex提供的GPIOConfig工具对PWM对应管脚进行查看,可以看到由原来的PWM属性变成了GPIO,修改成功后则可以按照这里的说明直接调用GPIO使用。
d).对于CAN,ColibriVF61支持两个CAN接口,CAN0和CAN1,在设备树中使能CAN设备示例如下
./编辑vf610-colibri-my-carrier.dts,添加下面内容
./和上述方法一样重新编译设备树文件后部署,然后就可以在系统中调用CAN了,更详细的说明可以参考这里。