beagleboneblack – 如何使用设备树覆盖在Beaglebone Black上添加i2c设备?

前端之家收集整理的这篇文章主要介绍了beagleboneblack – 如何使用设备树覆盖在Beaglebone Black上添加i2c设备?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
为什么要读这个?

如果您有一个Beaglebone Black(BBB),并且想要将自己的设备连接到它(不是capes),那么您可能已经听说过设备树.在我的情况下,我想将RTC设备连接到BBB上的I2C总线.网络上散布着大量信息,本文旨在概述我发现的内容,并指导您完成此操作.

因此,我将给出一个在BBB上激活I2C总线的完整示例,以及使用内核中包含的设备驱动程序连接DS1308 RTC芯片.听起来不错?

然后阅读,如果有什么不清楚,请留下评论.如果您有点匆忙,您也可以在Github上抓住设备树重叠代码并飞走.

第一件事

我在我的BBB上使用ArchLinux ARM,主要是因为Arch Linux很棒,我可能太笨了,不能使用debianoid发行版.
这是系统的screenfetch

你可能会注意到内核版本已经超过了3.x的东西.在screenfetch中看不到的是内核支持使用Capemgr实用程序的设备树覆盖.

什么是设备树?

我会做的很快,你可以找到更深入的知识here,here,herehere.
设备树是描述您平台上底层硬件的结构.它在嵌入式设备中大量使用,因为SOC和东西没有像PCI这样的公共汽车,可以发现设备.它们必须被静态定义,并附加到“平台总线”上,以提供与内核一起提供的设备驱动程序的句柄.

在将设备树引入Linux之前,所有这些工作必须用特定的C头文件自定义实现完成,然后所有这些都必须被合并到主线内核中.因此,作为一个可想象的穷尽任务,它来到了着名的Linus Torvalds rant.这里你还有更多的device tree background.

是的,不错,但它是如何工作的?

要描述设备树,我们使用.dts(设备树源)文件,它们是人类可读的,并由设备树编译器(dtc)编译成设备树blob(.dtb)二进制格式.当系统引导引导程序(例如u-boot)时,将该blob交给内核.内核解析它并创建由设备树给出的所有设备.

如果您不信我,请使用设备树编译器将您的BBB正在使用的设备树峰值.

如果您还没有安装,请获取相应的软件包..

pacman -Sy dtc-overlay
dtc -f -I fs /proc/device-tree | less

由于该命令生成了大量的输出,所以推荐使用传呼机的管道.结果应该看起来像这样..

您的设备树的所有部分也可以在内核源中进行调查,但是由于还有一个包含机制,信息会在几个文件之间分割

<kernel-source>/arch/arm/boot/dts/..

一些相关文件是:

> am335x-bone-common.dtsi
> am335x-boneblack.dts
> am33xx.dtsi

Note: The .dtsi files are equivalent to .h files in C or C++
because they get included (therefore the ‘i’ at the end) by .dts
files

它们都描述与处理器相关的设备,Beaglebone平台上的常见设备或仅适用于Beaglebone Black的设备.

你提到了叠加层,那是什么?

好的问题,我看到你还在我身边.如前所述,内核启动时,设备树blob将被解析.所以当你的系统启动并运行时,整个魔法已经结束了.在像BBB这样的平台上,有一大堆扩展板(Capes),这将需要您每次去另一个斗篷使用时重新编译设备树.

因此,您可以使用覆盖机制,允许您在设备树中添加修改设备AT RUNTIME!惊人.

Note: to be able to compile device tree overlays make sure to install the appropriate package like above (dtc-overlay)

我该如何使用这一切?

我会给你一个例子.由于BBB没有实时时钟(rtc),这对于生成测量等的时间戳是有用的,我们将要解决这个问题.

我们将使用ds1307实时时钟芯片(事实上,我有一个ds1308 rtc,但驱动程序是兼容的),并通过BBB上的I2C1总线进行通信.默认情况下,BBB上的总线被禁用,从设备树源可以看到.

该片段中的重要信息是:

>定义了一个名为’i2c1’的节点
>它被定义为与omap4-i2c驱动程序兼容
>根据处理器reference manual(第181页),设备将分配一个内存映射地址(0x4802a000)和一个适当的地址范围(0x1000)
>设备状态被禁用

现在我们将创建一个覆盖图来配置i2c1总线的GPIO引脚,激活该总线,之后我们将添加rtc-i2c1总线,以便自动加载相应的驱动程序,并在/ dev中创建rtc-device .

BBB上的P8和P9接头上的GPIO引脚具有多种功能,它们被复合在一起,因此我们必须调整引脚设置以将其用于I2C通信.从this table可以看到,对于I2C1总线,我们必须在多路复用器模式2中使用引脚17和18.要获取有关BBB外观上的GPIO处理的更多信息,请参阅here.

/dts-v1/;
/plugin/;

/{ /* this is our device tree overlay root node */

  compatible = "ti,beaglebone","ti,beaglebone-black";
  part-number = "BBB-I2C1"; // you can choose any name here but it should be memorable
  version = "00A0";

  fragment@0 {
    target = <&am33xx_pinmux>; // this is a link to an already defined node in the device tree,so that node is overlayed with our modification

    __overlay__ {
      i2c1_pins: pinmux_i2c1_pins {
        pinctrl-single,pins = <
          0x158 0x72 /* spi0_d1.i2c1_sda */ 
          0x15C 0x72 /* spi0_cs0.i2c1_sdl */
        >;
      };
    };
  };
}; /* root node end */

OMG刚刚发生什么?

乍一看,重叠语法看起来很奇怪,但它基本上由所谓的片段组成,目标是已经存在的设备节点并修改该节点(而且是子节点).

在这种情况下,我们定位处理器设备树(am33xx.dtsi)中定义的am33xx_pinmux设备节点.在该节点中,我们添加一个新的子节点,名为pinmux_i2c1_pins,之前不存在(看看am335x-bone-common.dtsi以验证)和标签i2c1_pins.

下一部分更复杂一些,如果您有兴趣,请阅读this.每个GPIO引脚都由一个具有几个位的单个寄存器配置,以控制其行为,所有寄存器由pinctrl单个驱动程序控制.要设置一个特定的引脚只是使用它的地址偏移从基地址(你会发现在上面的P9标题表),它的引脚配置作为第二个参数..

我从Derek Molloy借了这个概述来解释引脚模式.由于0x72相当于01110010b,因此我们将两个引脚配置为使能上拉电阻的输入和复用模式2中的主动转换控制.

并且这些引脚的复用模式2意味着标题P9上的引脚17是时钟线SCL,标题P9上的引脚18是数据线SDA.

但是我们还是要启用I2C1?

这是绝对正确的,所以让我们扩展我们的覆盖如下.

/dts-v1/;
/plugin/;

/{ /* this is our device tree overlay root node */

  compatible = "ti,pins = <
          0x158 0x72 /* spi0_d1.i2c1_sda */ 
          0x15C 0x72 /* spi0_cs0.i2c1_sdl */
        >;
      };
    };
  };

  fragment@1 {
    target = <&i2c1>;

    __overlay__ {
      pinctrl-0 = <&i2c1_pins>;

      clock-frequency = <100000>;
      status = "okay";

      rtc: rtc@68 { /* the real time clock defined as child of the i2c1 bus */
        compatible = "dallas,ds1307";
        #address-cells = <1>;
        #size-cells = <0>;
        reg = <0x68>;
      };
    };
  };
}; /* root node end */

在上面的代码中,我们添加了一个针对i2c1设备节点的新片段,并告诉它使用我们以前定义的引脚配置.我们设置一个100kHz的I2C时钟频率并激活该设备.

此外,rtc时钟作为一个小孩添加到i2c1节点.内核的重要信息是兼容语句,命名驱动程序(ds1307)和I2C总线上的器件地址(0x68). rtc的I2C地址可以从数据表中获取.

那我该如何把这个代码放到内核中?

起初设备树源必须被编译.使用带有以下调用的dtc编译器

dtc -O dtb -o <filename>-00A0.dtbo -b 0 -@ <filename>.dts

Caution! The filename must be a concatenation of the name you desire plus the version tag as seen above (-00A0) otherwise you’ll have a hard time.

所得到的.dtbo文件应该被复制到/ lib / firmware中,我真的不知道那个“-00A0”命名约定来自哪里,但固件目录里还有其他文件.

从现在开始,您可以使用Capemgr动态加载叠加层.这样做进入/ sys / devices / platform / bone_capemgr /然后执行..

echo <filename> > slots

然后,Capemgr将在固件目录中查找您的.dtbo文件,如果可能的话加载它.通过查看插槽文件,您可以看到过程是否成功.应该看起来像这样..

检查Beaglebone使用的设备树.

dtc -f -I fs /proc/device-tree | less

你会发现覆盖层的所有条目

此外,您的文件系统中应该有一个新的I2C设备(/ dev / i2c-1)和一个新的rtc设备(/ dev / rtc1).

要看看你的i2c总线安装包i2c工具并使用..

i2cdetect -r 1

输出应该是这样的东西..

您可以看到地址0x68被设备占用.

查询您的rtc使用..

hwclock -r -f /dev/rtc1

但这不是全部,还是呢?

不,还有一个选项,在引导时加载设备树重叠.真棒!

要这样做打开/boot/uEnv.txt并添加bone_capemgr.enable_partno =< filename>到optargs声明.这就是我BBB上的样子

optargs=coherent_pool=1M bone_capemgr.enable_partno=bbb-i2c1

令人困惑的是,文件名在optargs中使用,而不是在设备树覆盖中定义的部件号标签.

如果你喜欢,你可以在github代码放在一个有用的Makefile上.

对不起,长发

解决方法

这是非常有用和有价值的信息.我写了一个i2c内核驱动程序,我可以动态加载,与地址0x77的定制芯片通话.我以前通过手动实例化设备成功地与芯片通信,如下所示:echo act2_chip 0x77> / SYS /总线/ I2C /装置/ I2C-1 / new_device.
在设备实例化之后,我可以看到它使用i2cdetect工具,我的可加载内核驱动程序可以与芯片进行通信.

现在我试图使用设备树方法实例化设备.所以跟随你,我改变了你的dtsi文件中的一些参数,如下所示:

片段@ 1 {
target =<< i2c1>;

__overlay__ {
  pinctrl-0 = <&i2c1_pins>;

  clock-frequency = <100000>;
  status = "okay";

  act2_chip: act2_chip@77 { /* the real time clock defined as child of the i2c1 bus */
    compatible = "xx,act2_chip";
    #address-cells = <1>;
    #size-cells = <0>;
    reg = <0x77>;
  };

我将芯片连接到引脚17和18,用于scl和sdk.这是echo中得到的dmesg输出>插槽:

但是当将驱动程序插入内核时,我看到被调用的探测功能.这意味着司机能够尽可能地看到设备.

当我尝试写入内核驱动程序时,我会收到以下消息:omap_i2c 4802a000.i2c:控制器超时

猜你在找的C&C++相关文章