/****************************************************************************** 版权所有: 文件名称: rtc_ds1338.c 文件版本: 01.01 创建作者: sunxi 创建日期: 2008-07-09 功能说明: DS1338 实时时钟驱动程序。 其它说明: DS1338中的年从2000年开始。 修改记录: */ /*------------------------------- 头文件 -------------------------------------- */ #include "bspconfig.h" #include "i2c.h" #include "my_rtc.h" #include "watchdog.h" //#include "rt_ints.h" /*------------------------------- 宏定义 -------------------------------------- */ #if CFG_BSP_DEBUG #define _DEBUG_RTC #endif #define RTC_I2C_ID 0X64 #define RTC_ADDR_EXT 0X0D #define RTC_ADDR_FLAG 0X0E #define RTC_ADDR_CONTROL 0X0F #define RTC_FLAG_VLF 0X02 //rtc rx8025内部结构定义 typedef struct { u8 second; //0~59 u8 minute; //0~59 u8 hour; //0~23 u8 week; //每个星期用一个bit表示 u8 date; //1~31 u8 month; //1~12 *与tm结构范围不同 u8 year; //0~99 *与tm结构范围不同 }rtc_t; typedef struct { u8 ext_reg; u8 flg_reg; u8 ctl_reg; // }rtc_ctrl_t; // 此结构仅供参考,不可使用 typedef struct { rtc_t rtc; u8 ram; // 可以任意读写 u8 min_alm; // u8 hour_alm; u8 day_alm; u8 tim_cnt0; u8 tim_cnt1; rtc_ctrl_t rtc_ctrl; }rtc_all_t; /*------------------------------ 全局变量 ------------------------------------- */ int g_rtc_write_5ms; // 离实际写入时间还差多少个5ms rtc_t g_rtc_write_data; // 需要写入RTC芯片的时间 /*------------------------------ 函数声明 ------------------------------------- */ int _rtc_read(uint32_t offset, unsigned char *buffer, uint32_t length); int _rtc_write(uint32_t offset, unsigned char *buffer, uint32_t length); /*------------------------------ 外部函数 ------------------------------------- */ /****************************************************************************** 函数名称: rtc_init 函数版本: 01.01 创建作者: sunxi 创建日期: 2008-08-06 函数说明: rtc初始化。 参数说明: 无 返回值: 成功返回0. 修改记录: */ int rtc_init(void) { return 0; } /****************************************************************************** 函数名称: rtc_time_read 函数版本: 01.01 创建作者: sunxi 创建日期: 2008-08-06 函数说明: 从时钟芯片中读出时间。 参数说明: p_tm(out): 读出的时间存放在这个指针所指的结构中。 返回值: 0: 成功返回。 1: 成功返回,但是由于时钟芯片振荡器曾经停止过,所以时间可能不准。 <0:读取失败。 修改记录: */ int rtc_time_read(struct rtc_time_t *p_tm) { int ret; rtc_t rtc; u8 flag=0; //检查参数 if(p_tm == 0) { return -1; } memset(&rtc, 0x00, sizeof(rtc_t)); //读出数据 ret = _rtc_read(0,(unsigned char *)&rtc,sizeof(rtc)); if(ret != 0) { return -2; } ret = _rtc_read(RTC_ADDR_FLAG,&flag,1); if(ret != 0) { return -3; } //转换格式 //清除不需要的标志 rtc.second &= ~0x80; rtc.hour &= ~0xc0; //BCD转化为二进制 p_tm->ms = (unsigned short)((rtc.second >> 4)*10 + (rtc.second & 0xf)); //秒 p_tm->min = (unsigned char )((rtc.minute >> 4)*10 + (rtc.minute & 0xf)); //分 p_tm->hour = (unsigned char )((rtc.hour >> 4)*10 + (rtc.hour & 0xf)); //时 p_tm->day = (unsigned char )((rtc.date >> 4)*10 + (rtc.date & 0xf)); //日 p_tm->month = (unsigned char )((rtc.month >> 4)*10 + (rtc.month & 0xf)); //月 p_tm->year = (unsigned char )((rtc.year >> 4)*10 + (rtc.year & 0xf)); //年 //s->ms p_tm->ms *= 1000; //如果时钟振荡器曾经停止过,时间有可能不准,返回1。 if(flag&RTC_FLAG_VLF) { return 1; } return 0; } /****************************************************************************** 函数名称: rtc_time_write 函数版本: 01.01 创建作者: sunxi 创建日期: 2008-08-06 函数说明: 将时间写入时钟芯片。 参数说明: p_tm(in): 要写入的时间存放在这个指针所指的结构中。 返回值: 0: 成功返回。 <0:写入失败。 修改记录: */ extern void sys_time_change(struct rtc_time_t *p_ct); int rtc_time_write(struct rtc_time_t *p_tm) { //uint32_t flags; int seccond,ms5; rtc_t rtc; // rt_printf("rtc_time_write.\r\n"); //检查参数 if(p_tm == 0) { return -11; } if(p_tm->ms > 59999) { return -12; } if(p_tm->min > 59) { return -13; } if(p_tm->hour > 23) { return -14; } if(p_tm->day <1 || p_tm->day > 31) { return -15; } if(p_tm->month <1 || p_tm->month > 12) { return -16; } if(p_tm->year > 99) { return -17; } //ms->s,使用下一秒作为要写入的秒值 seccond = p_tm->ms/1000 + 1; ms5 = (seccond*1000 - p_tm->ms)/5; if(ms5 <1) { ms5 = 1; } if(seccond>=60) { seccond-=60; sys_time_change(p_tm); } //二进制转换为BCD rtc.second = (unsigned char)(((seccond /10)<<4) | (seccond %10)); rtc.minute = (unsigned char)(((p_tm->min /10)<<4) | (p_tm->min %10)); rtc.hour = (unsigned char)(((p_tm->hour /10)<<4) | (p_tm->hour %10)); rtc.date = (unsigned char)(((p_tm->day /10)<<4) | (p_tm->day %10)); rtc.month = (unsigned char)(((p_tm->month/10)<<4) | (p_tm->month %10)); rtc.year = (unsigned char)(((p_tm->year /10)<<4) | (p_tm->year %10)); //星期不使用直接赋值1 rtc.week = 1; //写入数据 rt_irq_save(flags); g_rtc_write_data = rtc; g_rtc_write_5ms = ms5; rt_irq_restore(flags); return 0; } void rtc_time_write_5ms(void) { int ret = 0; rtc_ctrl_t rtc_ctrl; if(g_rtc_write_5ms == 0) { return; } if(g_rtc_write_5ms == 1) { // 写入时间数据 //ret = _rtc_write(0,(unsigned char *)&g_rtc_write_data,sizeof(g_rtc_write_data)); //jack.liu 20200921 读写RTC失能 if(ret) { rt_printf("rtc_write_5ms0:ret=%d)\r\n",ret); } // 写入控制数据 rtc_ctrl.ext_reg = 0x00; rtc_ctrl.flg_reg = 0x00; rtc_ctrl.ctl_reg = 0x40;// 默认2.0s温度补偿 //ret = _rtc_write(RTC_ADDR_EXT,(unsigned char *)&rtc_ctrl,sizeof(rtc_ctrl)); //jack.liu 20200921 读写RTC失能 if(ret) { rt_printf("rtc_write_5ms1:ret=%d)\r\n",ret); } } g_rtc_write_5ms--; } /****************************************************************************** 函数名称: rtc_nvram_read 函数版本: 01.01 创建作者: sunxi 创建日期: 2008-08-07 函数说明: 从时钟芯片的NVRAM中读出数据。 参数说明: offset(in):需要读的数据在NVRAM中的偏移量,和length之和必须小于CFG_RTC_NVRAM_SIZE. buffer(out):读出数据的buffer。 length(in): 需要读出数据的长度,和offset之和必须小于CFG_RTC_NVRAM_SIZE。 返回值: 成功返回0. 修改记录: */ int rtc_nvram_read(uint32_t offset, unsigned char *buffer, uint32_t length) { //检查参数 if(buffer == 0 || (offset + length) > CFG_RTC_NVRAM_SIZE) { return -1; } if(length == 0) { return 0; } return _rtc_read(offset+7,buffer,length); } /****************************************************************************** 函数名称: rtc_nvram_write 函数版本: 01.01 创建作者: sunxi 创建日期: 2008-08-07 函数说明: 将数据写入时钟芯片的NVRAM中。 参数说明: offset(in):需要写入的数据在NVRAM中的偏移量,和length之和必须小于CFG_RTC_NVRAM_SIZE. buffer(in):写入数据的buffer。 length(in): 需要写入数据的长度,和offset之和必须小于CFG_RTC_NVRAM_SIZE。 返回值: 成功返回0. 修改记录: */ int rtc_nvram_write(uint32_t offset, unsigned char *buffer, uint32_t length) { //检查参数 if(buffer == 0 || (offset + length) > CFG_RTC_NVRAM_SIZE) { return -1; } if(length == 0) { return 0; } return _rtc_write(offset+7, buffer, length); } /*------------------------------ 内部函数 ------------------------------------- */ /****************************************************************************** 函数名称: _rtc_read 函数版本: 01.01 创建作者: sunxi 创建日期: 2008-08-07 函数说明: 从时钟芯片中读出数据。 参数说明: offset(in):需要读的数据在时钟芯片的偏移量. buffer(out):读出数据的buffer。 length(in): 需要读出数据的长度。 返回值: 成功返回0. 修改记录: */ int _rtc_read(uint32_t offset, unsigned char *buffer, uint32_t length) { #if 0 unsigned char c; int h_i2c,ret; h_i2c = i2c_open(I2C_ID_RTC); if(h_i2c < 0) { return -1; } ret = -2; //等待总线释放 I2C_WAIT_BUS_IDLE(); //发送模式 MCF_I2CR |= MCF_I2C_I2CR_MTX; //发送START信号 MCF_I2CR |= MCF_I2C_I2CR_MSTA; //发送控制字节 MCF_I2DR = RTC_I2C_ID; I2C_WAIT_COMPLETION(); I2C_CHECK_ACK(); //发送地址 MCF_I2DR = (unsigned char)(offset); I2C_WAIT_COMPLETION(); I2C_CHECK_ACK(); //发送重开始信号,方向改为读 MCF_I2CR |= MCF_I2C_I2CR_RSTA; MCF_I2DR = RTC_I2C_ID | 0x01; I2C_WAIT_COMPLETION(); I2C_CHECK_ACK(); //接收模式 MCF_I2CR &= ~MCF_I2C_I2CR_MTX; //接收数据,最后一个字节不发ACK. if(length == 1) { MCF_I2CR |= MCF_I2C_I2CR_TXAK; //不发ACK c = MCF_I2DR; //空读,启动下一个字节的读 I2C_WAIT_COMPLETION(); *buffer++ = MCF_I2DR; I2C_WAIT_COMPLETION(); } else { //循环接收length个字节。 MCF_I2CR &= ~MCF_I2C_I2CR_TXAK; //发送ACK c = MCF_I2DR; //空读,启动下一个字节的读 I2C_WAIT_COMPLETION(); while(length--) { if(length == 1) { MCF_I2CR |= MCF_I2C_I2CR_TXAK; //不发ACK } *buffer++ = MCF_I2DR; //读数据,并启动下一个字节的读。 I2C_WAIT_COMPLETION(); } } ret = 0; LABEL_END: //发送STOP信号 MCF_I2CR &= ~MCF_I2C_I2CR_MSTA; i2c_close(h_i2c); return ret; #endif return 0; } /****************************************************************************** 函数名称: _rtc_write 函数版本: 01.01 创建作者: sunxi 创建日期: 2008-08-07 函数说明: 将数据写入时钟芯片中。 参数说明: offset(in):需要写入的数据在时钟芯片中的偏移量. buffer(in):写入数据的buffer。 length(in): 需要写入数据的长度。 返回值: 成功返回0. 修改记录: */ int _rtc_write(uint32_t offset, unsigned char *buffer, uint32_t length) { #if 0 int h_i2c,ret; h_i2c = i2c_open(I2C_ID_RTC); if(h_i2c < 0) { return -1; } ret = -2; //等待总线释放 I2C_WAIT_BUS_IDLE(); //发送模式 // MCF_I2CR |= MCF_I2C_I2CR_MTX; //发送START信号 // MCF_I2CR |= MCF_I2C_I2CR_MSTA; //发送控制字节 MCF_I2DR = RTC_I2C_ID; I2C_WAIT_COMPLETION(); I2C_CHECK_ACK(); //发送地址 MCF_I2DR = (unsigned char)(offset); I2C_WAIT_COMPLETION(); I2C_CHECK_ACK(); //发送数据 while(length--) { MCF_I2DR = *buffer++; I2C_WAIT_COMPLETION(); I2C_CHECK_ACK(); } ret = 0; LABEL_END: //发送STOP信号 // MCF_I2CR &= ~MCF_I2C_I2CR_MSTA; i2c_close(h_i2c); return ret; #endif return 0; } /*------------------------------ 测试函数 ------------------------------------- */ #ifdef _DEBUG_RTC #include "ustimer.h" #include "rt.h" #define RTC_TEST_SIZE 1 int rtc_test(void) { int ret; uint32_t us0,us; uint32_t i,offset,length; unsigned char buffer[CFG_RTC_BUFFER_SIZE]; struct rtc_time_t tm0; rt_printf("rtc_test start...\r\n"); offset = 0; while(offset < CFG_RTC_NVRAM_SIZE) { //写 length = (CFG_RTC_NVRAM_SIZE - offset) > RTC_TEST_SIZE ? RTC_TEST_SIZE : (CFG_RTC_NVRAM_SIZE - offset); for(i=0;i RTC_TEST_SIZE ? RTC_TEST_SIZE : (CFG_RTC_NVRAM_SIZE - offset); memset(buffer,0,RTC_TEST_SIZE); us0 = ustimer_get_origin(); ret = rtc_nvram_read(offset,(unsigned char *)buffer,length); us = ustimer_get_duration(us0); // rt_printf("rtc_nvram_read:(offset=%d,ret=%d,us=%d)\r\n",offset,ret,us); if(ret != 0) { break; } //比较 for(i=0;i