我们都知道,嵌入式系统中的RTC测试可以使用date,hwclock来查看写入时间,断电一段时间在查看始终的走时功能是否正常.这些都是通过固定的命令来实现的,我在学习嵌入式系统的时候,接触到了I2C总线,把学习的笔记总结了以下.
I2C和其他的接口是不一样的,比如232,485等等,这些在嵌入式系统中都有预留接口,可以在上位机比如在windows平台开发测试程序来完成,平时就对它有一个较深的理解,但是I2C是不一样,它一般连接的设备有RTC,声音,EEprom等,这些一般都是内部接口,所以我们平时用不到,也就不熟悉,说实话,我第一次接触的时候也挺抽象的(对于那些专门搞硬件的当然很清楚嘿嘿),这里有不同意见的可以提,但是不接收吵架式回复.
I²C(Inter-Integrated Circuit),中文应该叫集成电路总线,它是一种串行通信总线,使用多主从架构,是由飞利浦公司在1980年代初设计的,方便了主板、嵌入式系统或手机与周边设备组件之间的通讯。由于其简单性,它被广泛用于微控制器与传感器阵列,显示器,IoT设备,EEPROM等之间的通信。
I²C最重要的功能包括:
IIC总线是多主总线
多个主机可以同时尝试控制总线,而不会破坏消息
所有事务都已start开始,并由stop结束
当scl为h时,sda线上的h到l转换定义了一个start
当scl为h是,sda线上的l到h转换定义了一个stop
要想了解更多的i2c的知识,可网络查询,也可以参考我以前写的一篇科普文章https://blog.csdn.net/mainmaster/article/details/125721501?spm=1001.2014.3001.5501
我们这例使用的是飞凌公司的6ULL-C的开发板,首先查看原理图:
可以看到,具有2路i2c总线
rtc原理
P16的排线上也有i2c-1,经查为LCD
同时也连接到了P20沛县上,我们可以看到这个是可以接入外接设备的,如接入一个E2rom原件
可以看到,i2c-1总线可挂载LCD,RTC,外部设备
i2c-2的出口
音频接口
P12端子输出,可外接设备camrea
也可接入外接设备
总结,可见iic2上挂载着音频,摄像头,和自定义外接设备.
下面开始针对RTC来研究i2c
在这个板子上我们i2c-1上挂载了RTC,使用rx8010sj芯片,是一个实时始终模块,集成了一个32768Khz的晶体振荡器包含年月日周小时分秒的时钟计数器,还包含时间劲爆,间隔计时器和时间更新中断等功能
管脚分配如下:
功能说明
地址定义:
可见地址为0x32.
首先看手册,查找有用的寄存器地址.
首先我们可以使用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,现在意义不大,走一步看一步吧.
编写不易,关注点赞后再走,您的点赞是我写下去的最大动力!