drv_rtc.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386
  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-04-12 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. /* Private define ---------------------------------------------------------------*/
  19. /* convert the real year and month value to the format of struct tm. */
  20. #define CONV_TO_TM_YEAR(year) ((year) - 1900)
  21. #define CONV_TO_TM_MON(mon) ((mon) - 1)
  22. /* convert the tm_year and tm_mon from struct tm to the real value. */
  23. #define CONV_FROM_TM_YEAR(tm_year) ((tm_year) + 1900)
  24. #define CONV_FROM_TM_MON(tm_mon) ((tm_mon) + 1)
  25. /* rtc date upper bound reaches the year of 2099. */
  26. #define RTC_TM_UPPER_BOUND \
  27. { .tm_year = CONV_TO_TM_YEAR(2099), \
  28. .tm_mon = CONV_TO_TM_MON(12), \
  29. .tm_mday = 31, \
  30. .tm_hour = 23, \
  31. .tm_min = 59, \
  32. .tm_sec = 59, \
  33. }
  34. /* rtc date lower bound reaches the year of 2000. */
  35. #define RTC_TM_LOWER_BOUND \
  36. { .tm_year = CONV_TO_TM_YEAR(2000), \
  37. .tm_mon = CONV_TO_TM_MON(1), \
  38. .tm_mday = 1, \
  39. .tm_hour = 0, \
  40. .tm_min = 0, \
  41. .tm_sec = 0, \
  42. }
  43. /* Private typedef --------------------------------------------------------------*/
  44. /* Private functions ------------------------------------------------------------*/
  45. static rt_err_t nu_rtc_control(rt_device_t dev, int cmd, void *args);
  46. #if defined (NU_RTC_SUPPORT_IO_RW)
  47. static rt_size_t nu_rtc_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size);
  48. static rt_size_t nu_rtc_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size);
  49. #endif
  50. static rt_err_t nu_rtc_is_date_valid(const time_t *const t);
  51. static void nu_rtc_init(void);
  52. #if defined(RT_USING_ALARM)
  53. static void nu_rtc_alarm_reset(void);
  54. static void nu_rtc_isr(int vector, void *param);
  55. #endif
  56. /* Public functions -------------------------------------------------------------*/
  57. #if defined (NU_RTC_SUPPORT_MSH_CMD)
  58. extern rt_err_t set_date(rt_uint32_t year, rt_uint32_t month, rt_uint32_t day);
  59. extern rt_err_t set_time(rt_uint32_t hour, rt_uint32_t minute, rt_uint32_t second);
  60. #endif
  61. /* Private variables ------------------------------------------------------------*/
  62. static struct rt_device device_rtc;
  63. static void nu_rtc_init(void)
  64. {
  65. S_RTC_TIME_DATA_T sInitTime = {0};
  66. nu_sys_ipclk_enable(RTCCKEN);
  67. /* Time Setting */
  68. sInitTime.u32Year = 2015;
  69. sInitTime.u32cMonth = 5;
  70. sInitTime.u32cDay = 25;
  71. sInitTime.u32cHour = 13;
  72. sInitTime.u32cMinute = 30;
  73. sInitTime.u32cSecond = 0;
  74. sInitTime.u32cDayOfWeek = RTC_TUESDAY;
  75. sInitTime.u8cClockDisplay = RTC_CLOCK_24;
  76. /* hw rtc initialise */
  77. if (RTC_Init() != E_RTC_SUCCESS)
  78. rt_kprintf("[%s] failure!!\n", __func__);
  79. /* Initialization the RTC timer */
  80. if (RTC_Open(&sInitTime) != E_RTC_SUCCESS)
  81. rt_kprintf("Open Fail!!\n");
  82. /* Do RTC Calibration */
  83. RTC_Ioctl(0, RTC_IOC_SET_FREQUENCY, 0, 0);
  84. RTC_DisableInt(RTC_TICK_INT);
  85. RTC_DisableInt(RTC_ALARM_INT);
  86. #if defined(RT_USING_ALARM)
  87. nu_rtc_alarm_reset();
  88. rt_hw_interrupt_install(IRQ_RTC, nu_rtc_isr, &device_rtc, "rtc");
  89. rt_hw_interrupt_umask(IRQ_RTC);
  90. #endif
  91. }
  92. #if defined(RT_USING_ALARM)
  93. /* Reset alarm settings to avoid the unwanted values remain in rtc registers. */
  94. static void nu_rtc_alarm_reset(void)
  95. {
  96. S_RTC_TIME_DATA_T alarm = {0};
  97. /* Reset alarm time and calendar. */
  98. alarm.u32Year = RTC_YEAR2000;
  99. alarm.u32cMonth = 1;
  100. alarm.u32cDay = 1;
  101. alarm.u8cClockDisplay = RTC_CLOCK_24;
  102. RTC_Write(RTC_ALARM_TIME, &alarm);
  103. /* Clear alarm flag for safe */
  104. RTC_CLEAR_ALARM_INT_FLAG();
  105. }
  106. #endif
  107. /* rtc device driver initialise. */
  108. int rt_hw_rtc_init(void)
  109. {
  110. rt_err_t ret;
  111. nu_rtc_init();
  112. /* register rtc device IO operations */
  113. device_rtc.type = RT_Device_Class_RTC;
  114. device_rtc.init = NULL;
  115. device_rtc.open = NULL;
  116. device_rtc.close = NULL;
  117. device_rtc.control = nu_rtc_control;
  118. #if defined (NU_RTC_SUPPORT_IO_RW)
  119. device_rtc.read = nu_rtc_read;
  120. device_rtc.write = nu_rtc_write;
  121. #else
  122. device_rtc.read = NULL;
  123. device_rtc.write = NULL;
  124. #endif
  125. device_rtc.user_data = RT_NULL;
  126. device_rtc.rx_indicate = RT_NULL;
  127. device_rtc.tx_complete = RT_NULL;
  128. ret = rt_device_register(&device_rtc, "rtc", RT_DEVICE_FLAG_RDWR);
  129. return (int)ret;
  130. }
  131. INIT_BOARD_EXPORT(rt_hw_rtc_init);
  132. #if defined (NU_RTC_SUPPORT_IO_RW)
  133. /* Register rt-thread device.read() entry. */
  134. static rt_size_t nu_rtc_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
  135. {
  136. (void) pos;
  137. nu_rtc_control(dev, RT_DEVICE_CTRL_RTC_GET_TIME, buffer);
  138. return size;
  139. }
  140. #endif
  141. #if defined (NU_RTC_SUPPORT_IO_RW)
  142. /* Register rt-thread device.write() entry. */
  143. static rt_size_t nu_rtc_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
  144. {
  145. (void) pos;
  146. nu_rtc_control(dev, RT_DEVICE_CTRL_RTC_SET_TIME, (void *)buffer);
  147. return size;
  148. }
  149. #endif
  150. static rt_err_t nu_rtc_is_date_valid(const time_t *const t)
  151. {
  152. static struct tm tm_upper = RTC_TM_UPPER_BOUND;
  153. static struct tm tm_lower = RTC_TM_LOWER_BOUND;
  154. static time_t t_upper, t_lower;
  155. static rt_bool_t initialised = RT_FALSE;
  156. if (!initialised)
  157. {
  158. t_upper = timegm((struct tm *)&tm_upper);
  159. t_lower = timegm((struct tm *)&tm_lower);
  160. initialised = RT_TRUE;
  161. }
  162. /* check the date is supported by rtc. */
  163. if ((*t > t_upper) || (*t < t_lower))
  164. return -(RT_EINVAL);
  165. return RT_EOK;
  166. }
  167. /* Register rt-thread device.control() entry. */
  168. static rt_err_t nu_rtc_control(rt_device_t dev, int cmd, void *args)
  169. {
  170. struct tm tm_out, *tm_in;
  171. time_t *time;
  172. S_RTC_TIME_DATA_T hw_time = {0};
  173. #if defined(RT_USING_ALARM)
  174. struct rt_rtc_wkalarm *wkalarm;
  175. S_RTC_TIME_DATA_T hw_alarm = {0};
  176. #endif
  177. if ((dev == NULL) || (args == NULL))
  178. return -(RT_EINVAL);
  179. switch (cmd)
  180. {
  181. case RT_DEVICE_CTRL_RTC_GET_TIME:
  182. time = (time_t *)args;
  183. if (RTC_Read(RTC_CURRENT_TIME, &hw_time) != E_RTC_SUCCESS)
  184. return -(RT_ERROR);
  185. tm_out.tm_year = CONV_TO_TM_YEAR(hw_time.u32Year);
  186. tm_out.tm_mon = CONV_TO_TM_MON(hw_time.u32cMonth);
  187. tm_out.tm_mday = hw_time.u32cDay;
  188. tm_out.tm_hour = hw_time.u32cHour;
  189. tm_out.tm_min = hw_time.u32cMinute;
  190. tm_out.tm_sec = hw_time.u32cSecond;
  191. tm_out.tm_wday = hw_time.u32cDayOfWeek;
  192. *time = timegm(&tm_out);
  193. break;
  194. case RT_DEVICE_CTRL_RTC_SET_TIME:
  195. time = (time_t *) args;
  196. tm_in = gmtime(time);
  197. if (nu_rtc_is_date_valid(time) != RT_EOK)
  198. return -(RT_ERROR);
  199. hw_time.u32Year = CONV_FROM_TM_YEAR(tm_in->tm_year);
  200. hw_time.u32cMonth = CONV_FROM_TM_MON(tm_in->tm_mon);
  201. hw_time.u32cDay = tm_in->tm_mday;
  202. hw_time.u32cHour = tm_in->tm_hour;
  203. hw_time.u32cMinute = tm_in->tm_min;
  204. hw_time.u32cSecond = tm_in->tm_sec;
  205. hw_time.u32cDayOfWeek = tm_in->tm_wday;
  206. hw_time.u8cClockDisplay = RTC_CLOCK_24;
  207. hw_time.u8cAmPm = 0;
  208. if (RTC_Write(RTC_CURRENT_TIME, &hw_time) != E_RTC_SUCCESS)
  209. return -(RT_ERROR);
  210. break;
  211. #if defined(RT_USING_ALARM)
  212. case RT_DEVICE_CTRL_RTC_GET_ALARM:
  213. wkalarm = (struct rt_rtc_wkalarm *) args;
  214. if (RTC_Read(RTC_ALARM_TIME, &hw_alarm) != E_RTC_SUCCESS)
  215. return -(RT_ERROR);
  216. wkalarm->tm_hour = hw_alarm.u32cHour;
  217. wkalarm->tm_min = hw_alarm.u32cMinute;
  218. wkalarm->tm_sec = hw_alarm.u32cSecond;
  219. break;
  220. case RT_DEVICE_CTRL_RTC_SET_ALARM:
  221. wkalarm = (struct rt_rtc_wkalarm *) args;
  222. /* Readback current ALARM time from RTC register for avoiding wrong parameter when next RTC_Write. */
  223. if (RTC_Read(RTC_CURRENT_TIME, &hw_alarm) != E_RTC_SUCCESS)
  224. return -(RT_ERROR);
  225. hw_alarm.u32AlarmMaskHour = 0;
  226. hw_alarm.u32AlarmMaskMinute = 0;
  227. hw_alarm.u32AlarmMaskSecond = 0;
  228. hw_alarm.u32cHour = wkalarm->tm_hour;
  229. hw_alarm.u32cMinute = wkalarm->tm_min;
  230. hw_alarm.u32cSecond = wkalarm->tm_sec;
  231. if (RTC_Write(RTC_ALARM_TIME, &hw_alarm) != E_RTC_SUCCESS)
  232. return -(RT_ERROR);
  233. break;
  234. default:
  235. return -(RT_EINVAL);
  236. #endif
  237. }
  238. return RT_EOK;
  239. }
  240. #if defined (NU_RTC_SUPPORT_MSH_CMD)
  241. /* Support "rtc_det_date" command line in msh mode */
  242. static rt_err_t msh_rtc_set_date(int argc, char **argv)
  243. {
  244. rt_uint32_t index, len, arg[3];
  245. rt_memset(arg, 0, sizeof(arg));
  246. len = (argc >= 4) ? 4 : argc;
  247. /* The date information stored in argv is represented by the following order :
  248. argv[0,1,2,3] = [cmd, year, month, day] */
  249. for (index = 0; index < (len - 1); index ++)
  250. {
  251. arg[index] = atol(argv[index + 1]);
  252. }
  253. return set_date(arg[0], arg[1], arg[2]);
  254. }
  255. MSH_CMD_EXPORT_ALIAS(msh_rtc_set_date, rtc_set_date, e.g: rtc_set_date 2020 1 20);
  256. #endif
  257. #if defined (NU_RTC_SUPPORT_MSH_CMD)
  258. /* Support "rtc_det_time" command line in msh mode */
  259. static rt_err_t msh_rtc_set_time(int argc, char **argv)
  260. {
  261. rt_uint32_t index, len, arg[3];
  262. rt_memset(arg, 0, sizeof(arg));
  263. len = (argc >= 4) ? 4 : argc;
  264. /* The time information stored in argv is represented by the following order :
  265. argv[0,1,2,3] = [cmd, hour, minute, second] */
  266. for (index = 0; index < (len - 1); index ++)
  267. {
  268. arg[index] = atol(argv[index + 1]);
  269. }
  270. return set_time(arg[0], arg[1], arg[2]);
  271. }
  272. MSH_CMD_EXPORT_ALIAS(msh_rtc_set_time, rtc_set_time, e.g: rtc_set_time 18 30 00);
  273. #endif
  274. #if defined(RT_USING_ALARM)
  275. /* rtc interrupt entry */
  276. static void nu_rtc_isr(int vector, void *param)
  277. {
  278. if (RTC_GET_TICK_INT_FLAG())
  279. {
  280. RTC_CLEAR_TICK_INT_FLAG();
  281. }
  282. if (RTC_GET_ALARM_INT_FLAG())
  283. {
  284. RTC_CLEAR_ALARM_INT_FLAG();
  285. /* Send an alarm event to notify rt-thread alarm service. */
  286. rt_alarm_update(&device_rtc, (rt_uint32_t)NULL);
  287. }
  288. }
  289. #endif
  290. #endif /* BSP_USING_RTC */