ds3231.c 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. /*
  2. * Copyright (c) 2020 panrui <https://github.com/Prry/rtt-ds3231>
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2020-03-01 panrui the first version
  9. */
  10. #include <rtdevice.h>
  11. #if RT_VER_NUM >= 0x40100
  12. #include <sys/time.h>
  13. #endif /*RT_VER_NUM >= 0x40100*/
  14. #include "ds3231.h"
  15. #ifdef PKG_USING_DS3231
  16. #define DBG_TAG "ds3231"
  17. #define DBG_LVL DBG_LOG
  18. #include <rtdbg.h>
  19. #define DS3231_ARRD 0x68 /* slave address */
  20. #define REG_SEC 0x00
  21. #define REG_MIN 0x01
  22. #define REG_HOUR 0x02
  23. #define REG_DAY 0x03
  24. #define REG_WEEK 0x04
  25. #define REG_MON 0x05
  26. #define REG_YEAR 0x06
  27. #define REG_ALM1_SEC 0x07
  28. #define REG_ALM1_MIN 0x08
  29. #define REG_ALM1_HOUR 0x09
  30. #define REG_ALM1_DAY_DATE 0x0A
  31. #define REG_ALM2_MIN 0x0B
  32. #define REG_ALM2_HOUR 0x0C
  33. #define REG_ALM2_DAY_DATE 0x0D
  34. #define REG_CONTROL 0x0E
  35. #define REG_STATUS 0x0F
  36. #define REG_AGING_OFFSET 0x10
  37. #define REG_TEMP_MSB 0x11
  38. #define REG_TEMP_LSB 0x12
  39. #define DS3231_I2C_BUS "i2c1" /* i2c linked */
  40. #define DS3231_DEVICE_NAME "rtc" /* register device name */
  41. static struct rt_device ds3231_dev; /* ds3231 device */
  42. static unsigned char bcd_to_hex(unsigned char data)
  43. {
  44. unsigned char temp;
  45. temp = ((data>>4)*10 + (data&0x0f));
  46. return temp;
  47. }
  48. static unsigned char hex_to_bcd(unsigned char data)
  49. {
  50. unsigned char temp;
  51. temp = (((data/10)<<4) + (data%10));
  52. return temp;
  53. }
  54. static rt_err_t ds3231_read_reg(rt_device_t dev, rt_uint8_t reg,rt_uint8_t *data,rt_uint8_t data_size)
  55. {
  56. struct rt_i2c_msg msg[2];
  57. struct rt_i2c_bus_device *i2c_bus = RT_NULL;
  58. RT_ASSERT(dev != RT_NULL);
  59. i2c_bus = (struct rt_i2c_bus_device*)dev->user_data;
  60. msg[0].addr = DS3231_ARRD;
  61. msg[0].flags = RT_I2C_WR;
  62. msg[0].len = 1;
  63. msg[0].buf = &reg;
  64. msg[1].addr = DS3231_ARRD;
  65. msg[1].flags = RT_I2C_RD;
  66. msg[1].len = data_size;
  67. msg[1].buf = data;
  68. if(rt_i2c_transfer(i2c_bus, msg, 2) == 2)
  69. {
  70. return RT_EOK;
  71. }
  72. else
  73. {
  74. LOG_E("i2c bus read failed!\r\n");
  75. return -RT_ERROR;
  76. }
  77. }
  78. static rt_err_t ds3231_write_reg(rt_device_t dev, rt_uint8_t reg, rt_uint8_t *data, rt_uint8_t data_size)
  79. {
  80. struct rt_i2c_msg msg[2];
  81. struct rt_i2c_bus_device *i2c_bus = RT_NULL;
  82. RT_ASSERT(dev != RT_NULL);
  83. i2c_bus = (struct rt_i2c_bus_device*)dev->user_data;
  84. msg[0].addr = DS3231_ARRD;
  85. msg[0].flags = RT_I2C_WR;
  86. msg[0].len = 1;
  87. msg[0].buf = &reg;
  88. msg[1].addr = DS3231_ARRD;
  89. msg[1].flags = RT_I2C_WR | RT_I2C_NO_START;
  90. msg[1].len = data_size;
  91. msg[1].buf = data;
  92. if(rt_i2c_transfer(i2c_bus, msg, 2) == 2)
  93. {
  94. return RT_EOK;
  95. }
  96. else
  97. {
  98. LOG_E("i2c bus write failed!\r\n");
  99. return -RT_ERROR;
  100. }
  101. }
  102. static rt_err_t rt_ds3231_open(rt_device_t dev, rt_uint16_t flag)
  103. {
  104. if (dev->rx_indicate != RT_NULL)
  105. {
  106. /* open interrupt */
  107. }
  108. return RT_EOK;
  109. }
  110. static rt_size_t rt_ds3231_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
  111. {
  112. return RT_EOK;
  113. }
  114. static rt_err_t rt_ds3231_control(rt_device_t dev, int cmd, void *args)
  115. {
  116. rt_err_t ret = RT_EOK;
  117. time_t *time;
  118. struct tm time_temp;
  119. rt_uint8_t buff[7];
  120. RT_ASSERT(dev != RT_NULL);
  121. rt_memset(&time_temp, 0, sizeof(struct tm));
  122. switch (cmd)
  123. {
  124. /* read time */
  125. case RT_DEVICE_CTRL_RTC_GET_TIME:
  126. time = (time_t *)args;
  127. ret = ds3231_read_reg(dev, REG_SEC,buff,7);
  128. if(ret == RT_EOK)
  129. {
  130. time_temp.tm_year = bcd_to_hex(buff[6]) + 2000 - 1900;
  131. time_temp.tm_mon = bcd_to_hex(buff[5]&0x7f) - 1;
  132. time_temp.tm_mday = bcd_to_hex(buff[4]);
  133. time_temp.tm_hour = bcd_to_hex(buff[2]);
  134. time_temp.tm_min = bcd_to_hex(buff[1]);
  135. time_temp.tm_sec = bcd_to_hex(buff[0]);
  136. *time = mktime(&time_temp);
  137. }
  138. break;
  139. /* set time */
  140. case RT_DEVICE_CTRL_RTC_SET_TIME:
  141. {
  142. struct tm *time_new;
  143. time = (time_t *)args;
  144. time_new = localtime(time);
  145. buff[6] = hex_to_bcd(time_new->tm_year + 1900 - 2000);
  146. buff[5] = hex_to_bcd(time_new->tm_mon + 1);
  147. buff[4] = hex_to_bcd(time_new->tm_mday);
  148. buff[3] = hex_to_bcd(time_new->tm_wday+1);
  149. buff[2] = hex_to_bcd(time_new->tm_hour);
  150. buff[1] = hex_to_bcd(time_new->tm_min);
  151. buff[0] = hex_to_bcd(time_new->tm_sec);
  152. ret = ds3231_write_reg(dev, REG_SEC, buff, 7);
  153. }
  154. break;
  155. #ifdef RT_USING_ALARM
  156. /* get alarm time */
  157. case RT_DEVICE_CTRL_RTC_GET_ALARM:
  158. {
  159. struct rt_rtc_wkalarm *alm_time;
  160. ret = ds3231_read_reg(dev, REG_ALM1_SEC, buff, 4);
  161. if(ret == RT_EOK)
  162. {
  163. alm_time = (struct rt_rtc_wkalarm *)args;
  164. alm_time->tm_hour = bcd_to_hex(buff[2]);
  165. alm_time->tm_min = bcd_to_hex(buff[1]);
  166. alm_time->tm_sec = bcd_to_hex(buff[0]);
  167. }
  168. }
  169. break;
  170. /* set alarm time */
  171. case RT_DEVICE_CTRL_RTC_SET_ALARM:
  172. {
  173. struct rt_rtc_wkalarm *alm_time;
  174. alm_time = (struct rt_rtc_wkalarm *)args;
  175. buff[3] = 0x80; /* enable, alarm when hours, minutes, and seconds match */
  176. buff[2] = hex_to_bcd(alm_time->tm_hour);
  177. buff[1] = hex_to_bcd(alm_time->tm_min);
  178. buff[0] = hex_to_bcd(alm_time->tm_sec);
  179. ret = ds3231_write_reg(dev, REG_ALM1_SEC, buff, 4);
  180. }
  181. break;
  182. #endif
  183. default:
  184. break;
  185. }
  186. return ret;
  187. }
  188. float ds3231_get_temperature(void)
  189. {
  190. rt_int8_t buff[2];
  191. float temp = 0.0f;
  192. ds3231_read_reg(&ds3231_dev, REG_TEMP_MSB, (rt_uint8_t*)buff, 2);
  193. if(buff[0]&0x80)
  194. {/* negative temperature */
  195. temp = buff[0];
  196. temp -= (buff[1]>>6)*0.25; /* 0.25C resolution */
  197. }
  198. else
  199. {/* positive temperature */
  200. temp = buff[0];
  201. temp += ((buff[1]>>6)&0x03)*0.25;
  202. }
  203. return temp;
  204. }
  205. int rt_hw_ds3231_init(void)
  206. {
  207. struct rt_i2c_bus_device *i2c_device;
  208. uint8_t data;
  209. i2c_device = rt_i2c_bus_device_find(DS3231_I2C_BUS);
  210. if (i2c_device == RT_NULL)
  211. {
  212. LOG_E("i2c bus device %s not found!\r\n", DS3231_I2C_BUS);
  213. return -RT_ERROR;
  214. }
  215. /* register rtc device */
  216. ds3231_dev.type = RT_Device_Class_RTC;
  217. ds3231_dev.init = RT_NULL;
  218. ds3231_dev.open = rt_ds3231_open;
  219. ds3231_dev.close = RT_NULL;
  220. ds3231_dev.read = rt_ds3231_read;
  221. ds3231_dev.write = RT_NULL;
  222. ds3231_dev.control = rt_ds3231_control;
  223. ds3231_dev.user_data = (void*)i2c_device; /* save i2cbus */;
  224. rt_device_register(&ds3231_dev, DS3231_DEVICE_NAME, RT_DEVICE_FLAG_RDWR);
  225. /* init ds3231 */
  226. data = 0x04; /* close clock out */
  227. ds3231_write_reg(&ds3231_dev, REG_CONTROL, &data, 1);
  228. LOG_D("the rtc of ds3231 init succeed!");
  229. return 0;
  230. }
  231. INIT_DEVICE_EXPORT(rt_hw_ds3231_init);
  232. #ifdef RT_USING_FINSH
  233. #include <finsh.h>
  234. void list_ds31_temp(void)
  235. {
  236. float temp = 0.0f;
  237. temp = ds3231_get_temperature();
  238. rt_kprintf("ds3231 temperature: [%d.%dC] \n", (int)temp, (int)(temp * 10) % 10);
  239. }
  240. FINSH_FUNCTION_EXPORT(list_ds31_temp, list ds3231 temperature.)
  241. #endif /* RT_USING_FINSH */
  242. #if defined(RT_USING_FINSH) && defined(FINSH_USING_MSH)
  243. MSH_CMD_EXPORT(list_ds31_temp, list ds3231 temperature.);
  244. #endif /* RT_USING_FINSH & FINSH_USING_MSH */
  245. #endif /* PKG_USING_DS3231 */