是不是一切的Linux内核都是完美的?究竟许多黑客效能于此,当然不是,至少在内核3.x版别之前不是,之前的代码臃肿,代码利用率较低,直到设备树的引进,彻底改进这一状况;
一、FDT的概念
体系发动时,Bootloader开端加载,将内核文件,如zImage读取到内存中,内核依照咱们的代码,逐一去装备每个寄存器,每个外设,好像没有什么问题。可是试想一下,100种ARM芯片,就要写100个装备文件么?当然,假如你非要这么做,我也无话可说。假如能笼统出一种数据结构,它能够直接笼统出内核需求装备的一切硬件以及硬件特点,BootLoader预读取到内存中,在内核发动今后,能够直接装备,关于用户而言,装备MCU的外围时咱们直接面临的就仅仅这个DTS文件,极端方便快捷。FDT精确来讲是一种数据结构,使得硬件能够用形如XML的描绘言语来描绘。
二、设备树结构
图一 设备树结构
设备树一般包含以上内容:
Ø 根节点“/”下的model ,这个一般为字符串类型,它描绘了厂商以及板子称号;
Ø 根节点“/”下的compitable,这个一般为字符串类型,用以匹配model选定的开发板对应的代码;包含后续外围驱动的匹配均是有这个compitable来完结;
Ø 根节点“/”下的aliases,这个设备节点只能放在根节点目录,首要用以寄存外设的别号,简略讲,"/soc/aips-bus@02000000/spba-bus@02000000/serial@02020000"其实是一个串口,可是开发人员自己看起来并不直观,我能够在aliases中写作:serial ="/soc/aips-bus@02000000/spba-bus@02000000/serial@02020000";serial即可替代方才的串口设备;
Ø 根节点“/”下的chosen:这个并非物理设备节点,而是内核发动参数的节点,类似于uboot阶段的bootargs参数;
当然,这个节点也能够是子节点,不一定要在根节点下;
实例:chosen {
stdout-path = &uart1;
};
Ø snvs@020b0000:除以上节点,剩余的我一般称之为物理设备节点(或许不精确),以snvs外设举例,直接举例;
实例:snvs@020b0000{
conpitable = “fsl,imx6ul-snvs”;
reg = <0x020b0000 0x4000>;
interrupts = <0x0 0x4 0x4>;
};
(1)“@”后边紧跟便是该外设在MCU总线的地址,这个不难了解,能够了解为外设的基地址,外设模型 name@addresss;”
(2)“compitable”:如上陈说,十分要害的特点,匹配外设驱动,特点模型 compitable = “[manufacture,[model]]”;
(3)“reg”:该特点为外设地址特点,第一个参数为该节点总线地址,后者为地址长度;
(4)“interrupt”:望文生义,该外设的中止,para1表明该中止是不是SPI中止(shared peripheral interrupt),留意名词区别,参数值为1表明为SPI中止,反之不是SPI中止;para2是该中止号;para3表明触发方法,参数值为1,表明上升沿触发,为4表明高电平触发;假如需求低电平以及下降沿触发,硬件需求加非门;
三、编译设备树与反编译
设备树编译,咱们都知道运用如下指令编译:
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- dtbs 或许
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- all
实际上,是dtc这个文件在担任把dts解说成dtb文件,该文件在内核源码根目录 ./scripts/dtc
编译指令:
./scripts/dtc/dtc –I dts –O dtb /home/gyh/tmp/imx6y2c-256m.dtb ./arch/arm/boot/dts/imx6y2c-256m.dts
反编译指令:
./scripts/dtc/dtc -I dtb -O dts -o /home/gyh/tmp/imx6y2c_asm.dts ./arch/arm/boot/dts/imx6y2c-256m.dtb
关于Linux指令的运用,能够运用help cmdname 或许man cmdname,关于dtc,非内建指令,man dtc:
-I <input format>
Input formats are:
dts – device tree source text
dtb – device tree blob
fs – /proc/device-tree style directory
-O <output format>
Output formats are:
dts – device tree source text
dtb – device tree blob
asm – assembler source
体系供给的dts一般引证dtsi这个母设备树,所以很多外设都是直接引证dtsi中的,因而很难了解这些字符串是怎样的匹配驱动程序的,可是一旦将现已出产的dtb文件反编译,出产的dts文件将更直观;可是易读性也更差。这并不矛盾;我挑选,” /” ,”chosen” ,”aliases”三个节点来比照。
图二 BSP供给的dts文件
图三 反编译的dts文件
对同一个chosen节点:BSP中dts描绘为stdout-path = &uart1;这样很难幻想它是怎样把该外设界说为规范输出的,可是假如看反编译文件能够较好的了解,规范输出被重定向到某个能够作为输出的外设地址;
四、设备树节点添加与验证
(1)直接在dts文件中查找,是否现已存在你需求的外设节点;假如有,且该外设支撑多从机或许多节点,直接在该节点下面,添加子节点,以GPIO_LED为例。
图四 GPIO_LEDS节点
(2)假定,你需求添加一个黄色的LED,那么仿照现已存在的节点,仿制一个节点在母节点下,命名为green-led,一起用GPIO3_4为该LED驱动引脚;你期望在arm板上叫他,My_Cute(这个姓名欠好),那么最终修正如下:
图五 添加yellow-led节点
(3)节点添加完结,引证了GPIO3_4,所以你需求承认该MCU引脚现已装备为GPIO功用,这儿直接贴出装备代码:MX6UL_PAD_LCD_RESET__GPIO3_IO04 0x40017059
图六 引脚装备为GPIO
该宏界说MX6UL_PAD_LCD_RESET__GPIO3_IO04在./arch/arm/boot/dts/imx6ull-pinfunc.h中;针对同一个引脚的悉数复用,均界说了宏,能够直接调用;该dts并未直接包含imx6ull-pinfunc.h,在其他dtsi中现已包含该头文件;
(4)假如之前现已彻底编译过内核,能够直接编译dtb,留意不要make menuconfig或许defconfig,否则会掩盖zImage的装备文件.config;
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- dtbs
(5)编译完结后,开发板直接进入uboot形式,tftp网络烧写dtb,reset重启收效;
run updtb
(补白:updtb为组合指令updtb=if tftp ${fdt_file}; then nand erase.part dtb; nand write ${loadaddr} dtb ${filesize}; fi;)
(6)假如dtb依照咱们了解修正是正确的,那么咱们将在开发板的/sys/class/leds下面看到咱们的My_Cute这个LED节点;成果如下:
图七 开发板设备截图
其实,能够看到/sys/class/leds下面的设备节点都是指向/devices/platfome/leds目录的衔接文件,也便是这儿仅仅是这个设备的“快捷方法”,咱们也能够进行文件IO操作;
(7)文件IO操作:翻开My_Cute节点,能够看到以下接口能够操作,可是咱们在添加GPIO_LEDS并没有添加这些特点。Brightness, trigger—led亮度以及触发方法比较常用,那么问题来了,为什么会有这些接口。由于它们承继了母节点的特点,所以咱们需求找到母节点设备的界说。
图八 yellow-led的操作接口
(8)讲道理,一切的内核驱动你都能够测验在 ./driver/下面去找,针对led类,咱们直接进入leds文件夹,发现leds的驱动leds-gpio.c在,在这儿就能够了解led的接口为什么是这样;当然优异的驱动应该还有一份明晰的文档,你相同可也测验去源码根目录的. /Documentation 中查找leds-gpio的运用文档;这儿也会解说,我为什么会去开发板的/sys/class/leds下面去检查我添加的My_Cute节点;
图九 驱动运用文档
(9)添加一个驱动或许一个设备节点到设备树中,你能够先检查内核源码的/ Documentation目录,其间包含了简直一切驱动的运用说明以及设备树特点的解说,一起也包含很多优异的内核调试技巧;再去写节点,也能够先仿照,针对不明白的当地再来看文档,形象更为深入。
五、结语
设备树比较于传统的装备文件,无疑是降低了Linux外设开发与运用的门槛,可是也躲藏了很多的细节,难以了解其底层的驱动原理;关于LINUX内核的了解,我所知道的还不及冰山一角,单期望对你有一点协助。