嵌入式系统I2C学习之RTC(通过I2C总线读写RTC)笔记

我们都知道,嵌入式系统中的RTC测试可以使用date,hwclock来查看写入时间,断电一段时间在查看始终的走时功能是否正常.这些都是通过固定的命令来实现的,我在学习嵌入式系统的时候,接触到了I2C总线,把学习的笔记总结了以下.

I2C和其他的接口是不一样的,比如232,485等等,这些在嵌入式系统中都有预留接口,可以在上位机比如在windows平台开发测试程序来完成,平时就对它有一个较深的理解,但是I2C是不一样,它一般连接的设备有RTC,声音,EEprom等,这些一般都是内部接口,所以我们平时用不到,也就不熟悉,说实话,我第一次接触的时候也挺抽象的(对于那些专门搞硬件的当然很清楚嘿嘿),这里有不同意见的可以提,但是不接收吵架式回复.

背景

I²C(Inter-Integrated Circuit),中文应该叫集成电路总线,它是一种串行通信总线,使用多主从架构,是由飞利浦公司在1980年代初设计的,方便了主板、嵌入式系统或手机与周边设备组件之间的通讯。由于其简单性,它被广泛用于微控制器与传感器阵列,显示器,IoT设备,EEPROM等之间的通信。

I²C最重要的功能包括:

  1. 只需要两条总线;
  2. 没有严格的波特率要求,例如使用RS232,主设备生成总线时钟;
  3. 所有组件之间都存在简单的主/从关系,连接到总线的每个设备均可通过唯一地址进行软件寻址;
  4. I²C是真正的多主设备总线,可提供仲裁和冲突检测;
  5. 传输速度;
  6. 标准模式:Standard Mode = 100 Kbps
  7. 快速模式:Fast Mode = 400 Kbps
  8. 高速模式: High speed mode = 3.4 Mbps
  9. 超快速模式: Ultra fast mode = 5 Mbps
  10. 最大主设备数:无限制;
  11. 最大从机数:理论上是127;

框图

嵌入式系统I2C学习之RTC(通过I2C总线读写RTC)笔记_第1张图片

 IIC总线是多主总线

 多个主机可以同时尝试控制总线,而不会破坏消息

 所有事务都已start开始,并由stop结束

当scl为h时,sda线上的h到l转换定义了一个start

当scl为h是,sda线上的l到h转换定义了一个stop

嵌入式系统I2C学习之RTC(通过I2C总线读写RTC)笔记_第2张图片

 要想了解更多的i2c的知识,可网络查询,也可以参考我以前写的一篇科普文章https://blog.csdn.net/mainmaster/article/details/125721501?spm=1001.2014.3001.5501

6ULL-c的I2C分布

我们这例使用的是飞凌公司的6ULL-C的开发板,首先查看原理图:

嵌入式系统I2C学习之RTC(通过I2C总线读写RTC)笔记_第3张图片

 可以看到,具有2路i2c总线

嵌入式系统I2C学习之RTC(通过I2C总线读写RTC)笔记_第4张图片

rtc原理

嵌入式系统I2C学习之RTC(通过I2C总线读写RTC)笔记_第5张图片

P16的排线上也有i2c-1,经查为LCD

嵌入式系统I2C学习之RTC(通过I2C总线读写RTC)笔记_第6张图片

同时也连接到了P20沛县上,我们可以看到这个是可以接入外接设备的,如接入一个E2rom原件

可以看到,i2c-1总线可挂载LCD,RTC,外部设备

嵌入式系统I2C学习之RTC(通过I2C总线读写RTC)笔记_第7张图片

i2c-2的出口

嵌入式系统I2C学习之RTC(通过I2C总线读写RTC)笔记_第8张图片

音频接口

嵌入式系统I2C学习之RTC(通过I2C总线读写RTC)笔记_第9张图片

P12端子输出,可外接设备camrea

嵌入式系统I2C学习之RTC(通过I2C总线读写RTC)笔记_第10张图片

也可接入外接设备

总结,可见iic2上挂载着音频,摄像头,和自定义外接设备.

RTC芯片

下面开始针对RTC来研究i2c

在这个板子上我们i2c-1上挂载了RTC,使用rx8010sj芯片,是一个实时始终模块,集成了一个32768Khz的晶体振荡器包含年月日周小时分秒的时钟计数器,还包含时间劲爆,间隔计时器和时间更新中断等功能

嵌入式系统I2C学习之RTC(通过I2C总线读写RTC)笔记_第11张图片

管脚分配如下:

嵌入式系统I2C学习之RTC(通过I2C总线读写RTC)笔记_第12张图片

功能说明

嵌入式系统I2C学习之RTC(通过I2C总线读写RTC)笔记_第13张图片

地址定义:

嵌入式系统I2C学习之RTC(通过I2C总线读写RTC)笔记_第14张图片

可见地址为0x32.

RTC在开发板上的操作-使用ic2-tools

首先看手册,查找有用的寄存器地址.

嵌入式系统I2C学习之RTC(通过I2C总线读写RTC)笔记_第15张图片

 首先我们可以使用i2ctools来查看或者操作i2c寄存器,具体i2ctools是如何使用,如何下载编译的,这里不描述了,可以百度,去看,如果真的不清楚,可以留言,我可以考虑单独针对i2c-tools写一篇如何编译和使用的文章.

i2cdetect -l 得到I2c列表
i2c-0	i2c       	21a0000.i2c                     	I2C adapter
i2c-1	i2c       	21a4000.i2c                     	I2C adapter

可看到存在2个i2c总线,和硬件所说的一致

root@fl-imx6ull:~# i2cdetect -y 0
     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: -- -- -- -- -- -- -- --         

可看到第一条总线上存在1个sop设备,地址为0x32 经分析rx8010的地址未0x32,能对应上

root@fl-imx6ull:~# i2cdetect -y 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- -- 
10: -- -- -- -- -- -- -- -- -- -- UU -- -- -- -- -- 
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
70: -- -- -- -- -- -- -- -- 

第二条总线有一个设备,地址为0x1a,应该为音频设备,本次内容和音频无关,我们以后分析;

root@fl-imx6ull:~# i2cget -f -y 0 0x32
0x07
root@fl-imx6ull:~# i2cdump -f -y 0 0x32
No size specified (using byte-data access)
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f    0123456789abcdef
00: XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX    XXXXXXXXXXXXXXXX
10: 56 07 01 0c 27 03 22 d8 00 10 01 00 00 06 20 00    V???'?"?.??..? .
20: 20 00 00 00 00 00 08 00 00 00 00 00 00 00 00 00     .....?.........
30: 08 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ?...............
40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
70: XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX    XXXXXXXXXXXXXXXX
80: XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX    XXXXXXXXXXXXXXXX
90: 57 07 01 0c 27 03 22 d8 00 10 01 00 00 06 20 00    W???'?"?.??..? .
a0: 20 00 00 00 00 00 08 00 00 00 00 00 00 00 00 00     .....?.........
b0: 08 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ?...............
c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
f0: XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX    XXXXXXXXXXXXXXXX

这样,我们就学会了如何操作寄存器,那么我们怎么通过i2c修改系统时间呢?

根据数据表查看得到数据,我们可以使用这个脚本通过i2c获得时间

root@fl-imx6ull:~# cat showrtc.sh 
#!/bin/bash
temp='00'
sec='00'
while true
do
	temp=`i2cget -f -y 0 0x32 0x16`
	temp=${temp:2}
	year=$((${temp}+2000))
	
	temp=`i2cget -f -y 0 0x32 0x15`
	month=${temp:2}

	temp=`i2cget -f -y 0 0x32 0x14`
	day=${temp:2}

	temp=`i2cget -f -y 0 0x32 0x12`
	hour=${temp:2}

	temp=`i2cget -f -y 0 0x32 0x11`
	min=${temp:2}

	temp=`i2cget -f -y 0 0x32 0x10`
	second=${temp:2}

	echo "time is ${year}-${month}-${day} ${hour}:${min}:${second}" 
	usleep 1000000
done

执行后如下图:

root@fl-imx6ull:~# ./showrtc.sh 
time is 2022:03:27 01-09-08
time is 2022:03:27 01-09-09
time is 2022:03:27 01-09-10
time is 2022:03:27 01-09-11
time is 2022:03:27 01-09-12
time is 2022:03:27 01-09-13

写数据:

root@fl-imx6ull:~# i2cdump -f -y 0 0x32
No size specified (using byte-data access)
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f    0123456789abcdef
00: XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX    XXXXXXXXXXXXXXXX
10: 12 19 02 00 27 03 22 d8 00 10 01 00 00 06 20 00    ???.'?"?.??..? .
20: 20 00 00 00 00 00 08 00 00 00 00 00 00 00 00 00     .....?.........
30: 08 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ?...............
40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
70: XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX    XXXXXXXXXXXXXXXX
80: XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX    XXXXXXXXXXXXXXXX
90: 12 19 02 00 27 03 22 d8 00 10 01 00 00 06 20 00    ???.'?"?.??..? .
a0: 20 00 00 00 00 00 08 00 00 00 00 00 00 00 00 00     .....?.........
b0: 08 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ?...............
c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
f0: XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX    XXXXXXXXXXXXXXXX

root@fl-imx6ull:~# i2cset -f -y 0 0x32 0x11 0x33

root@fl-imx6ull:~# i2cdump -f -y 0 0x32
No size specified (using byte-data access)
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f    0123456789abcdef
00: XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX    XXXXXXXXXXXXXXXX
10: 31 33 02 00 27 03 22 d8 00 10 01 00 00 06 20 00    13?.'?"?.??..? .
20: 20 00 00 00 00 00 08 00 00 00 00 00 00 00 00 00     .....?.........
30: 08 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ?...............
40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
70: XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX    XXXXXXXXXXXXXXXX
80: XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX    XXXXXXXXXXXXXXXX
90: 32 33 02 00 27 03 22 d8 00 10 01 00 00 06 20 00    23?.'?"?.??..? .
a0: 20 00 00 00 00 00 08 00 00 00 00 00 00 00 00 00     .....?.........
b0: 08 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ?...............
c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
f0: XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX    XXXXXXXXXXXXXXXX
root@fl-imx6ull:~# hwclock -s 将rtc时间同步到系统中
root@fl-imx6ull:~# date
Sun Mar 27 02:33:37 UTC 2022

hwclock -w 将系统时间同步到rtc中

hwclock -r 读取系统时间

优化以上脚本如下:

root@fl-imx6ull:~# cat showrtc.sh 
#!/bin/bash
temp='00'
sec='00'
index=1
echo "start get the rtc time "
while ((index<10))
do
	temp=`i2cget -f -y 0 0x32 0x16`
	temp=${temp:2}
	year=$((${temp}+2000))
	
	temp=`i2cget -f -y 0 0x32 0x15`
	month=${temp:2}

	temp=`i2cget -f -y 0 0x32 0x14`
	day=${temp:2}

	temp=`i2cget -f -y 0 0x32 0x12`
	hour=${temp:2}

	temp=`i2cget -f -y 0 0x32 0x11`
	min=${temp:2}

	temp=`i2cget -f -y 0 0x32 0x10`
	second=${temp:2}

	echo "time is ${year}:${month}:${day} ${hour}-${min}-${second}" 
	usleep 1000000
	index=$((${index}+1))
done

echo "start set the rtc time to 2021-01-02 03:04:05"
i2cset -f -y 0 0x32 0x16 0x21 # 年
i2cset -f -y 0 0x32 0x15 0x01 # 月
i2cset -f -y 0 0x32 0x14 0x02 # 日
i2cset -f -y 0 0x32 0x12 0x03 # 时
i2cset -f -y 0 0x32 0x11 0x04 # 分
i2cset -f -y 0 0x32 0x10 0x05 #秒
echo "sync rtc to system time "
hwclock -s
echo "set time finished"

echo "current system time is `date`"

	temp=`i2cget -f -y 0 0x32 0x16`
	temp=${temp:2}
	year=$((${temp}+2000))
	
	temp=`i2cget -f -y 0 0x32 0x15`
	month=${temp:2}

	temp=`i2cget -f -y 0 0x32 0x14`
	day=${temp:2}

	temp=`i2cget -f -y 0 0x32 0x12`
	hour=${temp:2}

	temp=`i2cget -f -y 0 0x32 0x11`
	min=${temp:2}

	temp=`i2cget -f -y 0 0x32 0x10`
	second=${temp:2}

	echo "current rtc time is ${year}:${month}:${day} ${hour}-${min}-${second}" 

执行如下:

root@fl-imx6ull:~# ./showrtc.sh 
start get the rtc time 
time is 2021:01:02 03-06-24
time is 2021:01:02 03-06-25
time is 2021:01:02 03-06-26
time is 2021:01:02 03-06-27
time is 2021:01:02 03-06-28
time is 2021:01:02 03-06-29
time is 2021:01:02 03-06-31
time is 2021:01:02 03-06-32
time is 2021:01:02 03-06-33
start set the rtc time to 2021-01-02 03:04:05
sync rtc to system time 
set time finished
current system time is Sat Jan  2 03:04:05 UTC 2021
current rtc time is 2021:01:02 03-04-05
I2ctransfer 使用 这个使用的是i2c协议不是smi2c协议
root@fl-imx6ull:~# i2cdump -f -y 0 0x32 
No size specified (using byte-data access)
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f    0123456789abcdef
00: XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX    XXXXXXXXXXXXXXXX
10: 12 41 21 03 27 03 22 d8 00 10 01 00 00 06 20 00    ?A!?'?"?.??..? .
20: 00 00 00 00 00 00 08 00 00 00 00 00 00 00 00 00    ......?.........
30: 08 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ?...............
40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
70: XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX    XXXXXXXXXXXXXXXX
80: XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX    XXXXXXXXXXXXXXXX
90: 12 41 21 03 27 03 22 d8 00 10 01 00 00 06 20 00    ?A!?'?"?.??..? .
a0: 00 00 00 00 00 00 08 00 00 00 00 00 00 00 00 00    ......?.........
b0: 08 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ?...............
c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
f0: XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX    XXXXXXXXXXXXXXXX
# 读从0x10地址开始的0x16个数据
root@fl-imx6ull:~# ./i2ctransfer -f -y 0 w1@0x32 0x10 r16
0x16 0x41 0x21 0x03 0x27 0x03 0x22 0xd8 0x00 0x10 0x01 0x00 0x00 0x06 0x20 0x00
也可以使用./i2ctransfer -f -y 0 w1@0x32 0x10 r16@0x32 ,使用i2ctransfer读数据要先写入要读取的地址,然后紧跟这读数据才行,不能直接使用读
root@fl-imx6ull:~# ./i2ctransfer -f -y 0 w1@0x32 0x10 r8
0x28 0x41 0x21 0x03 0x27 0x03 0x22 0xd8
# 写数据 写0号总线0x32设备 0x12地址 为0x22
root@fl-imx6ull:~# ./i2ctransfer -f -y 0 w2@0x32 0x12 0x22
root@fl-imx6ull:~# ./i2ctransfer -f -y 0 w1@0x32 0x10 r16
0x00 0x44 0x22 0x03 0x27 0x03 0x22 0xd8 0x00 0x10 0x01 0x00 0x00 0x06 0x20 0x00

我们从寄存器上看到,有专门的寄存器是表示时间的,那么当时间和日期冲突的时候,那个起主要作用呢?验证如下:

修改星期看日期是否改变
root@fl-imx6ull:~# date
Sun Mar 27 17:33:21 UTC 2022
root@fl-imx6ull:~# i2cset -f -y 0 0x32 0x13 0x01
root@fl-imx6ull:~# date
Sun Mar 27 17:34:23 UTC 2022
root@fl-imx6ull:~# hwclock -s
root@fl-imx6ull:~# date
Sun Mar 27 17:34:37 UTC 2022
修改日期看星期是否改变
root@fl-imx6ull:~# date
Sat Mar 26 17:30:37 UTC 2022
root@fl-imx6ull:~# i2cset -f -y 0 0x32 0x14 0x27
root@fl-imx6ull:~# date
Sat Mar 26 17:33:13 UTC 2022
root@fl-imx6ull:~# hwclock -s
root@fl-imx6ull:~# date
Sun Mar 27 17:33:21 UTC 2022
验证日期错误数据输入验证
root@fl-imx6ull:~# i2cset -f -y 0 0x32 0x14 0x32
root@fl-imx6ull:~# date
Sun Mar 27 17:35:33 UTC 2022
root@fl-imx6ull:~# hwclock -s
hwclock: RTC_RD_TIME: Invalid argument

验证星期的错误数据输入验证.
root@fl-imx6ull:~# i2cset -f -y 0 0x32 0x13 0x03
root@fl-imx6ull:~# hwclock -s
root@fl-imx6ull:~# date
Sun Mar 27 17:42:32 UTC 2022
root@fl-imx6ull:~# i2cget -f -y 0 0x32 0x13
0x03
可见,错误型数据可以写入寄存器,但是不影响rtc走时功能
其他的寄存器,如报警终端,周期定时终端,计时更新等这里就不一一讲解了,熟悉了最基础的,后面的参照手册一一实践就可以了.

就写到这里吧,现在正在考虑是否在深入一点,写一个就象i2ctools一样的程序,实现我们自己的i2c操作,但是考虑毕竟已经有了i2ctools,现在意义不大,走一步看一步吧.

编写不易,关注点赞后再走,您的点赞是我写下去的最大动力!

你可能感兴趣的:(嵌入式系统,shell脚本编程,学习,linux)