drv_rtc.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371
  1. /**************************************************************************//**
  2. *
  3. * @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0
  6. *
  7. * Change Logs:
  8. * Date Author Notes
  9. * 2021-09-27 Wayne First version
  10. *
  11. ******************************************************************************/
  12. #include <rtconfig.h>
  13. #if defined(BSP_USING_RTC)
  14. #include <rtdevice.h>
  15. #include <sys/time.h>
  16. #include "NuMicro.h"
  17. #include "drv_sys.h"
  18. #include "drv_common.h"
  19. /* Private define ---------------------------------------------------------------*/
  20. /* convert the real year and month value to the format of struct tm. */
  21. #define CONV_TO_TM_YEAR(year) ((year) - 1900)
  22. #define CONV_TO_TM_MON(mon) ((mon) - 1)
  23. /* convert the tm_year and tm_mon from struct tm to the real value. */
  24. #define CONV_FROM_TM_YEAR(tm_year) ((tm_year) + 1900)
  25. #define CONV_FROM_TM_MON(tm_mon) ((tm_mon) + 1)
  26. /* rtc date upper bound reaches the year of 2099. */
  27. #define RTC_TM_UPPER_BOUND \
  28. { .tm_year = CONV_TO_TM_YEAR(2038), \
  29. .tm_mon = CONV_TO_TM_MON(1), \
  30. .tm_mday = 19, \
  31. .tm_hour = 3, \
  32. .tm_min = 14, \
  33. .tm_sec = 07, \
  34. }
  35. /* rtc date lower bound reaches the year of 2000. */
  36. #define RTC_TM_LOWER_BOUND \
  37. { .tm_year = CONV_TO_TM_YEAR(2000), \
  38. .tm_mon = CONV_TO_TM_MON(1), \
  39. .tm_mday = 1, \
  40. .tm_hour = 0, \
  41. .tm_min = 0, \
  42. .tm_sec = 0, \
  43. }
  44. /* Private typedef --------------------------------------------------------------*/
  45. /* Private functions ------------------------------------------------------------*/
  46. static rt_err_t nu_rtc_control(rt_device_t dev, int cmd, void *args);
  47. #if defined (NU_RTC_SUPPORT_IO_RW)
  48. static rt_ssize_t nu_rtc_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size);
  49. static rt_ssize_t nu_rtc_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size);
  50. #endif
  51. static rt_err_t nu_rtc_is_date_valid(const time_t t);
  52. static rt_err_t nu_rtc_init(void);
  53. #if defined(RT_USING_ALARM)
  54. static void nu_rtc_alarm_reset(void);
  55. static void nu_rtc_isr(int vector, void *param);
  56. #endif
  57. /* Public functions -------------------------------------------------------------*/
  58. #if defined (NU_RTC_SUPPORT_MSH_CMD)
  59. extern rt_err_t set_date(rt_uint32_t year, rt_uint32_t month, rt_uint32_t day);
  60. extern rt_err_t set_time(rt_uint32_t hour, rt_uint32_t minute, rt_uint32_t second);
  61. #endif
  62. /* Private variables ------------------------------------------------------------*/
  63. static struct rt_device device_rtc;
  64. static rt_err_t nu_rtc_init(void)
  65. {
  66. /* hw rtc initialise */
  67. CLK_EnableModuleClock(RTC_MODULE);
  68. if (RTC_Open(NULL) < 0)
  69. {
  70. rt_kprintf("*** RTC initialization is failure. Is LXT clock ready?\n");
  71. rt_kprintf("*** Please also press RTC Wakeup button before pressing Reset button.\n");
  72. return -RT_ERROR;
  73. }
  74. RTC_DisableInt(RTC_INTEN_ALMIEN_Msk | RTC_INTEN_TICKIEN_Msk |
  75. RTC_INTEN_TAMP0IEN_Msk | RTC_INTEN_TAMP1IEN_Msk);
  76. #if defined(RT_USING_ALARM)
  77. nu_rtc_alarm_reset();
  78. RTC_EnableInt(RTC_INTEN_ALMIEN_Msk);
  79. rt_hw_interrupt_install(RTC_IRQn, nu_rtc_isr, &device_rtc, "rtc");
  80. rt_hw_interrupt_umask(RTC_IRQn);
  81. #endif
  82. return RT_EOK;
  83. }
  84. #if defined(RT_USING_ALARM)
  85. /* Reset alarm settings to avoid the unwanted values remain in rtc registers. */
  86. static void nu_rtc_alarm_reset(void)
  87. {
  88. S_RTC_TIME_DATA_T alarm;
  89. /* Reset alarm time and calendar. */
  90. alarm.u32Year = RTC_YEAR2000;
  91. alarm.u32Month = 0;
  92. alarm.u32Day = 0;
  93. alarm.u32Hour = 0;
  94. alarm.u32Minute = 0;
  95. alarm.u32Second = 0;
  96. alarm.u32TimeScale = RTC_CLOCK_24;
  97. RTC_SetAlarmDateAndTime(&alarm);
  98. /* Reset alarm time mask and calendar mask. */
  99. RTC_SetAlarmDateMask(0, 0, 0, 0, 0, 0);
  100. RTC_SetAlarmTimeMask(0, 0, 0, 0, 0, 0);
  101. /* Clear alarm flag for safe */
  102. RTC_CLEAR_ALARM_INT_FLAG();
  103. }
  104. #endif
  105. /* rtc device driver initialise. */
  106. int rt_hw_rtc_init(void)
  107. {
  108. rt_err_t ret;
  109. ret = nu_rtc_init();
  110. if (ret != RT_EOK)
  111. {
  112. return -1;
  113. }
  114. /* register rtc device IO operations */
  115. device_rtc.type = RT_Device_Class_RTC;
  116. device_rtc.init = NULL;
  117. device_rtc.open = NULL;
  118. device_rtc.close = NULL;
  119. device_rtc.control = nu_rtc_control;
  120. #if defined (NU_RTC_SUPPORT_IO_RW)
  121. device_rtc.read = nu_rtc_read;
  122. device_rtc.write = nu_rtc_write;
  123. #else
  124. device_rtc.read = NULL;
  125. device_rtc.write = NULL;
  126. #endif
  127. device_rtc.user_data = RT_NULL;
  128. device_rtc.rx_indicate = RT_NULL;
  129. device_rtc.tx_complete = RT_NULL;
  130. ret = rt_device_register(&device_rtc, "rtc", RT_DEVICE_FLAG_RDWR);
  131. return (int)ret;
  132. }
  133. INIT_BOARD_EXPORT(rt_hw_rtc_init);
  134. #if defined (NU_RTC_SUPPORT_IO_RW)
  135. /* Register rt-thread device.read() entry. */
  136. static rt_ssize_t nu_rtc_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
  137. {
  138. (void) pos;
  139. nu_rtc_control(dev, RT_DEVICE_CTRL_RTC_GET_TIME, buffer);
  140. return size;
  141. }
  142. #endif
  143. #if defined (NU_RTC_SUPPORT_IO_RW)
  144. /* Register rt-thread device.write() entry. */
  145. static rt_ssize_t nu_rtc_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
  146. {
  147. (void) pos;
  148. nu_rtc_control(dev, RT_DEVICE_CTRL_RTC_SET_TIME, (void *)buffer);
  149. return size;
  150. }
  151. #endif
  152. static rt_err_t nu_rtc_is_date_valid(const time_t t)
  153. {
  154. static struct tm tm_upper = RTC_TM_UPPER_BOUND;
  155. static struct tm tm_lower = RTC_TM_LOWER_BOUND;
  156. static time_t t_upper, t_lower;
  157. static rt_bool_t initialised = RT_FALSE;
  158. if (!initialised)
  159. {
  160. t_upper = timegm((struct tm *)&tm_upper);
  161. t_lower = timegm((struct tm *)&tm_lower);
  162. initialised = RT_TRUE;
  163. }
  164. /* check the date is supported by rtc. */
  165. if ((t > t_upper) || (t < t_lower))
  166. return -(RT_EINVAL);
  167. return RT_EOK;
  168. }
  169. /* Register rt-thread device.control() entry. */
  170. static rt_err_t nu_rtc_control(rt_device_t dev, int cmd, void *args)
  171. {
  172. struct tm tm_out, tm_in;
  173. time_t *time;
  174. S_RTC_TIME_DATA_T hw_time;
  175. #if defined(RT_USING_ALARM)
  176. struct rt_rtc_wkalarm *wkalarm;
  177. S_RTC_TIME_DATA_T hw_alarm;
  178. #endif
  179. if ((dev == NULL) || (args == NULL))
  180. return -(RT_EINVAL);
  181. switch (cmd)
  182. {
  183. case RT_DEVICE_CTRL_RTC_GET_TIME:
  184. time = (time_t *)args;
  185. RTC_GetDateAndTime(&hw_time);
  186. tm_out.tm_year = CONV_TO_TM_YEAR(hw_time.u32Year);
  187. tm_out.tm_mon = CONV_TO_TM_MON(hw_time.u32Month);
  188. tm_out.tm_mday = hw_time.u32Day;
  189. tm_out.tm_hour = hw_time.u32Hour;
  190. tm_out.tm_min = hw_time.u32Minute;
  191. tm_out.tm_sec = hw_time.u32Second;
  192. *time = timegm(&tm_out);
  193. break;
  194. case RT_DEVICE_CTRL_RTC_SET_TIME:
  195. time = (time_t *) args;
  196. if (nu_rtc_is_date_valid(*time) != RT_EOK)
  197. return -(RT_ERROR);
  198. gmtime_r(time, &tm_in);
  199. hw_time.u32Year = CONV_FROM_TM_YEAR(tm_in.tm_year);
  200. hw_time.u32Month = CONV_FROM_TM_MON(tm_in.tm_mon);
  201. hw_time.u32Day = tm_in.tm_mday;
  202. hw_time.u32Hour = tm_in.tm_hour;
  203. hw_time.u32Minute = tm_in.tm_min;
  204. hw_time.u32Second = tm_in.tm_sec;
  205. hw_time.u32TimeScale = RTC_CLOCK_24;
  206. hw_time.u32AmPm = 0;
  207. RTC_SetDateAndTime(&hw_time);
  208. break;
  209. #if defined(RT_USING_ALARM)
  210. case RT_DEVICE_CTRL_RTC_GET_ALARM:
  211. wkalarm = (struct rt_rtc_wkalarm *) args;
  212. RTC_GetAlarmDateAndTime(&hw_alarm);
  213. wkalarm->tm_hour = hw_alarm.u32Hour;
  214. wkalarm->tm_min = hw_alarm.u32Minute;
  215. wkalarm->tm_sec = hw_alarm.u32Second;
  216. break;
  217. case RT_DEVICE_CTRL_RTC_SET_ALARM:
  218. wkalarm = (struct rt_rtc_wkalarm *) args;
  219. hw_alarm.u32Hour = wkalarm->tm_hour;
  220. hw_alarm.u32Minute = wkalarm->tm_min;
  221. hw_alarm.u32Second = wkalarm->tm_sec;
  222. RTC_SetAlarmDateMask(1, 1, 1, 1, 1, 1);
  223. RTC_SetAlarmDateAndTime(&hw_alarm);
  224. break;
  225. default:
  226. return -(RT_EINVAL);
  227. #endif
  228. }
  229. return RT_EOK;
  230. }
  231. #if defined (NU_RTC_SUPPORT_MSH_CMD)
  232. /* Support "rtc_det_date" command line in msh mode */
  233. static rt_err_t msh_rtc_set_date(int argc, char **argv)
  234. {
  235. rt_uint32_t index, len, arg[3];
  236. rt_memset(arg, 0, sizeof(arg));
  237. len = (argc >= 4) ? 4 : argc;
  238. /* The date information stored in argv is represented by the following order :
  239. argv[0,1,2,3] = [cmd, year, month, day] */
  240. for (index = 0; index < (len - 1); index ++)
  241. {
  242. arg[index] = atol(argv[index + 1]);
  243. }
  244. return set_date(arg[0], arg[1], arg[2]);
  245. }
  246. MSH_CMD_EXPORT_ALIAS(msh_rtc_set_date, rtc_set_date, e.g: rtc_set_date 2020 1 20);
  247. #endif
  248. #if defined (NU_RTC_SUPPORT_MSH_CMD)
  249. /* Support "rtc_det_time" command line in msh mode */
  250. static rt_err_t msh_rtc_set_time(int argc, char **argv)
  251. {
  252. rt_uint32_t index, len, arg[3];
  253. rt_memset(arg, 0, sizeof(arg));
  254. len = (argc >= 4) ? 4 : argc;
  255. /* The time information stored in argv is represented by the following order :
  256. argv[0,1,2,3] = [cmd, hour, minute, second] */
  257. for (index = 0; index < (len - 1); index ++)
  258. {
  259. arg[index] = atol(argv[index + 1]);
  260. }
  261. return set_time(arg[0], arg[1], arg[2]);
  262. }
  263. MSH_CMD_EXPORT_ALIAS(msh_rtc_set_time, rtc_set_time, e.g: rtc_set_time 18 30 00);
  264. #endif
  265. #if defined(RT_USING_ALARM)
  266. /* rtc interrupt entry */
  267. static void nu_rtc_isr(int vector, void *param)
  268. {
  269. rt_interrupt_enter();
  270. if (RTC_GET_TICK_INT_FLAG())
  271. {
  272. RTC_CLEAR_TICK_INT_FLAG();
  273. }
  274. #if defined(RT_USING_ALARM)
  275. if (RTC_GET_ALARM_INT_FLAG())
  276. {
  277. RTC_CLEAR_ALARM_INT_FLAG();
  278. /* Send an alarm event to notify rt-thread alarm service. */
  279. rt_alarm_update(&device_rtc, (rt_uint32_t)NULL);
  280. }
  281. #endif
  282. rt_interrupt_leave();
  283. }
  284. #endif
  285. #endif /* BSP_USING_RTC */