rtc.c 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  1. /*
  2. * File : rtc.c
  3. * This file is part of RT-Thread RTOS
  4. * COPYRIGHT (C) 2006, RT-Thread Development Team
  5. *
  6. * The license and distribution terms for this file may be
  7. * found in the file LICENSE in this distribution or at
  8. * http://openlab.rt-thread.com/license/LICENSE
  9. *
  10. * Change Logs:
  11. * Date Author Notes
  12. * 2009-04-26 yi.qiu first version
  13. * 2010-03-18 Gary Lee add functions such as GregorianDay
  14. * and rt_rtc_time_to_tm
  15. */
  16. #include <rtthread.h>
  17. #include <time.h>
  18. #include <s3c24x0.h>
  19. #include "rtc.h"
  20. /**
  21. * This function get rtc time
  22. */
  23. void rt_hw_rtc_get(struct rtc_time *ti)
  24. {
  25. rt_uint8_t sec, min, hour, mday, wday, mon, year;
  26. /* enable access to RTC registers */
  27. RTC_ENABLE();
  28. /* read RTC registers */
  29. do
  30. {
  31. sec = BCDSEC;
  32. min = BCDMIN;
  33. hour = BCDHOUR;
  34. mday = BCDDATE;
  35. wday = BCDDAY;
  36. mon = BCDMON;
  37. year = BCDYEAR;
  38. } while (sec != BCDSEC);
  39. /* disable access to RTC registers */
  40. RTC_DISABLE();
  41. ti->tm_sec = BCD2BIN(sec & 0x7F);
  42. ti->tm_min = BCD2BIN(min & 0x7F);
  43. ti->tm_hour = BCD2BIN(hour & 0x3F);
  44. ti->tm_mday = BCD2BIN(mday & 0x3F);
  45. ti->tm_mon = BCD2BIN(mon & 0x1F);
  46. ti->tm_year = BCD2BIN(year);
  47. ti->tm_wday = BCD2BIN(wday & 0x07);
  48. ti->tm_yday = 0;
  49. ti->tm_isdst = 0;
  50. }
  51. /**
  52. * This function set rtc time
  53. */
  54. void rt_hw_rtc_set(struct rtc_time *ti)
  55. {
  56. rt_uint8_t sec, min, hour, mday, wday, mon, year;
  57. year = BIN2BCD(ti->tm_year);
  58. mon = BIN2BCD(ti->tm_mon);
  59. wday = BIN2BCD(ti->tm_wday);
  60. mday = BIN2BCD(ti->tm_mday);
  61. hour = BIN2BCD(ti->tm_hour);
  62. min = BIN2BCD(ti->tm_min);
  63. sec = BIN2BCD(ti->tm_sec);
  64. /* enable access to RTC registers */
  65. RTC_ENABLE();
  66. /* write RTC registers */
  67. BCDSEC = sec;
  68. BCDMIN = min;
  69. BCDHOUR = hour;
  70. BCDDATE = mday;
  71. BCDDAY = wday;
  72. BCDMON = mon;
  73. BCDYEAR = year;
  74. /* disable access to RTC registers */
  75. RTC_DISABLE();
  76. }
  77. /**
  78. * This function reset rtc
  79. */
  80. void rt_hw_rtc_reset (void)
  81. {
  82. RTCCON = (RTCCON & ~0x06) | 0x08;
  83. RTCCON &= ~(0x08|0x01);
  84. }
  85. /*
  86. * This only works for the Gregorian calendar - i.e. after 1752 (in the UK)
  87. */
  88. void GregorianDay(struct rtc_time * tm)
  89. {
  90. int leapsToDate;
  91. int lastYear;
  92. int day;
  93. int MonthOffset[] = { 0,31,59,90,120,151,181,212,243,273,304,334 };
  94. lastYear=tm->tm_year-1;
  95. /*
  96. * Number of leap corrections to apply up to end of last year
  97. */
  98. leapsToDate = lastYear/4 - lastYear/100 + lastYear/400;
  99. /*
  100. * This year is a leap year if it is divisible by 4 except when it is
  101. * divisible by 100 unless it is divisible by 400
  102. *
  103. * e.g. 1904 was a leap year, 1900 was not, 1996 is, and 2000 will be
  104. */
  105. if((tm->tm_year%4==0) &&
  106. ((tm->tm_year%100!=0) || (tm->tm_year%400==0)) &&
  107. (tm->tm_mon>2)) {
  108. /*
  109. * We are past Feb. 29 in a leap year
  110. */
  111. day=1;
  112. } else {
  113. day=0;
  114. }
  115. day += lastYear*365 + leapsToDate + MonthOffset[tm->tm_mon-1] + tm->tm_mday;
  116. tm->tm_wday=day%7;
  117. }
  118. void rt_rtc_time_to_tm(rt_uint32_t tim, struct rtc_time *tm)
  119. {
  120. register int i;
  121. register long hms, day;
  122. day = tim / SECDAY;
  123. hms = tim % SECDAY;
  124. /* Hours, minutes, seconds are easy */
  125. tm->tm_hour = hms / 3600;
  126. tm->tm_min = (hms % 3600) / 60;
  127. tm->tm_sec = (hms % 3600) % 60;
  128. /* Number of years in days */
  129. for (i = STARTOFTIME; day >= days_in_year(i); i++) {
  130. day -= days_in_year(i);
  131. }
  132. tm->tm_year = i;
  133. /* Number of months in days left */
  134. if (LEAP_YEAR(tm->tm_year)) {
  135. days_in_month(FEBRUARY) = 29;
  136. }
  137. for (i = 1; day >= days_in_month(i); i++) {
  138. day -= days_in_month(i);
  139. }
  140. days_in_month(FEBRUARY) = 28;
  141. tm->tm_mon = i;
  142. /* Days are what is left over (+1) from all that. */
  143. tm->tm_mday = day + 1;
  144. /*
  145. * Determine the day of week
  146. */
  147. GregorianDay(tm);
  148. }
  149. static struct rt_device rtc;
  150. static rt_err_t rt_rtc_open(rt_device_t dev, rt_uint16_t oflag)
  151. {
  152. RTC_ENABLE();
  153. return RT_EOK;
  154. }
  155. static rt_err_t rt_rtc_close(rt_device_t dev)
  156. {
  157. RTC_DISABLE();
  158. return RT_EOK;
  159. }
  160. static rt_size_t rt_rtc_read(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size)
  161. {
  162. return RT_EOK;
  163. }
  164. static rt_err_t rt_rtc_control(rt_device_t dev, rt_uint8_t cmd, void *args)
  165. {
  166. struct rtc_time* time;
  167. RT_ASSERT(dev != RT_NULL);
  168. time = (struct rtc_time*)args;
  169. switch (cmd)
  170. {
  171. case RT_DEVICE_CTRL_RTC_GET_TIME:
  172. /* read device */
  173. rt_hw_rtc_get(time);
  174. break;
  175. case RT_DEVICE_CTRL_RTC_SET_TIME:
  176. /* write device */
  177. rt_hw_rtc_set(time);
  178. break;
  179. }
  180. return RT_EOK;
  181. }
  182. void rt_hw_rtc_init(void)
  183. {
  184. rtc.type = RT_Device_Class_RTC;
  185. /* register rtc device */
  186. rtc.init = RT_NULL;
  187. rtc.open = rt_rtc_open;
  188. rtc.close = rt_rtc_close;
  189. rtc.read = rt_rtc_read;
  190. rtc.write = RT_NULL;
  191. rtc.control = rt_rtc_control;
  192. /* no private */
  193. rtc.private = RT_NULL;
  194. rt_device_register(&rtc, "rtc", RT_DEVICE_FLAG_RDWR);
  195. }
  196. time_t time(time_t* t)
  197. {
  198. rt_device_t device;
  199. struct tm ti;
  200. time_t time;
  201. device = rt_device_find("rtc");
  202. if (device != RT_NULL)
  203. {
  204. rt_device_control(device, RT_DEVICE_CTRL_RTC_GET_TIME, &ti);
  205. if (t != RT_NULL)
  206. {
  207. time = mktime(&ti);
  208. *t = time;
  209. }
  210. }
  211. return time;
  212. }
  213. #ifdef RT_USING_FINSH
  214. #include <finsh.h>
  215. void set_date(rt_uint32_t year, rt_uint32_t month, rt_uint32_t day)
  216. {
  217. struct rtc_time ti;
  218. rt_device_t device;
  219. device = rt_device_find("rtc");
  220. if (device != RT_NULL)
  221. {
  222. rt_rtc_control(device, RT_DEVICE_CTRL_RTC_GET_TIME, &ti);
  223. ti.tm_year = year - 1900;
  224. ti.tm_mon = month - 1;
  225. ti.tm_mday = day;
  226. rt_rtc_control(device, RT_DEVICE_CTRL_RTC_SET_TIME, &ti);
  227. }
  228. }
  229. FINSH_FUNCTION_EXPORT(set_date, set date(year, month, day))
  230. void set_time(rt_uint32_t hour, rt_uint32_t minute, rt_uint32_t second)
  231. {
  232. struct rtc_time ti;
  233. rt_device_t device;
  234. device = rt_device_find("rtc");
  235. if (device != RT_NULL)
  236. {
  237. rt_rtc_control(device, RT_DEVICE_CTRL_RTC_GET_TIME, &ti);
  238. ti.tm_hour = hour;
  239. ti.tm_min = minute;
  240. ti.tm_sec = second;
  241. rt_rtc_control(device, RT_DEVICE_CTRL_RTC_SET_TIME, &ti);
  242. }
  243. }
  244. FINSH_FUNCTION_EXPORT(set_time, set time(hour, minute, second))
  245. void list_date(void)
  246. {
  247. time_t now;
  248. time(&now);
  249. rt_kprintf("%s\n", ctime(&now));
  250. }
  251. FINSH_FUNCTION_EXPORT(list_date, list date)
  252. #endif