很多嵌入式设备在使用过程中,会碰到未联网的状态,但是有需要保证时间的正常,或者定时开关机功能。这个时候就需要添加RTC 时钟模块。下面通过mstar 平台的rx8130ce 型号时钟调试为例,一起分享。
RTC HW 连接
从HW提供的原理图设计时,提供了两款RTC 时钟芯片,地址分别是0x64,0xD0。
从提供的PCB 板上,UT3 未上件。 我们进一步查询I2C 的连接走线。
分析完原理图,要确保硬件的一下几点正常:
- RTC 的power 连接正常,电池(待机/断电时供电)和主板(上电时)
- RTC 的I2C 和主芯片的连接正常;
- RTC 的I2C 地址 的确定;
I2C 地址配置
找到pin 脚定义,然后配置总线,设置delay 时间,接着在总线下面挂载设备。
//Bus Info Define
#define BOARD_I2C_SWBUS_NUM 3
#define BOARD_I2C_HWBUS_NUM 0
#define BOARD_I2C_DEVICE_NUM 6
static SWI2CBus_t BOARD_I2C_SWBUS[BOARD_I2C_SWBUS_NUM]=
{
//Example for SW I2C => { 1, PAD_DDCR_CK, PAD_DDCR_DA, 60, }, //SW_I2C /SCL_PAD /SDA_PAD /Delay
// Bus-0
{PAD_DDCR_CK, PAD_DDCR_DA, 100}, //IS_SW_I2C /SCL_PAD /SDA_PAD /Delay
// Bus-1
{PAD_TGPIO0 , PAD_TGPIO1, 100},
// Bus-2
{PAD_GPIO19 , PAD_GPIO20,100},
// Bus-3
//{PAD_GPIO2 , PAD_GPIO3,100},
};
static HWI2CBus_t BOARD_I2C_HWBUS[BOARD_I2C_HWBUS_NUM];
//Device Info Define
static I2CDeviceInfo_s Board_I2C_Dev[BOARD_I2C_DEVICE_NUM] =
{
//Example => { TUNER1, 1, 0xC2 }, //gID(U32) /i2c_bus(U8) /slave_id(U8)
{TUNER1 , 1, 0xC0}, //gID(U32) /i2c_bus(U8) /slave_id(U8)
// AD82088
{AMP_SLAVER_ID , 1, 0x62}, // 0x31 << 1 --> 0x62
// RTC
{RTC_I2C_ID , 1, 0x64},
// temp R/W
{TMP102_CHIP_R , 1, 0x90},
{TMP102_CHIP_W , 1, 0x91},
// TCA9535
{TCA9539_I2C_ID , 2, 0xE8}, // 0x74 << 1 = 0xE8
};
I2C 的读写
注意上面的RTC8130_SECADDR 是 RTC 的寄存器地址,跟时间日期相关的几个寄存器地址如下:
#define RTC8130_SLAVEADDR 0x64
#define RTC8130_SECADDR 0x10
#define RTC8130_MINADDR 0x11
#define RTC8130_HOURADDR 0x12
#define RTC8130_WEEKADDR 0x13
#define RTC8130_DATEADDR 0x14
#define RTC8130_MONTHADDR 0x15
#define RTC8130_YEARADDR 0x16
这些地址在协议里面会有说明。
RTC 时间数据格式
分析datasheet 中RTC 时间格式,其中秒,分,时,天,月,年 都是BCD 码格式存储。周 的存储方法不一样,按照所在的bit 位标记为第几周,一个月最多跨6 周。
设置时间
static MAPI_U8 HEX2BCD(MAPI_U8 cHEXData)
{
MAPI_U8 cTemp;
cTemp = ((cHEXData / 10) << 4) | (cHEXData % 10);
return cTemp;
}
先将16进制的数据转换成BCD 码,然后设置到对应寄存器中。
SecAdd = RTC8130_SECADDR; // 0x10
TimeTable[RTC_SECOND] = HEX2BCD(RTC8130_TimeData.param[RTC_SECOND]) & 0x7F;
TimeTable[RTC_MINUTE] = HEX2BCD(RTC8130_TimeData.param[RTC_MINUTE]) & 0x7F;
TimeTable[RTC_HOUR] = HEX2BCD(RTC8130_TimeData.param[RTC_HOUR]) & 0x3F;
TimeTable[RTC_WEEK] = RTC8130_TimeData.param[RTC_WEEK] & 0x7F ;
TimeTable[RTC_DATE] = HEX2BCD(RTC8130_TimeData.param[RTC_DATE]) & 0x3F;
TimeTable[RTC_MONTH] = HEX2BCD(RTC8130_TimeData.param[RTC_MONTH]) & 0x1F;
TimeTable[RTC_YEAR] = HEX2BCD(RTC8130_TimeData.param[RTC_YEAR]) & 0xFF;
ret = iptr->WriteBytes(1,&SecAdd,7,&TimeTable[RTC_SECOND]);
获取时间
mapi_i2c *iptr = NULL;
MAPI_U8 regAddr = RTC8130_SECADDR;
RX8130_PRINTF(printf("[%s][%d] RX81390 Enter .n",__FUNCTION__,__LINE__));
iptr = mapi_i2c::GetI2C_Dev(RTC_I2C_ID);
if(iptr == NULL)
{
printf("[%s][%d] RX81390 Invalid I2c rtc addr .n", __FUNCTION__,__LINE__);
return MAPI_FALSE;
}
ret = iptr->ReadBytes(1, ®Addr, 7, TimeTable);
if(MAPI_FALSE == ret)
{
printf("[%s][%d] RX81390 Read ret = %dn", __FUNCTION__,__LINE__,ret);
return MAPI_FALSE;
}
RTC8130_TimeData.param[RTC_SECOND] = BCD2HEX(TimeTable[0]);
RTC8130_TimeData.param[RTC_MINUTE] = BCD2HEX(TimeTable[1]);
RTC8130_TimeData.param[RTC_HOUR] = BCD2HEX(TimeTable[2]);
RTC8130_TimeData.param[RTC_WEEK] = TimeTable[3] & 0x7F;
RTC8130_TimeData.param[RTC_DATE] = BCD2HEX(TimeTable[4]);
RTC8130_TimeData.param[RTC_MONTH] = BCD2HEX(TimeTable[5]);
RTC8130_TimeData.param[RTC_YEAR] = BCD2HEX(TimeTable[6]);
将读取到的BCD码转换成16进制数据给上层使用。
static MAPI_U8 BCD2HEX(MAPI_U8 cBCDData)
{
MAPI_U8 cTemp;
cTemp = ((cBCDData >> 4) * 10) + ( cBCDData & 0x0F);
return cTemp;
}
另外要主要周,年的范围。例如, 年的最大值 165
(80+40+20+10+8+4+2+1),那么实际使用的需要补齐。
2019 年则传入RTC时是19,1970 传入应该是70 。一般定时也不多超过100年,所以还是能够满足实际要求的。
RTC 初始配置
RX8130_CONFIG g_RX8130_CONFIGData[] =
{
{0x30,0x80},//enable DTE
{0x1c,0x04},
{0x1d,0x06},
{0x1e,0x00},
{0x1f,0x00},
};
iptr = mapi_i2c::GetI2C_Dev(RTC_I2C_ID);
if(iptr == NULL)
{
printf("[%s][%d] RX81390 Invalid I2c mcu addr .n",__FUNCTION__,__LINE__);
return ret;
}
for(i=0; i
{
unAddr = g_RX8130_CONFIGData
.RX8130_Address;
unData = g_RX8130_CONFIGData.RX8130_InitData;
ret = iptr->WriteBytes(1, &unAddr, 1, &unData);
RX8130_PRINTF(printf("[%s][%d] RX8130 Write [0x%02x : 0x%02X] ret = %dn",__FUNCTION__,__LINE__,unAddr,unData,ret));
}
return ret;