这次动手想给自己的BBB做一个RTCcape,让自己的板子可以每次开机记住时间。简单来说划分成三个任务:
1,搭建一个RTC硬件电路,这个有较多资料可以参考,比如官方的cape中就有http://elinux.org/CircuitCo:RTC_Cape。
2,需要一个设备树文件,既然是插上就能使用的cape,那么必须由设备树文件来绑定内核中和RTC硬件电路相对应的驱动程序,通过底层驱动外露出来的接口,我们的应用程序才能驱动硬件。
3,仅仅设备树文件还不能完成任务,还需写一个简单的脚本(这个就相当于我们的应用程序吧),让每次开机脚本自动把DS1338中的时间更新到系统时间。
第一步就是参考别人的硬件电路,然而抄完电路发现别人DS1338芯片的I2C接口是接在BBB的I2C1总线上,而我的电路却焊接到了I2C2总线上,于是有了这个修改设备树文件的变故。
注意此处的cape和通常所说的cape有一点点不一样,就是他没有用eeprom。通常对于cape的描述是一插上后板子上电就能用,这是因为位于0x54-0x57地址的eeprom告诉了系统启动时该对哪几个overlay进行重载,从而开机后系统就识别出了硬件。而这里没有eeprom的情况下,我通过修改uEnv.txt,让系统开机后就加载对应的dtbo文件,同样达到了这个目的。
从上面的链接把他配套的设备树文件下载过来,打开源码如下:
/* * Copyright (C) 2013 Hieu Duong <[email protected]> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * */ /dts-v1/; /plugin/; / { compatible = "ti,beaglebone", "ti,beaglebone-black"; /* identification */ part-number = "BBB-RTC-01"; version = "00A1"; /* state the resources this cape uses */ exclusive-use = /* the pin header uses */ "P8.26", /* rtc: gpio1_29 */ "P9.18", /* i2c1_sda */ "P9.17", /* i2c1_scl */ /* the hardware ip uses */ "gpio1_29", "i2c1"; fragment@0 { target = <&am33xx_pinmux>; __overlay__ { rtc_mfp: pinmux_rtc_mfp { pinctrl-single,pins = < 0x07c 0x3f /* gpmc_csn0.gpio1_29, INPUT | PULLDIS | MODE 7 */ >; }; bb_i2c1_pins: pinmux_bb_i2c1_pins { pinctrl-single,pins = < 0x158 0x72 /* spi0_d1.i2c1_sda, SLEWCTRL_SLOW | INPUT_PULLUP | MODE2 */ 0x15c 0x72 /* spi0_cs0.i2c1_scl, SLEWCTRL_SLOW | INPUT_PULLUP | MODE2 */ >; }; }; }; fragment@1 { target = <&ocp>; __overlay__ { rtc_helper { status = "okay"; compatible = "bone-pinmux-helper"; pinctrl-names = "default"; pinctrl-0 = <&rtc_mfp>; }; }; }; fragment@2 { target = <&i2c1>; __overlay__ { status = "okay"; pinctrl-names = "default"; pinctrl-0 = <&bb_i2c1_pins>; /* this is the configuration part */ clock-frequency = <100000>; /* shut up DTC warnings */ #address-cells = <1>; #size-cells = <0>; /* MCP79410 RTC module */ rtc@68 { compatible = "maxim,ds1338"; reg = <0x68>; }; }; }; };
接下来根据自己的情况对文件进行修改,如下:
/* * Copyright (C) 2013 Hieu Duong <[email protected]> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * */ /dts-v1/; /plugin/; / { compatible = "ti,beaglebone", "ti,beaglebone-black"; /* identification */ part-number = "BBB-RTC-ZY"; version = "00A0"; /* state the resources this cape uses */ exclusive-use = /* the pin header uses */ "P8.26", /* rtc: gpio1_29 */ "P9.20", /* i2c2_sda */ "P9.19", /* i2c2_scl */ /* the hardware ip uses */ "gpio1_29", "i2c2"; fragment@0 { target = <&am33xx_pinmux>; __overlay__ { rtc_mfp: pinmux_rtc_mfp { pinctrl-single,pins = < 0x07c 0x3f /* gpmc_csn0.gpio1_29, INPUT | PULLDIS | MODE 7 */ >; }; bb_i2c2_pins: pinmux_bb_i2c2_pins { pinctrl-single,pins = < 0x178 0x73 /* spi0_d1.i2c1_sda, SLEWCTRL_SLOW | INPUT_PULLUP | MODE3 */ 0x17c 0x73 /* spi0_cs0.i2c1_scl, SLEWCTRL_SLOW | INPUT_PULLUP | MODE3 */ >; }; }; }; fragment@1 { target = <&ocp>; __overlay__ { rtc_helper { status = "okay"; compatible = "bone-pinmux-helper"; pinctrl-names = "default"; pinctrl-0 = <&rtc_mfp>; }; }; }; fragment@2 { target = <&i2c2>; __overlay__ { status = "okay"; pinctrl-names = "default"; pinctrl-0 = <&bb_i2c2_pins>; /* this is the configuration part */ clock-frequency = <100000>; /* shut up DTC warnings */ #address-cells = <1>; #size-cells = <0>; /* MCP79410 RTC module */ rtc@68 { compatible = "maxim,ds1338"; reg = <0x68>; }; }; }; };
注释如下:
01-15:一个设备树重载文件的注释头便于读者理解
17:表明dts文件版本
19:本dts文件在描述一个插件
23:一棵设备树的根节点
25:描述本设备树重载文件应用的平台,第一个字符串描述的平台是最匹配的,第二个其次....
29-33:part-number用于在不同的插件对应的设备树重载文件之间区别,version用于在同一个插件的不同版本之间进行区别,这样能保证不会弄错文件文件名字根据这两个信息进行命名,进一步保证不出错。此处我将名字修改了一下,那么待会儿文件名也最好相应改一下。
37-51:此处exclusive-use属性(顾名思义专用属性)描述插件所需要的资源,主要是引脚资源,这些资源不应该被分配给其他作用。修改之前此处是i2c1的引脚,现在根据自己的电路查看下表修改为i2c2引脚,另外一个gpio1_29是因为ds1338有一个可以输出方波频率为1K、4K、8K、32K的SQW引脚,该引脚接在GPIO61上,61 = 32 * 1 + 29
,此引脚不需要修改。
55-69:第0段代码fragment交代了其目标:pinmux引脚映射,__overlay__则是一个节点,节点的第一个子节点pinmux_rtc_mfp前面有一个代号rtc_mfp,这个代号是为了方便后面的代码段进行引用。节点pinmux_rtc_mfp的属性pinctrl-single,pins其值为0x07c 0x3f,第一个值表示我们想要的引脚gpio1_29,查下图可知在系统中其名字为0x07c,而0x3f = 0011 1111,其各个位所代表的意义如下下图(摘自4000+页的技术手册)所示。该引脚配置为MODE7即GPIO口模式,输入上拉下拉禁能(外部已经有焊接了上拉电阻),接收使能,快速。该属性和值的相关配置是由系统中的引脚复用配置驱动程序pinctrl-single来处理的。
73-85:作为__overlay__的第二个子节点,其代号被修改为bb_i2c2_pins,节点名称也被修改为pinmux_bb_i2c2_pins,其属性pinctrl-single,pins的值毫无疑问也是对i2c2_scl和i2c2_sda进行配置,查询方法如第1、3张图所示。
91-113:这一段代码段引用了第0段代码段的一个子节点,与gpio1_29的配置相关。
117-161:这一段代码代码段可能是提供了一些配置驱动程序的信息,用于配置i2c通信的一些相关参数。
设备树文件的编写最好拿最相近的设备树文件来改写。
修改完设备树文件命名为XX-00A0.dts,将其传到BBB板子上,通过系统中的dtc -I dts -O dtb -o xx-0A00.dtbo -@ filepath/XX-00A0.dts命令来编译得到XX-00A0.dtbo文件,将此文件复制到/lib/firmware目录。同时在uEnv.txt文件中添加如下语句,
蓝色框内表示开机自动禁止重载的内容,红线表示开机自动重载的内容。此处注意,事实上所有我们自己改写的设备树文件名不能随便乱取,否则系统无法接受,开机后重载失败,我采取的方法是通过同名覆盖掉原来的BB-BONE-RTC-00A0.dtbo,这样开机后就能自动重载了。貌似这是一个bug?本人采用的系统来自官方的最新的debian,内核版本3.8.13。
这样做了之后,每次开机系统会通过设备树重载文件找到驱动程序,这个驱动程序操作的硬件就是我们的DS1338了,而驱动程序外露出的接口就是/dev/rtc1,只要我们通过应用程序对这个设备文件操作就行。
在开机自动运行程序一文中可以看到如何让应用程序在每次开机后自动的把DS1338里面的时间更新到系统时间!
-