i.mx8 RTC问题
项目场景:
需要增加外置RTC,保证时间的精准。
问题描述:
基本情况,外置i2c接口的RTC,注册、读写都正常,但是偶发性重启后,系统时间是2022,rtc时间是1970,都像是恢复了默认时间一样。
原因分析:
几个名词含义:
- 系统时钟(
date
):存储在内存中,由操作系统维护,断电后会丢失,依赖硬件时钟初始化。- 硬件时钟(
hwclock
):由主板电池供电的独立时钟,断电后仍能运行,用于系统启动时初始化系统时钟。- UTC时间:全球统一时间。
- CST时间:我国采用时间,东八区时间,UTC+8。
- 例如:硬件时钟显示
10:00 UTC
,系统时钟若为北京时间(UTC+8),则显示18:00
。
设置时间脚本:
#/bin/bash
echo close ntp
timedatectl set-ntp false
echo time set rtc1
date -s "2025-07-16 8:00:00" && hwclock -w -f /dev/rtc1
echo print rtc1
hwclock -f /dev/rtc1
echo system to rtc1
hwclock --systohc -u
echo show rtc1
hwclock -u
echo sync to sys
hwclock --hctosys -u
这样设置后,date返回的系统时间,以及hwclock返回的rtc时间都是正确的,但是奇怪的事情发生了,若干次重启后,date显示2022,hwclock显示1970。
于是查看内核打印信息,是怎么说的:
内核显示上电时,就是把rtc读给了系统啊,但是确实是读了1970,那原因在于,nxp有自己集成的一个rtc0是默认的,实际上通过hwclock查的是rtc0,并不是我的外置rtc,通过指令可以看到,外置的rtc1实际上是一直正常工作的。
解决方案:
那解决的问题就是变成了:干掉rtc0,使能rtc1,有很多的解决办法,我的解决办法是简单粗暴,改设备树。
其中在NXP的设备树中,我找到了他对自己rtc的定义
snvs: snvs@30370000 {compatible = "fsl,sec-v4.0-mon","syscon", "simple-mfd";reg = <0x30370000 0x10000>;snvs_rtc: snvs-rtc-lp {compatible = "fsl,sec-v4.0-mon-rtc-lp";regmap =<&snvs>;offset = <0x34>;interrupts = <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>,<GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>;clocks = <&clk IMX8MP_CLK_SNVS_ROOT>;clock-names = "snvs-rtc";};snvs_pwrkey: snvs-powerkey {compatible = "fsl,sec-v4.0-pwrkey";regmap = <&snvs>;interrupts = <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>;clocks = <&clk IMX8MP_CLK_SNVS_ROOT>;clock-names = "snvs-pwrkey";linux,keycode = <KEY_POWER>;wakeup-source;status = "disabled";};};
snvs_rtc就是我们的目标rtc,把它干掉就可以了。
在自己的设备树xxx.dts里加上这一句,因为我是引用了NXP的imx8mp.dtsi的。
&snvs_rtc{status = "disabled";
};
至此,大功告成,时间正常,内核打印只显示这个i2crtc了,只是映射从从rtc1变为了rtc0。
最后:记得更改本地时区。
timedatectl set-timezone Asia/Shanghai