(米联客MSXBO)开发板 osrc-lab LINUX下RTC时钟模块使用

概述

RTC(real-time clock)简称实时时钟,是日常生活中应用最为广泛的消费类电子产品之一。它为人们提供精确的实时时间或者为电子系统提供精确的时间基准,而备份电池在掉电后数据不丢失,在下次启动依旧可以重新设置当前时间给计算机。另外,可以通过RTC的周期性中断来产生闹钟,也可以在系统suspend的时候作为系统的唤醒源使用。

常见的RTC芯片主要是I2C接口和SPI接口,其中,DS1337/DS1307PCF8563市面上最流行、性价比最高的I2C接口芯片。如果你需要在产品中使用RTC芯片,可以在Linux内核源码中,找找是否有对应的源码,这意味着你不再需要自己编写代码,而且主线里的驱动都是测试过的,使用起来更放心一些。而对于初学者,则可以通过内核中的驱动学到更地道的编程方法,何乐而不为呢。以下是可以在内核中找到源码部分芯片:

A.基于I2C接口RTC时钟芯片

* Dallas/Maxim DS1307/37/38/39/40, ST M41T00, EPSON RX-8025

* Dallas/Maxim DS1374

* Dallas/Maxim DS1672       

* Dallas/Maxim DS3232   

* Maxim MAX6900      

* Ricoh R2025S/D, RS5C372A/B, RV5C386, RV5C387A  

* Intersil ISL1208

* Intersil ISL12022           

* Xicor/Intersil X1205      

* Philips PCF8563/Epson RTC8564        

* Philips PCF8583   

* ST M41T62/65/M41T80/81/82/83/84/85/87  

* TI BQ32000  

* Seiko Instruments S-35390A  

* Ramtron FM3130

* Epson RX-8581       

* Epson RX-8025SA/NB    

* EM Microelectronic EM3027

* Micro Crystal RTC

       B. 基于SPI接口RTC时钟芯片

       * Dallas DS1286

* Dallas DS1511

* Maxim/Dallas DS1553  

* Maxim/Dallas DS1742/1743

* Simtek STK17TA8

* ST M48T86/Dallas DS12887

* ST M48T35  

* ST M48T59/M48T08/M48T02  

* Oki MSM6242

* TI BQ4802

* Ricoh RP5C01   

* EM Microelectronic V3020  

而本教程主要介绍基于I2C接口的DS1337/DS1307芯片在ZYNQ-7000上应用。 I2C总线是由Philips公司开发的一种简单、双向二线制同步串行总线。它只需要两根线即可在连接于总线上的器件之间传送信息,是嵌入式系统中广泛使用的一类通信协议,主要用于CPU和各种外设之间的低速数据通信。

I2C介绍

       我们知道I2C总线具备广泛的用途,比如寄存器的配置,EEPROM的使用,更重要的是I2C总线上可以挂载非常多的外设。 对于一些低速器件的访问非常节省IO资源,由于是标准的总线接口,使用起来非常方便。I2C总线是OC开路,支持双向传输,所以总线上需要上拉电阻,如下图。

dde390f8e979ff915050acdf1debd824860.jpg

I2C总线协议

       由于节课讲解的I2C是基于ZYNQ的I2C控制器,实际上可以不需要非常清楚I2C的详细时序,但是作为初学者,如果第一次学习I2C总线的,还是有必要学习下。

 

I2C协议把传输的消息分为两种类型的帧:

一个地址帧 :用于master指明消息发往哪个slave;

一个或多个数据帧: 由master发往slave的数据(或由slave发往master),每一帧是8-bit的数据。

注:协议要求每次放到SDA上的字节长度必须为8位,并且每个字节后须跟一个ACK位,在下面会讲到。

数据在SCL处于低电平时放到SDA上,并在SCL变为高电平后进行采样。读写数据和SCL上升沿之间的时间间隔是由总线上的设备自己定义的,不同芯片可能有差异。

I2C数据传输的时序图如下:

784ce8992d872649ea4135a8b590121e791.jpg

开始条件(start condition):

为了标识传输正式启动,master设备会将SCL置为高电平(当总线空闲时,SDA和SCL都处于高电平状态),然后将SDA拉低,这样,所有slave设备就会知道传输即将开始。如果两个master设备在同一时刻都希望获得总线的所有权,那么谁先将SDA拉低,谁就赢得了总线的控制权。在整个通信期间,可以存在多个start来开启每一次新的通信序列(communication sequence),而无需先放弃总线的控制权,后面会讲到这种机制。

 

地址帧(address frame):

地址帧总是在一次通信的最开始出现。一个7-bit的地址是从最高位(MSB)开始发送的,这个地址后面会紧跟1-bit的操作符,1表示读操作,0表示写操作。

接下来的一个bit是NACK/ACK,当这个帧中前面8bits发送完后,接收端的设备获得SDA控制权,此时接收设备应该在第9个时钟脉冲之前回复一个ACK(将SDA拉低)以表示接收正常,如果接收设备没有将SDA拉低,则说明接收设备可能没有收到数据(如寻址的设备不存在或设备忙)或无法解析收到的消息,如果是这样,则由master来决定如何处理(stop或repeated start condition)。

 

数据帧(data frames):

在地址帧发送之后,就可以开始传输数据了。Master继续产生时钟脉冲,而数据则由master(写操作)或slave(读操作)放到SDA上。每个数据帧8bits,数据帧的数量可以是任意的,直到产生停止条件。每一帧数据传输(即每8-bit)之后,接收方就需要回复一个ACK或NACK(写数据时由slave发送ACK,读数据时由master发送ACK。当master知道自己读完最后一个byte数据时,可发送NACK然后接stop condition)。

 

停止条件(stop condition):

当所有数据都发送完成时,master将产生一个停止条件。停止条件定义为:在SDA置于低电平时,将SCL拉高并保持高电平,然后将SDA拉高。

注意,在正常传输数据过程中,当SCL处于高电平时,SDA上的值不应该变化,防止意外产生一个停止条件。

 

重复开始条件(repeated start condition):

有时master需要在一次通信中进行多次消息交换(例如与不同的slave传输消息,或切换读写操作),并且期间不希望被其他master干扰,这时可以使用“重复开始条件” —— 在一次通信中,master可以产生多次start condition,来完成多次消息交换,最后再产生一个stop condition结束整个通信过程。由于期间没有stop condition,因此master一直占用总线,其他master无法切入。

为了产生一个重复的开始条件,SDA在SCL低电平时拉高,然后SCL拉高。接着master就可以产生一个开始条件继续新的消息传输(按照正常的7-bit/10-bit地址传输时序)。重复开始条件的传输时序如下图所示:

944329055013ce2e35c3d631b1a9654a755.jpg

时钟拉伸(clock stretching):

有时候,低速slave可能由于上一个请求还没处理完,尚无法继续接收master的后续请求,即master的数据传输速率超过了slave的处理能力。这种情况下,slave可以进行时钟拉伸来要求master暂停传输数据 —— 通常时钟都是由master提供的,slave只是在SDA上放数据或读数据。而时钟拉伸则是slave在master释放SCL后,将SCL主动拉低并保持,此时要求master停止在SCL上产生脉冲以及在SDA上发送数据,直到slave释放SCL(SCL为高电平)。之后,master便可以继续正常的数据传输了。可见时钟拉伸实际上是利用了时钟同步的机制(见下文),只是时钟由slave产生。

如果系统中存在这种低速slave并且slave实现了clock stretching,则master必须实现为能够处理这种情况,实际上大部分slave设备中不包含SCL驱动器的,因此无法拉伸时钟。

所以更完整的I2C数据传输时序图为:

4487a7126c1d93bf413c086f8fb7688e9a5.jpg

10-bit地址空间:

上面讲到I2C支持10-bit的设备地址,此时的时序如下图所示:

30525b399b5436304ac1e91e2a4d9ef59e4.jpg

在10-bit地址的I2C系统中,需要两个帧来传输slave的地址。第一个帧的前5个bit固定为b11110,后接slave地址的高2位,第8位仍然是R/W位,接着是一个ACK位,由于系统中可能有多个10-bit slave设备地址的高2bit相同,因此这个ACK可能由多有slave设备设置。第二个帧紧接着第一帧发送,包含slave地址的低8位(7:0),接着该地址的slave回复一个ACK(或NACK)。

注意,10-bit地址的设备和7-bit地址的设备在一个系统中是可以并存的,因为7-bit地址的高5位不可能是b11110。实际上对于7-bit的从设备地址,合法范围为b0001XXX-b1110XXX,’X’表示任意值,因此该类型地址最多有112个(其他为保留地址[1])。

两个地址帧传输完成后,就开始数据帧的传输了,这和7-bit地址中的数据帧传输过程相同。

 

时钟同步和仲裁:

如果两个master都想在同一条空闲总线上传输,此时必须能够使用某种机制来选择将总线控制权交给哪个master,这是通过时钟同步和仲裁来完成的,而被迫让出控制权的master则需要等待总线空闲后再继续传输。在单一master的系统上无需实现时钟同步和仲裁。

 

时钟同步:

时钟同步是通过I2C接口和SCL之间的线“与”(wired-AND)来完成的,即如果有多个master同时产生时钟,那么只有所有master都发送高电平时,SCL上才表现为高电平,否则SCL都表现为低电平。

 

总线仲裁:

总线仲裁和时钟同步类似,当所有master在SDA上都写1时,SDA的数据才是1,只要有一个master写0,那此时SDA上的数据就是0。一个master每发送一个bit数据,在SCL处于高电平时,就检查看SDA的电平是否和发送的数据一致,如果不一致,这个master便知道自己输掉仲裁,然后停止向SDA写数据。也就是说,如果master一直检查到总线上数据和自己发送的数据一致,则继续传输,这样在仲裁过程中就保证了赢得仲裁的master不会丢失数据。

输掉仲裁的master在检测到自己输了之后也不再产生时钟脉冲,并且要在总线空闲时才能重新传输。

仲裁的过程可能要经过多个bit的发送和检查,实际上两个master如果发送的时序和数据完全一样,则两个master都能正常完成整个的数据传输。

RTC时钟DS1307介绍

DS1307是低功耗、两线制串行读写接口、日历和时钟数据按BCD码存取的时钟/日历芯片。它提供秒、分、小时、星期、日期、月和年等时钟日历数据。另外它还集成了如下几点功能:

(1)56 字节掉电时电池保持的NV SRAM 数据存储器

(2)可编程的方波信号输出

(3)掉电检测和自动切换电池供电模式

8da5c58ae55b820ab5074cac734527cd9b2.jpg

       S1307的寄存器地址空间如下,我们的代码也就是读写一下地址空间。

1b3d0bf81a2bfed26a26775d59e57a38c14.jpg

地址空间中详细的参数定义如下表

6f455c48f077648589c00b88cd0315a42a4.jpg

写时序如下:

246dc94543c02e5af84906fb9a8c3dc9fc4.jpg

写时序很容易理解,和我们前面写EEPROM一样,先发送器件地址为1101000,再发送寄存器的地址,之后是连续写数据。

读时序如下:

4ba3da521e8a6dc0c7f2e40021ea553f81c.jpg

       这里读的时序有点没描述清楚,读时序前首先还要进行一次写寄存器起始地址的设置。比如代码,首先是写器件地址,并且指定标记读寄存器的其实寄存器地址为0x00,然后从标记的0x00读7个字节的数据。后面时序分析的时候再配合以上读写时序图介绍。

FPGA BD工程设计

通过EMIO的方式将PS端的IIC接口引出来

1、如下图,在ZYNQ7 Processing System IP的配置界面里,将IIC 0配置为EMIO。

2c6e5be609918813597aae711b23f316fab.jpg

2、如下图,按住Ctrl+T的组合键,将IIC_0引出来并重命名为IIC_0。

bf7a8f98f323c1ef00209c4d9078e56a7cb.jpg

在约束文件里添加以下内容。

set_property PACKAGE_PIN L15 [get_ports IIC_0_sda_io]

set_property IOSTANDARD LVCMOS33 [get_ports IIC_0_sda_io]

set_property PACKAGE_PIN L14 [get_ports IIC_0_scl_io]

set_property IOSTANDARD LVCMOS33 [get_ports IIC_0_scl_io]

配置kernel添加I2C及RTC的支持

、配置kernel,确保Device Drivers -> I2C support -> I2C Hardware Bus support->Cadence I2C Controller被选中。

 8194c4d3d8e02b522ec443645068f1f601a.jpg

2、 确保Device Drivers -> Real Time Clock界面下,确保以下选项被选中DS1337/DS1307使用的是同一份源代码。drivers/rtc/ rtc-ds1307.c,有兴趣的可以去阅读学习。

b4f7759d682fc77719779ceb69611e27484.jpg

05a76f01972bf6475cc3c1750f827485830.jpg

3、配置完使用save_ kernel _config.sh保存配置。

修改设备树

&i2c0 {

         clock-frequency = <400000>;

         status = "okay";

         /* DS1337 RTC module */

         Rtc0@68 {

                   compatible = "dallas,ds1337";

                   reg = <0x68>;

         };

};

编译并且部署系统到TF卡进行测试

安装RTC模块

bfbb1fc8b61f47740f0dc280f520f1a82cd.jpg

17b20a0518755e1c63a6874c93eb931d515.jpg

测试

上电启动MZ7XA-7020,从启动信息可以看到,rtc0已经可以挂载到总线上了接下的实验会教大家。

6294d014359f7444f428a6db775e64c0445.jpg

e98d4401630fd5f0d9d752b5ca8743bf270.jpg

硬件时钟(Real Time Clock)和系统时钟(System Clock)是Linux系统中的两个重要的时钟。硬件时钟也被称为RTCCMOSBIOS时钟,指主机板上的时钟设备,通常系统断电后,由主板上的电池提供电源。系统时钟也叫内核时钟或者软件时钟,是由内核根据时间中断来进行计数的,内核时钟在系统关机的情况下是不存在的,所以,当操作系统启动的时候,内核时钟是要读取读取硬件时钟来进行时间同步,然后系统时钟就会独立于硬件钟运行。

使用date命令显示系统时间:            

f4890c9246170e6e471774f27327a242216.jpg

date命令修改系统时间:

22e615b4355af5b5ed8d4545b2a2856f09e.jpg

 

使用“hwclock”或“hwclock –r”命令显示硬件时钟与日期:(注意:由于此时还未设置硬件时候,故提示“low voltage detected, date/time is not reliable. “)

我正常测试的RTC模块已经设置过了

4bdc516bc3d421756e4bc58b82c443d2c5e.jpg

 

使用“hwclock –w”命令将硬件时钟调整为与目前的系统时钟一致:

其中data -s "2019-07-30 22:00" 为把系统时间设置为当前时间,这样才方便测试有对比(如果RTC模块没有修改过时钟,可以发现硬件时钟与系统时钟不一致,low voltage detected, date/time is not reliable.)

a0fdb12d9ae34738f4564627bbf210f220e.jpg

hwclock -s将系统时钟调整为与目前的硬件时钟一致

先执行 date -s "2011-02-24 22:22"把系统时钟修为2011年方便测试

a0fdb12d9ae34738f4564627bbf210f220e.jpg

现在reboot一下

细心的同学应该可以看到,在接下来的启动信息有以下信息,这就是前面说的,内核启动时会将硬件时钟同步到系统时钟。

c148c06fbf0b071d4aa519770c83034a4c6.jpg

进入系统后,我们再来看看是硬件时钟和系统时钟是不是一致。

2372d240029f578208c6fc510ddaf5648d9.jpg

参考资料:

  1. Simple I2C Library for linux
  2. Wikipedia I²C Page
  3. Linux Kernel I2C Documentation
  4. Using the I²C Bus with Linux
  5. Linux i2c Subsystem
  6. Interfacing with I2C Devices
  7. Using I2C bus from user space
  8. Raspberry Pi PCF8563 Real Time Clock (RTC)
  9. RTC DS3231 on the Raspberry Pi
  10. Raspberry Pi tips and tricks
  11. https://github.com/alvareap/classwork/tree/master/rtc
  12. https://learn.adafruit.com/adding-a-real-time-clock-to-beaglebone-black/set-rtc-time
  13. https://elinux.org/Adafruit:_RTC_DS1307
  14. https://elinux.org/Beagleboard:BMP_on_the_Beagle_Bone_Black
  15. http://drewkeller.com/blog/adding-hardware-clock-raspberry-pi-ds3231
  16. www.wiki.xilinx.com/Cadence+I2C+Driver
  17. RTC DS1307
  18. How to use the Real Time Clock in Linux

转载于:https://my.oschina.net/msxbo/blog/3081360

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值