社区导航

 

搜索
查看: 4611|回复: 1

[经验] BB Black 入门基础之 Device Tree

[复制链接]

1739

TA的帖子

24

TA的资源

五彩晶圆(初级)

Rank: 7Rank: 7Rank: 7

发表于 2014-1-18 21:18 | 显示全部楼层 |阅读模式
本帖最后由 lonerzf 于 2014-1-20 10:09 编辑

这两天手头事情还挺多的。抽空发个文章吧。写的不好,有错误的地方还请拍砖指正。
首先介绍两个概念(个人理解,如有错误请指正)

1 cape
根据 learn.adafruit.com/introduction-to-the-beaglebone-black-device-tree/device-tree-background的介绍,
cape是BeagleBone社区内由众多开发者提供的创意产品。近似可以理解为基于BeagleBone的外设扩展设计吧。

2 overlays
直译为层叠。但在这里明显不符合原意。应该是一种用于动态地将已经定义的cape加载到正在运行的内核中去的方法吧。

3 本文中与设备树相关的几个概念
dt  device tree                设备树
dtb device tree blob        设备树二进制容器
dtc device tree compiler  设备树编译器
dts device tree source     设备树源码
ocp on chip peripherals   片上外设

4 Device Tree概念
设备树是一种用来描述硬件的数据结构,而不需编写硬件设备的每个细节到系统中去。一个设备树在系统启动时会传递硬件许多方面的描述信息给系统。

下面就介绍下设备树
circuidipity.com/bbb-dt  和 elinux.org/BeagleBone_and_the_3.8_Kernel 里边对Device Tree有了一个比较简洁的介绍,大家可以看看。

部分内容整理总结如下:
      在X86硬件时代,一个Linux的分发版本可以使用一个通用的内核,然后启动时加载必要的驱动就可以在许多的硬件上运行。
然而ARM嵌入式设备却大不相同,很多硬件在启动时并不能检测到,因此需要对每个设备进行定制。设备树就是针对这个
问题提出来的,并且3.8内核的BeagleBone Black 是第一款使用了该方法的ARM设备。

在BeagleBone Black 中有一个系列的dtb二进制文件可以供内核使用,启动时,它就在/boot目录下。
可以查看一下
# ls /boot/*.dtb
通过使用DT,BB Black在继承上层内核开发的所有优点的同时避免了定制系统带来的麻烦。比如众多的cape就是很好的例子。
beagleboard.org/project/  下有很多,有兴趣的同学可以去看看。

A Device Tree
设备树是一种用来描述硬件的数据结构,而不需编写硬件设备的每个细节到系统中去。一个设备树在系统启动时会传递硬件许多方面的描述信息给系统。
在基于DT的系统中,用户可以配置平台而无需重编译内核。
pinmux子系统和时钟源、时钟事件框架就是两个从ARM进化到DT的例子。
对于开发人员,使用DT的最大的变化在于它纯粹是数据驱动的,并且自定义平台的驱动程序很多时候都令人难以接受,而不如选择使用通用的框架,其中之一是PINMUX框架。
总结起来就是,DT最大的改变是将之前已经在板级文件完成的工作搬移到一个通用的框架中去,将设备驱动抽象化,用数据来驱动软件。

B overlays
overlays允许设备树能在启动时被内核访问,并在随后的用户空间(user space) 中修改。如果像cape这类东西加入到BBB扩展板上,那么pinmux框架可以进行重新配置而不需要重启。默认的Angstrom系统附带了一系列的DT overlays. 在 /lib/firmware 可以看到。

C Cape Manager
cape管理器能够执行overlays的装载和卸载,slots(槽)是其提供的用户接口。
每个cape的信息都存储在EEPROM中,包括序号,编号,版本更新信息等,cape管理器需要的只是编号和版本号。
Cape 管理器会执行一下操作
1 通过I2C总线访问EEPROM,扫描系统参考手册中已经定义的相关的地址。这些地址为0x54-0x57,因此只能最多包含四个capes。
2 读取EEOROM内容,通过配置文件得到编号和版本号。
2 在配置中匹配PART-NUMBER:REVISION这样的元组,如果该cape已经连接BeagleBone Black,则会执行相应操作。

此外,还需要一些额外的方式来帮助我们开发capes。
手动控制功能。保证在没有EEPROM的板子上也能支持cape。
在系统运行时能加载cape的选项。
在系统运行时能卸载cape的选项。
能在被系统检测到时仍可以停止加载cape的选项。
为防止系统资源冲突,cape使用的资源另一个cape必须被禁止使用。
能够禁止哪些不被支持的cape版本的加载。
如果发生冲突,高优先级的cape能得到加载。如LCD cape优先级就要高于HDMI cape。
...

D Example

讲了那么多,今天让我们通过实际的例子来了解一下device tree overlay,看看dts文件到底怎么回事。
CONTROL_MODULE Registers一节,在am335x技术参考手册P1117上有
980h conf_uart1_rxd  
984h conf_uart1_txd

可知uart1_rxd和uart1_txd相对于800h的偏移量分别为180h和184h.
分别位于Header P9.24和P9.26. 注意这里的P9.24和P9.26是Header PIN9的第24和26引脚的意思。

先看看 BB-UART1-00A0.dts这个文件
  1. /*
  2. * Copyright (C) 2013 CircuitCo
  3. *
  4. * Virtual cape for UART1 on connector pins P9.24 P9.26
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License version 2 as
  8. * published by the Free Software Foundation.
  9. */
  10. /dts-v1/;
  11. /plugin/;

  12. / {
  13.    compatible = "ti,beaglebone", "ti,beaglebone-black";

  14.         /* identification */
  15.         part-number = "BB-UART1";
  16.         version = "00A0";

  17.         /* state the resources this cape uses */
  18.         exclusive-use =
  19.                 /* the pin header uses */
  20.                 "P9.24",        /* uart1_txd */
  21.                 "P9.26",        /* uart1_rxd */
  22.                 /* the hardware ip uses */
  23.                 "uart1";

  24.         fragment@0 {
  25.                 target = <&am33xx_pinmux>;
  26.                 __overlay__ {
  27.                         bb_uart1_pins: pinmux_bb_uart1_pins {
  28.                                 pinctrl-single,pins = <
  29.                                         0x184 0x20 /* P9.24 uart1_txd.uart1_txd MODE0 OUTPUT (TX) */
  30.                                         0x180 0x20 /* P9.26 uart1_rxd.uart1_rxd MODE0 INPUT (RX) */
  31.                                 >;
  32.                         };
  33.                 };
  34.         };

  35.         fragment@1 {
  36.                            target = <&uart2>; /* really uart1 */
  37.                            __overlay__ {
  38.                            status = "okay";
  39.                            pinctrl-names = "default";
  40.                            pinctrl-0 = <&bb_uart1_pins>;
  41.                        };
  42.                 };
  43.         };
复制代码

我们分别查看每段的用法及意义。
  1. /dts-v1/;
  2. /plugin/;
复制代码
表示用于描述dts文件的版本信息。并声明了这个文件的内容是一个plugin.
接下来是DT的起始标记
  1. / {
复制代码
接下来兼容性列表这一行表示该device tree overlay所支持的平台,兼容性最好的放在前面。这一行非常重要,兼容列表中没有列举的平台设备将不会被装载。
  1. compatible = "ti,beaglebone", "ti,beaglebone-black";
复制代码
下一个就是标识符 编号和版本。进一步确保只有合适的DT overlays可以被装载。
此外,要说明的是dts文件的命名规则为 -.dts .这里dts文件需命名为BB-UART1-00A0.dts
并且目前BeagleBone Blak所用的编号只能为00A0。
  1. /* identification */
  2. part-number = "BB-UART1";
  3. version = "00A0";
复制代码
专有属性允许overlays描述哪些资源它们需要,这样可以防止其他的overlays使用这些资源而导致冲突。本例中,P9.24和P9.26就是需要保护的资源。
  1. /* state the resources this cape uses */
  2.         exclusive-use =               
  3. /* the pin header uses */               
  4. "P9.24",        /* uart1_txd */               
  5. "P9.26",        /* uart1_rxd */               
  6. /* the hardware ip uses */               
  7. "uart1";
复制代码
接着是device tree片段。它们描述了哪一个目标对象(target)需要去overlay,然后每个片段都需要定制各自的引脚复用功能,或设备的使能。下面的片段看起来有点复杂,但是还算可以。首先我们要设置需要overlay的目标对象(target)。本例中target是am33x_pinmux,其实它和pinctrl-single是兼容的。只是am33xx_pinmux定义了芯片功能复用引脚的具体功能,它使用的还是pinctrl-single,pins这个驱动。

接下来银行的 __overlay__  表示节点本身。这里节点的第一个属性(bb_uart1_pins)会被下一个片段所使用。它包含了引脚的定义与复用,功能的屏蔽和更新。例如,一个设备的引脚可以用这种方式来设置pinctrl-single,pins = <0xdc 0x118>;这里0xDC表示了相对于pinctrl基地址的偏移量,0x118表示我们要在该寄存器中写入的值。
  1. fragment@0 {
  2.                 target = <&am33xx_pinmux>;
  3.                 __overlay__ {
  4.                         bb_uart1_pins: pinmux_bb_uart1_pins {
  5.                                 pinctrl-single,pins = <
  6.                                         0x184 0x20 /* P9.24 uart1_txd.uart1_txd MODE0 OUTPUT (TX)  */
  7.                                         0x180 0x20 /* P9.26 uart1_rxd.uart1_rxd MODE0 INPUT (RX)  */
  8.                                 >;
  9.                         };
  10.                 };   
  11.     };
复制代码

最后一个片段是使能UART设备。这里的目标对象是uart2,但实际上使用的是我们上边声明过的uart1。同样地,它引用了上面片段的属性(bb_uart1_pins)来映射pinctrl到uart中去。
  1. fragment@1 {
  2.                 target = <&uart2>; /* really uart1 */
  3.                 __overlay__ {
  4.                         status = "okay";
  5.                         pinctrl-names = "default";
  6.                         pinctrl-0 = <&bb_uart1_pins>;
  7.                 };
  8.         };
复制代码
有的人就想问了,那我怎么知道我的目标对象target名字是什么?我怎么知道它有哪些属性?取值范围又是什么?

下次再续~



基础内容暂时就这么些,肯定还有漏的,到时再补充。
还得唠叨下, 写的不好,有错误的地方还请拍砖指正。



这孩子,成熟的象征,理智的典范。


回复

使用道具 举报

6551

TA的帖子

8

TA的资源

版主

Rank: 6Rank: 6

发表于 2014-1-19 14:05 | 显示全部楼层
不错 不错

生活就是油盐酱醋再加一点糖,快活就是一天到晚乐呵呵的忙
===================================
做一个简单的人,踏实而务实,不沉溺幻想,不庸人自扰


回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

关闭

站长推荐上一条 1/8 下一条

  • 论坛活动 E手掌握

    扫码关注
    EEWORLD 官方微信

  • EE福利  唾手可得

    扫码关注
    EE福利 唾手可得

词云| Archiver|手机版|小黑屋|电子工程世界 ( 京ICP证 060456 )

GMT+8, 2020-7-10 15:11 , Processed in 0.134360 second(s), 22 queries , Gzip On, MemCache On.

快速回复 返回顶部 返回列表