linux下RX8010SJ实时时钟芯片(RTC)的读写


注意:Linux4.x版本以上的内核才内置EPSON RX8010SJ驱动

Chapter1 linux下RX8010SJ实时时钟芯片(RTC)的读写

原文链接:https://blog.youkuaiyun.com/shenyan0712/article/details/108389923

1. 硬件

由于项目的需要在ARM嵌入式板子上挂上了一颗EPSON的RX8010实时时钟芯片,为数据采集提供可靠的时间。RX8010内置了具有温补的晶振,可以简化设计,而且也不贵,所以就选择了它。其实选择其它使用I2C的芯片在软件上来说问题都不大,只要Linux内置了该芯片的驱动。目前Linux已经支持了绝大多数的RTC芯片了。

电路图如下图所示。其中通过一个BAT54C来完成电池和DC电源供电之间的切换。在设计的第一板中出现了严重的低级错误,那就是没有给I2C总线加上上拉电阻。这个源自于对ARM芯片GPIO的误解,以为内置了上拉电阻。所以导致在调试时作为普通GPIO使用时能够测到有波形输出,而作为I2C使用时没有信号。一度怀疑是不是Linux下的I2C驱动有问题。最后终于想到了上拉电阻的问题,手动焊上两个电阻后果然就好使了。
在这里插入图片描述

2. 软件

芯片检测

在linux下,可以查看到I2C接口设备信息:

root@MyBoard:/dev# ls
...
gpiochip0        mmcblk0p2         sequencer           tty3    tty59  vhci
gpiochip1        mmcblk0p3         sequencer2          tty30   tty6   watchdog
i2c-0            mqueue            shm                 tty31   tty60  watchdog0
i2c-1            nbd0              snd                 tty32   tty61  zero
i2c-2            nbd1              spidev0.0           tty33   tty62
i2c-3            nbd10             stderr              tty34   tty63
initctl          nbd11             stdin               tty35   tty7

当挂载了RX8010后,如果确定其在I2C总线上的地址,可以使用I2C工具来侦测:

root@MyBoard:/dev# i2cdetect 0
WARNING! This program can confuse your I2C bus, cause data loss and worse!
I will probe file /dev/i2c-0.
I will probe address range 0x03-0x77.
Continue? [Y/n] y
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- UU -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --

可以看到挂载在i2c-0上的RX8010的地址为0x32。然后就可以加载RX8010驱动了。

如果侦测不到芯片,一般是硬件有问题,要么是线路有问题,要么是芯片有问题。

驱动挂载

在Linux 4.x.y版本中已经内置了RX8010的驱动,只不过默认是以模块的形式编译的。也就是说,在linux启动时并不会自动加载。如果需要自动,则需要自行编译linux使其随内核一起加载。这样做也比较麻烦,所以干脆就让其在linux启动后手动加载,最后做成一个脚本也一样。

启动系统后,找到模块所在的位置在/lib/modules/4.14.111/kernel/drivers/rtc目录下,名为rtc-rx8010.ko。使用如下命令加载并查看:

root@MyBoard:/lib/modules/4.14.111/kernel/drivers/rtc# insmod rtc-rx8010.ko
root@MyBoard:/lib/modules/4.14.111/kernel/drivers/rtc# lsmod

Module                  Size  Used by
rtc_rx8010             16384  0
nls_ascii              16384  1
8189es               1024000  0
brcmfmac              180224  0
brcmutil               16384  1 brcmfmac
xradio_wlan           110592  0
88XXau               1753088  0
8821cu               1683456  0
g_mass_storage         16384  0

可以看到RX8010的驱动模块已经加载到内核了。暂时不要高兴,现在还并不能使用RX8010,因为并没有在/dev目录下生成对应的设备文件。

还记得的之间侦测RX8010时得到的地址(0x32)吧,我们需要它来创建设备文件。执行如下命令

 echo "rx8010 0x32" > /sys/class/i2c-adapter/i2c-0/new_device

其中rx8010为RX8010驱动注册的名称,不能为其它字符,而0x32则为该芯片在I2C总线上的通信地址。上面的命令将合成的字符串写入new_device,然后内核就会查找到加载的RX8010驱动,将地址传入,再由驱动程序与实际芯片进行通信,如果通信正常则完成设备的注册,生成设备文件/dev/rtc1。

3. 测试

最后测试该芯片是否能够正常工作。首先来读取芯片的时间:

root@MyBoard:~# hwclock -r -f /dev/rtc1
Thu 07 Nov 2013 07:30:04 PM UTC  .008031 seconds

如果能够读到时间,就99%预示着芯片正常工作了。

然后试试时间的写入,首先从网络获取最新时间:

root@MyBoard:~# /etc/init.d/ntp restart
root@MyBoard:~# ntp-wait
root@MyBoard:~# date
Thu Sep  3 09:47:39 UTC 2020

然后写入RX8010后,等一下下再读取:

root@MyBoard:~# hwclock -w -f /dev/rtc1
root@MyBoard:~# hwclock -r -f /dev/rtc1
Thu 03 Sep 2020 09:49:04 AM UTC  .179065 seconds

可见成功的写入了时间,而且时间也正常运行起来了。

Chapter2 Linux内核编程(二十)RTC子系统一驱动rx8010

原文链接:https://blog.youkuaiyun.com/qq_48361010/article/details/143630260
在这里插入图片描述

一、电路原理图

在这里插入图片描述
分析:
(1)RTC供电路径
当3.3V主电源存在时,RTC芯片通过路径1和路径2同时获得供电,主要是3.3V供电。
当3.3V断电后,RTC芯片通过路径2由电池(CR1220)供电。路径2是备用电池供电路径。

(2)二极管的选择
补充:什么是电流泄露?
   电流泄漏是指电流在不应该流过的路径上产生的微小电流。在二极管中,当二极管在反向偏置的情况下(即反向电压加在二极管上)也会有极小的电流通过,这种电流称为反向泄漏电流。虽然这个电流一般很小,但在低功耗设计中,泄漏电流会逐渐消耗电池电量,影响系统的待机寿命。
   为了减少电流损耗和提高电源切换效率,路径1的二极管应具有较低的正向压降(VF)和低泄漏电流(通常使用肖特基二极管,因为它们的正向压降低且泄漏电流小)。这样可以确保在3.3V断电时,电池供电能顺利切换到RTC芯片,并且尽量减少3.3V电源供电时的电流泄漏,从而延长电池寿命。

(3)Vcc_RTC=BAT1-D3
   RTC芯片的Vcc端电压为BAT1(电池电压)减去二极管D3的正向导通电压。因此,选用导通电压较小的二极管能够使RTC芯片在电池供电状态下获得较高的电压,使其正常工作。RTC芯片要求电源电压为 1.6v到5.5v。

二、RTC芯片(RX8010)移植

  1. 配置设备树(device部分)
    这里rx8010芯片使用iic与主控通信,具体挂载到那个iic控制器上可以自行定义(如果原理图已经设计好,就按原理图上来)。
&i2c5 {
    status = "okay";
    rx8010: rx8010@32 {
        compatible = "epson,rx8010";
        reg = <0x32>;
        status = "okay";
        #clock-cells = <0>;
    };
};

图形化配置driver部分
在源码目录下使用export ARCH=arm64,再使用make menuconfig打开图形配置界面。具体分为下面两种情况。
(1)源码中有rx8010的驱动程序。
Device Drivers —>
   [★]Real Time Clock —>
      [★] Epson RX8010SJ
      [ ] Rockchip RK805/RK808/RK809/RK816/RK817/RK818 RTC
(2)源码中没有rx8010的驱动程序。
   需要问厂家要一下源码,然后自己写一个kconfig和Makefile文件,来配置图形界面就行。配置教程。

Linux内核编程(八) 添加自定义目录驱动菜单 (Kconfig文件使用),点击链接

三、关于时间的一些命令

在 Linux 系统中,存在两个时间:系统时间 和 RTC 时间(硬件时钟时间)。这个双时间架构允许系统在断电情况下仍能保持准确的时间,并且在某些特殊用途场景(如嵌入式系统或实时应用)中,可以独立管理 RTC 时间和系统时间。

data命令(查看系统时间)

系统时间是由内核维护的时间,它通常从 RTC 获取初始值,并在系统运行期间由操作系统维护和更新。系统时间会随着操作系统的运行而不断更新,即使系统时间偏离了 RTC 时间。

date        //查看系统时间
date -s "YYYY-MM-DD HH:MM:SS"  // 设置系统时间
date -u       //将系统时间以UTC标准显示

hwclock命令(查看硬件时间)

RTC 是系统主板上一个独立的实时时钟模块,通常带有电池,因此即使系统断电或重启也能保持时间。它是系统启动时的时间源,系统启动时会从 RTC 读取时间,并将其复制到系统时间。

hwclock          //查看 RTC 时间
hwclock -w       //将系统时间写入 RTC 时间
hwclock -s       //将 RTC 时间同步到系统时间

我们通过上面的学习了解到系统在启动时获取RTC时间,并将其设置为系统时间,那为什么我们使用命令查看时,两个时间不一致呢?
   答:这是因为时间标准不一样,UTC(协调世界时)是全球公认的时间标准,CST(中国标准时间),即北京时间,是东八区时间,相当于 UTC+8。使用上面的命令一个获取的是北京时间,一个是UTC时间。

四、应用层使用

1. 使用RTC驱动

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/rtc.h>
#include <time.h>
#include <errno.h>

int main(int argc, char *argv[]) {
    int fd;
    int ret;
    struct rtc_time tm;

    fd = open("/dev/rtc0", O_RDONLY);  //硬件上只有一个,常用的就是rtc0节点
    if (fd < 0) {
        perror("open error");
        return -1;
    }

    ret = ioctl(fd, RTC_RD_TIME, &tm);
    if (ret < 0) {
        perror("RTC_RD_TIME error");
        close(fd);
        return -1;
    }

    printf("RTC time is %d-%02d-%02d, %02d:%02d:%02d\n",
           tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
           tm.tm_hour, tm.tm_min, tm.tm_sec);

    close(fd);
    return 0;
}

2. 使用time.h库(额外知识点)

#include <fcntl.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <time.h>

/*
struct tm {
			 int tm_sec;	//Seconds (0-60) 
			 int tm_min;	//Minutes (0-59) 
			 int tm_hour;	// Hours (0-23) 
			 int tm_mday;	// Day of the month (1-31) 
			 int tm_mon;	// Month (0-11) 
			 int tm_year;	// Year - 1900 
			 int tm_wday;	// Day of the week (0-6, Sunday = 0) 
			 int tm_yday;	// Day in the year (0-365, 1 Jan = 0) 
			 int tm_isdst;	// Daylight saving time 
		 };
*/
int main(int argc,char **argv)
{
	time_t tim;
    struct tm *p;
	while(1)
	{
	    tim=time(NULL);//获取时间戳 获取1900-1-1到现在的总秒数
		p=localtime(&tim); //将秒数转换
		
		printf("%4d-%d-%d %d:%d:%d\r\n",
		p->tm_year+1900,
		p->tm_mon+1,
		p->tm_mday,
		p->tm_hour,
		p->tm_min,
		p->tm_sec);
	   sleep(1);  //延迟1s
   }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值