rtc_rx8025.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700
  1. /******************************************************************************
  2. 版权所有:
  3. 文件名称: rtc_ds1338.c
  4. 文件版本: 01.01
  5. 创建作者: sunxi
  6. 创建日期: 2008-07-09
  7. 功能说明: DS1338 实时时钟驱动程序。
  8. 其它说明: DS1338中的年从2000年开始。
  9. 修改记录:
  10. */
  11. /*------------------------------- 头文件 --------------------------------------
  12. */
  13. #include "bspconfig.h"
  14. #include "i2c.h"
  15. #include "my_rtc.h"
  16. #include "watchdog.h"
  17. // #include "rt_ints.h"
  18. /*------------------------------- 宏定义 --------------------------------------
  19. */
  20. #if CFG_BSP_DEBUG
  21. #define _DEBUG_RTC
  22. #endif
  23. #define RTC_I2C_ID 0X64
  24. #define RTC_ADDR_EXT 0X0D
  25. #define RTC_ADDR_FLAG 0X0E
  26. #define RTC_ADDR_CONTROL 0X0F
  27. #define RTC_FLAG_VLF 0X02
  28. // rtc rx8025内部结构定义
  29. typedef struct
  30. {
  31. u8 second; // 0~59
  32. u8 minute; // 0~59
  33. u8 hour; // 0~23
  34. u8 week; // 每个星期用一个bit表示
  35. u8 date; // 1~31
  36. u8 month; // 1~12 *与tm结构范围不同
  37. u8 year; // 0~99 *与tm结构范围不同
  38. } rtc_t;
  39. typedef struct
  40. {
  41. u8 ext_reg;
  42. u8 flg_reg;
  43. u8 ctl_reg; //
  44. } rtc_ctrl_t;
  45. // 此结构仅供参考,不可使用
  46. typedef struct
  47. {
  48. rtc_t rtc;
  49. u8 ram; // 可以任意读写
  50. u8 min_alm; //
  51. u8 hour_alm;
  52. u8 day_alm;
  53. u8 tim_cnt0;
  54. u8 tim_cnt1;
  55. rtc_ctrl_t rtc_ctrl;
  56. } rtc_all_t;
  57. /*------------------------------ 全局变量 -------------------------------------
  58. */
  59. struct rtc_write
  60. {
  61. bool write_flg; // 执行写入标志
  62. int write_5ms; // 离实际写入时间还差多少个5ms
  63. struct rtc_time_t write_data; // 需要写入RTC芯片的时间
  64. };
  65. struct rtc_write rtc_write;
  66. /*------------------------------ 函数声明 -------------------------------------
  67. */
  68. int _rtc_read(uint32_t offset, unsigned char *buffer, uint32_t length);
  69. int _rtc_write(uint32_t offset, unsigned char *buffer, uint32_t length);
  70. /*------------------------------ 外部函数 -------------------------------------
  71. */
  72. /******************************************************************************
  73. 函数名称: rtc_init
  74. 函数版本: 01.01
  75. 创建作者: sunxi
  76. 创建日期: 2008-08-06
  77. 函数说明: rtc初始化。
  78. 参数说明: 无
  79. 返回值: 成功返回0.
  80. 修改记录:
  81. */
  82. int rtc_init(void)
  83. {
  84. return 0;
  85. }
  86. /******************************************************************************
  87. 函数名称: rtc_time_read
  88. 函数版本: 01.01
  89. 创建作者: sunxi
  90. 创建日期: 2008-08-06
  91. 函数说明: 从时钟芯片中读出时间。
  92. 参数说明:
  93. p_tm(out): 读出的时间存放在这个指针所指的结构中。
  94. 返回值:
  95. 0: 成功返回。
  96. 1: 成功返回,但是由于时钟芯片振荡器曾经停止过,所以时间可能不准。
  97. <0:读取失败。
  98. 修改记录:
  99. */
  100. int rtc_time_read(struct rtc_time_t *p_tm)
  101. {
  102. int ret;
  103. rtc_t rtc;
  104. u8 flag = 0;
  105. // 检查参数
  106. if (p_tm == 0)
  107. {
  108. return -1;
  109. }
  110. memset(&rtc, 0x00, sizeof(rtc_t));
  111. // 读出数据
  112. ret = _rtc_read(0, (unsigned char *)&rtc, sizeof(rtc));
  113. if (ret != 0)
  114. {
  115. return -2;
  116. }
  117. ret = _rtc_read(RTC_ADDR_FLAG, &flag, 1);
  118. if (ret != 0)
  119. {
  120. return -3;
  121. }
  122. // 转换格式
  123. // 清除不需要的标志
  124. rtc.second &= ~0x80;
  125. rtc.hour &= ~0xc0;
  126. // BCD转化为二进制
  127. p_tm->ms = (unsigned short)((rtc.second >> 4) * 10 + (rtc.second & 0xf)); // 秒
  128. p_tm->min = (unsigned char)((rtc.minute >> 4) * 10 + (rtc.minute & 0xf)); // 分
  129. p_tm->hour = (unsigned char)((rtc.hour >> 4) * 10 + (rtc.hour & 0xf)); // 时
  130. p_tm->day = (unsigned char)((rtc.date >> 4) * 10 + (rtc.date & 0xf)); // 日
  131. p_tm->month = (unsigned char)((rtc.month >> 4) * 10 + (rtc.month & 0xf)); // 月
  132. p_tm->year = (unsigned char)((rtc.year >> 4) * 10 + (rtc.year & 0xf)); // 年
  133. // s->ms
  134. p_tm->ms *= 1000;
  135. // 如果时钟振荡器曾经停止过,时间有可能不准,返回1。
  136. if (flag & RTC_FLAG_VLF)
  137. {
  138. return 1;
  139. }
  140. return 0;
  141. }
  142. /******************************************************************************
  143. 函数名称: rtc_time_write
  144. 函数版本: 01.01
  145. 创建作者: sunxi
  146. 创建日期: 2008-08-06
  147. 函数说明: 将时间写入时钟芯片。
  148. 参数说明:
  149. p_tm(in): 要写入的时间存放在这个指针所指的结构中。
  150. 返回值:
  151. 0: 成功返回。
  152. <0:写入失败。
  153. 修改记录:
  154. */
  155. extern void sys_time_change(struct rtc_time_t *p_ct);
  156. int rtc_time_write(struct rtc_time_t *p_tm)
  157. {
  158. uint32_t flags;
  159. int seccond, ms5;
  160. rtc_t rtc;
  161. // rt_printf("rtc_time_write.\r\n");
  162. // 检查参数
  163. if (p_tm == 0)
  164. {
  165. return -11;
  166. }
  167. if (p_tm->ms > 59999)
  168. {
  169. return -12;
  170. }
  171. if (p_tm->min > 59)
  172. {
  173. return -13;
  174. }
  175. if (p_tm->hour > 23)
  176. {
  177. return -14;
  178. }
  179. if (p_tm->day < 1 || p_tm->day > 31)
  180. {
  181. return -15;
  182. }
  183. if (p_tm->month < 1 || p_tm->month > 12)
  184. {
  185. return -16;
  186. }
  187. if (p_tm->year > 99)
  188. {
  189. return -17;
  190. }
  191. // ms->s,使用下一秒作为要写入的秒值
  192. seccond = p_tm->ms / 1000 + 1;
  193. ms5 = (seccond * 1000 - p_tm->ms) / 5;
  194. if (ms5 < 1)
  195. {
  196. ms5 = 1;
  197. }
  198. p_tm->ms = seccond * 1000; // 在下一秒整秒时写入rtc
  199. if (seccond >= 60)
  200. {
  201. seccond -= 60;
  202. p_tm->ms = 0; // 加1秒后刚好一分钟,分钟加1,ms清0
  203. sys_time_change(p_tm);
  204. }
  205. #if (0)
  206. // 二进制转换为BCD
  207. rtc.second = (unsigned char)(((seccond / 10) << 4) | (seccond % 10));
  208. rtc.minute = (unsigned char)(((p_tm->min / 10) << 4) | (p_tm->min % 10));
  209. rtc.hour = (unsigned char)(((p_tm->hour / 10) << 4) | (p_tm->hour % 10));
  210. rtc.date = (unsigned char)(((p_tm->day / 10) << 4) | (p_tm->day % 10));
  211. rtc.month = (unsigned char)(((p_tm->month / 10) << 4) | (p_tm->month % 10));
  212. rtc.year = (unsigned char)(((p_tm->year / 10) << 4) | (p_tm->year % 10));
  213. // 星期不使用直接赋值1
  214. rtc.week = 1;
  215. #endif
  216. // 写入数据
  217. rt_irq_save(flags);
  218. rtc_write.write_data = *p_tm;
  219. rtc_write.write_5ms = ms5;
  220. rt_irq_restore(flags);
  221. return 0;
  222. }
  223. void rtc_time_write_5ms(void)
  224. {
  225. int ret = 0;
  226. rtc_ctrl_t rtc_ctrl;
  227. if (rtc_write.write_5ms == 0)
  228. {
  229. return;
  230. }
  231. if (rtc_write.write_5ms == 1)
  232. {
  233. #if (0)
  234. // 写入时间数据
  235. // ret = _rtc_write(0,(unsigned char *)&g_rtc_write_data,sizeof(g_rtc_write_data)); //jack.liu 20200921 读写RTC失能
  236. if (ret)
  237. {
  238. rt_printf("rtc_write_5ms0:ret=%d)\r\n", ret);
  239. }
  240. // 写入控制数据
  241. rtc_ctrl.ext_reg = 0x00;
  242. rtc_ctrl.flg_reg = 0x00;
  243. rtc_ctrl.ctl_reg = 0x40; // 默认2.0s温度补偿
  244. // ret = _rtc_write(RTC_ADDR_EXT,(unsigned char *)&rtc_ctrl,sizeof(rtc_ctrl)); //jack.liu 20200921 读写RTC失能
  245. if (ret)
  246. {
  247. rt_printf("rtc_write_5ms1:ret=%d)\r\n", ret);
  248. }
  249. #endif
  250. // 置此标志在大循环中写入RTC,不在实时线程中写,因为调用非实时接口会造成模式切换;
  251. // 会有10ms左右的误差
  252. rtc_write.write_flg = true;
  253. }
  254. rtc_write.write_5ms--;
  255. }
  256. void check_rtc_write(void)
  257. {
  258. char pchDT[30];
  259. if (rtc_write.write_flg)
  260. {
  261. rtc_write.write_flg = false;
  262. sprintf(pchDT, "date -s '%04d-%02d-%02d %02d:%02d:%02d'",
  263. rtc_write.write_data.year + 2000, rtc_write.write_data.month, rtc_write.write_data.day, rtc_write.write_data.hour, rtc_write.write_data.min, rtc_write.write_data.ms / 1000);
  264. system(pchDT);
  265. system("hwclock -w");
  266. system("sync");
  267. rt_printf("设置系统时间: %s\n", pchDT);
  268. }
  269. }
  270. /******************************************************************************
  271. 函数名称: rtc_nvram_read
  272. 函数版本: 01.01
  273. 创建作者: sunxi
  274. 创建日期: 2008-08-07
  275. 函数说明: 从时钟芯片的NVRAM中读出数据。
  276. 参数说明:
  277. offset(in):需要读的数据在NVRAM中的偏移量,和length之和必须小于CFG_RTC_NVRAM_SIZE.
  278. buffer(out):读出数据的buffer。
  279. length(in): 需要读出数据的长度,和offset之和必须小于CFG_RTC_NVRAM_SIZE。
  280. 返回值: 成功返回0.
  281. 修改记录:
  282. */
  283. int rtc_nvram_read(uint32_t offset, unsigned char *buffer, uint32_t length)
  284. {
  285. // 检查参数
  286. if (buffer == 0 || (offset + length) > CFG_RTC_NVRAM_SIZE)
  287. {
  288. return -1;
  289. }
  290. if (length == 0)
  291. {
  292. return 0;
  293. }
  294. return _rtc_read(offset + 7, buffer, length);
  295. }
  296. /******************************************************************************
  297. 函数名称: rtc_nvram_write
  298. 函数版本: 01.01
  299. 创建作者: sunxi
  300. 创建日期: 2008-08-07
  301. 函数说明: 将数据写入时钟芯片的NVRAM中。
  302. 参数说明:
  303. offset(in):需要写入的数据在NVRAM中的偏移量,和length之和必须小于CFG_RTC_NVRAM_SIZE.
  304. buffer(in):写入数据的buffer。
  305. length(in): 需要写入数据的长度,和offset之和必须小于CFG_RTC_NVRAM_SIZE。
  306. 返回值: 成功返回0.
  307. 修改记录:
  308. */
  309. int rtc_nvram_write(uint32_t offset, unsigned char *buffer, uint32_t length)
  310. {
  311. // 检查参数
  312. if (buffer == 0 || (offset + length) > CFG_RTC_NVRAM_SIZE)
  313. {
  314. return -1;
  315. }
  316. if (length == 0)
  317. {
  318. return 0;
  319. }
  320. return _rtc_write(offset + 7, buffer, length);
  321. }
  322. /*------------------------------ 内部函数 -------------------------------------
  323. */
  324. /******************************************************************************
  325. 函数名称: _rtc_read
  326. 函数版本: 01.01
  327. 创建作者: sunxi
  328. 创建日期: 2008-08-07
  329. 函数说明: 从时钟芯片中读出数据。
  330. 参数说明:
  331. offset(in):需要读的数据在时钟芯片的偏移量.
  332. buffer(out):读出数据的buffer。
  333. length(in): 需要读出数据的长度。
  334. 返回值: 成功返回0.
  335. 修改记录:
  336. */
  337. int _rtc_read(uint32_t offset, unsigned char *buffer, uint32_t length)
  338. {
  339. #if 0
  340. unsigned char c;
  341. int h_i2c,ret;
  342. h_i2c = i2c_open(I2C_ID_RTC);
  343. if(h_i2c < 0)
  344. {
  345. return -1;
  346. }
  347. ret = -2;
  348. //等待总线释放
  349. I2C_WAIT_BUS_IDLE();
  350. //发送模式
  351. MCF_I2CR |= MCF_I2C_I2CR_MTX;
  352. //发送START信号
  353. MCF_I2CR |= MCF_I2C_I2CR_MSTA;
  354. //发送控制字节
  355. MCF_I2DR = RTC_I2C_ID;
  356. I2C_WAIT_COMPLETION();
  357. I2C_CHECK_ACK();
  358. //发送地址
  359. MCF_I2DR = (unsigned char)(offset);
  360. I2C_WAIT_COMPLETION();
  361. I2C_CHECK_ACK();
  362. //发送重开始信号,方向改为读
  363. MCF_I2CR |= MCF_I2C_I2CR_RSTA;
  364. MCF_I2DR = RTC_I2C_ID | 0x01;
  365. I2C_WAIT_COMPLETION();
  366. I2C_CHECK_ACK();
  367. //接收模式
  368. MCF_I2CR &= ~MCF_I2C_I2CR_MTX;
  369. //接收数据,最后一个字节不发ACK.
  370. if(length == 1)
  371. {
  372. MCF_I2CR |= MCF_I2C_I2CR_TXAK; //不发ACK
  373. c = MCF_I2DR; //空读,启动下一个字节的读
  374. I2C_WAIT_COMPLETION();
  375. *buffer++ = MCF_I2DR;
  376. I2C_WAIT_COMPLETION();
  377. }
  378. else
  379. {
  380. //循环接收length个字节。
  381. MCF_I2CR &= ~MCF_I2C_I2CR_TXAK; //发送ACK
  382. c = MCF_I2DR; //空读,启动下一个字节的读
  383. I2C_WAIT_COMPLETION();
  384. while(length--)
  385. {
  386. if(length == 1)
  387. {
  388. MCF_I2CR |= MCF_I2C_I2CR_TXAK; //不发ACK
  389. }
  390. *buffer++ = MCF_I2DR; //读数据,并启动下一个字节的读。
  391. I2C_WAIT_COMPLETION();
  392. }
  393. }
  394. ret = 0;
  395. LABEL_END:
  396. //发送STOP信号
  397. MCF_I2CR &= ~MCF_I2C_I2CR_MSTA;
  398. i2c_close(h_i2c);
  399. return ret;
  400. #endif
  401. return 0;
  402. }
  403. /******************************************************************************
  404. 函数名称: _rtc_write
  405. 函数版本: 01.01
  406. 创建作者: sunxi
  407. 创建日期: 2008-08-07
  408. 函数说明: 将数据写入时钟芯片中。
  409. 参数说明:
  410. offset(in):需要写入的数据在时钟芯片中的偏移量.
  411. buffer(in):写入数据的buffer。
  412. length(in): 需要写入数据的长度。
  413. 返回值: 成功返回0.
  414. 修改记录:
  415. */
  416. int _rtc_write(uint32_t offset, unsigned char *buffer, uint32_t length)
  417. {
  418. #if 0
  419. int h_i2c,ret;
  420. h_i2c = i2c_open(I2C_ID_RTC);
  421. if(h_i2c < 0)
  422. {
  423. return -1;
  424. }
  425. ret = -2;
  426. //等待总线释放
  427. I2C_WAIT_BUS_IDLE();
  428. //发送模式
  429. // MCF_I2CR |= MCF_I2C_I2CR_MTX;
  430. //发送START信号
  431. // MCF_I2CR |= MCF_I2C_I2CR_MSTA;
  432. //发送控制字节
  433. MCF_I2DR = RTC_I2C_ID;
  434. I2C_WAIT_COMPLETION();
  435. I2C_CHECK_ACK();
  436. //发送地址
  437. MCF_I2DR = (unsigned char)(offset);
  438. I2C_WAIT_COMPLETION();
  439. I2C_CHECK_ACK();
  440. //发送数据
  441. while(length--)
  442. {
  443. MCF_I2DR = *buffer++;
  444. I2C_WAIT_COMPLETION();
  445. I2C_CHECK_ACK();
  446. }
  447. ret = 0;
  448. LABEL_END:
  449. //发送STOP信号
  450. // MCF_I2CR &= ~MCF_I2C_I2CR_MSTA;
  451. i2c_close(h_i2c);
  452. return ret;
  453. #endif
  454. return 0;
  455. }
  456. /*------------------------------ 测试函数 -------------------------------------
  457. */
  458. #ifdef _DEBUG_RTC
  459. #include "ustimer.h"
  460. #include "rt.h"
  461. #define RTC_TEST_SIZE 1
  462. int rtc_test(void)
  463. {
  464. int ret;
  465. uint32_t us0, us;
  466. uint32_t i, offset, length;
  467. unsigned char buffer[CFG_RTC_BUFFER_SIZE];
  468. struct rtc_time_t tm0;
  469. rt_printf("rtc_test start...\r\n");
  470. offset = 0;
  471. while (offset < CFG_RTC_NVRAM_SIZE)
  472. {
  473. // 写
  474. length = (CFG_RTC_NVRAM_SIZE - offset) > RTC_TEST_SIZE ? RTC_TEST_SIZE : (CFG_RTC_NVRAM_SIZE - offset);
  475. for (i = 0; i < length; i++)
  476. {
  477. buffer[i] = (unsigned char)(offset + i + 0x37);
  478. }
  479. us0 = ustimer_get_origin();
  480. ret = rtc_nvram_write(offset, (unsigned char *)buffer, length);
  481. us = ustimer_get_duration(us0);
  482. // rt_printf("rtc_nvram_write:(offset=%d,ret=%d,us=%d)\r\n",offset,ret,us);
  483. if (ret != 0)
  484. {
  485. break;
  486. }
  487. offset += length;
  488. }
  489. offset = 0;
  490. while (offset < CFG_RTC_NVRAM_SIZE)
  491. {
  492. // 读
  493. length = (CFG_RTC_NVRAM_SIZE - offset) > RTC_TEST_SIZE ? RTC_TEST_SIZE : (CFG_RTC_NVRAM_SIZE - offset);
  494. memset(buffer, 0, RTC_TEST_SIZE);
  495. us0 = ustimer_get_origin();
  496. ret = rtc_nvram_read(offset, (unsigned char *)buffer, length);
  497. us = ustimer_get_duration(us0);
  498. // rt_printf("rtc_nvram_read:(offset=%d,ret=%d,us=%d)\r\n",offset,ret,us);
  499. if (ret != 0)
  500. {
  501. break;
  502. }
  503. // 比较
  504. for (i = 0; i < length; i++)
  505. {
  506. if (buffer[i] != (unsigned char)(offset + i + 0x37))
  507. {
  508. break;
  509. }
  510. }
  511. if (i != length)
  512. {
  513. rt_printf("compare error(offset=%lu,i=%lu)!\r\n", offset, i);
  514. break;
  515. }
  516. offset += length;
  517. }
  518. if (offset == CFG_RTC_NVRAM_SIZE)
  519. {
  520. rt_printf("rtc_nvram ok!\r\n\n");
  521. }
  522. else
  523. {
  524. rt_printf("rtc_nvram fail!\r\n\n");
  525. }
  526. // 开始测试时间
  527. ret = rtc_time_read(&tm0);
  528. if (ret == 1)
  529. {
  530. rt_printf("rtc was stoped!\r\n");
  531. }
  532. else if (ret == 0)
  533. {
  534. rt_printf("rtc is running!\r\n");
  535. }
  536. else
  537. {
  538. rt_printf("rtc_time_read test fail!");
  539. }
  540. tm0.ms = 8000;
  541. tm0.min = 28;
  542. tm0.hour = 14;
  543. tm0.day = 19;
  544. tm0.month = 10;
  545. tm0.year = 2010 - 2000;
  546. #if 0
  547. ret = rtc_time_write(&tm0);
  548. if(ret == 0)
  549. {
  550. rt_printf("rtc_time_write ok!\r\n\n");
  551. }
  552. else
  553. {
  554. rt_printf("rtc_time_write fail(ret=%d)!\r\n\n",ret);
  555. }
  556. #endif
  557. us0 = ustimer_get_origin();
  558. while (1)
  559. {
  560. ret = rtc_time_read(&tm0);
  561. if (ret == 0 || ret == 1)
  562. {
  563. rt_printf("date(ret=%d): %04d-%02d-%02d time: %02d:%02d:%05d!\r\n",
  564. ret,
  565. tm0.year + 2000,
  566. tm0.month,
  567. tm0.day,
  568. tm0.hour,
  569. tm0.min,
  570. tm0.ms);
  571. }
  572. else
  573. {
  574. rt_printf("rtc_time_read fail(ret=%d)!\r\n\n", ret);
  575. }
  576. watchdog_feed_mainloop();
  577. // 精确间隔1S循环。
  578. ustimer_delay_origin(us0, USTIMER_SEC);
  579. us0 += USTIMER_SEC;
  580. }
  581. return 0;
  582. }
  583. #endif