rtc.c 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429
  1. #include "rtc.h"
  2. #include "settings_api.h"
  3. #include "common_config.h"
  4. #include <string.h>
  5. #include <stdio.h>
  6. // Days in a month
  7. uint8_t TM_RTC_Months[2][12] = {
  8. {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, // Not leap year
  9. {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} // Leap year
  10. };
  11. // monthly correction data sheet
  12. const uint8_t table_week[12] = {0, 3, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5};
  13. // monmonth data table of common year
  14. const uint8_t mon_table[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
  15. // Internal RTC defines
  16. #define TM_RTC_LEAP_YEAR(year) ((((year) % 4 == 0) && ((year) % 100 != 0)) || ((year) % 400 == 0))
  17. #define TM_RTC_DAYS_IN_YEAR(x) TM_RTC_LEAP_YEAR(x) ? 366 : 365
  18. #define TM_RTC_OFFSET_YEAR 1970
  19. #define TM_RTC_SECONDS_PER_DAY 86400
  20. #define TM_RTC_SECONDS_PER_HOUR 3600
  21. #define TM_RTC_SECONDS_PER_MINUTE 60
  22. #define TM_RTC_BCD2BIN(x) ((((x) >> 4) & 0x0F) * 10 + ((x) & 0x0F))
  23. #define TM_RTC_CHAR2NUM(x) ((x) - '0')
  24. #define TM_RTC_CHARISNUM(x) ((x) >= '0' && (x) <= '9')
  25. extern SemaphoreHandle_t flash_mutex;
  26. /**
  27. * @brief rtc peripheral initialization.
  28. * @param calendar
  29. * @retval 0: rtc already init
  30. 1: rtc init
  31. */
  32. uint8_t TM_RTC_Init(void)
  33. {
  34. TM_RTC_t datatime;
  35. uint16_t tmp = 0;
  36. // enable pwc and bpr clocks
  37. crm_periph_clock_enable(CRM_PWC_PERIPH_CLOCK, TRUE);
  38. crm_periph_clock_enable(CRM_BPR_PERIPH_CLOCK, TRUE);
  39. // enable the battery-powered domain write operations
  40. pwc_battery_powered_domain_access(TRUE);
  41. tmp = bpr_data_read(BACKUP_RTC_KEY);
  42. printf("RTC: %X\r\n", tmp);
  43. // check if rtc is initialized
  44. if (bpr_data_read(BACKUP_RTC_KEY) != 0x1234)
  45. {
  46. // reset battery-powered domain register
  47. bpr_reset();
  48. // enable the lext osc
  49. crm_clock_source_enable(CRM_CLOCK_SOURCE_LEXT, TRUE);
  50. // wait lext is ready
  51. while(crm_flag_get(CRM_LEXT_STABLE_FLAG) == RESET);
  52. // select the rtc clock source
  53. crm_rtc_clock_select(CRM_RTC_CLOCK_LEXT);
  54. // enable rtc clock
  55. crm_rtc_clock_enable(TRUE);
  56. // wait for rtc registers update
  57. rtc_wait_update_finish();
  58. // wait for the register write to complete
  59. rtc_wait_config_finish();
  60. // enable the rtc second
  61. nvic_irq_enable(RTC_IRQn, 6, 0);
  62. rtc_interrupt_enable(RTC_TS_INT, TRUE);
  63. // set rtc divider: set rtc period to 1sec
  64. rtc_divider_set(32767);
  65. // wait for the register write to complete
  66. rtc_wait_config_finish();
  67. // set date and time
  68. datatime.date = 1;
  69. datatime.day = 1;
  70. datatime.month = 1;
  71. datatime.year = 0;
  72. datatime.hours = 0;
  73. datatime.minutes = 0;
  74. datatime.seconds = 0;
  75. TM_RTC_SetDateTime(&datatime);
  76. // writes data to bpr register
  77. bpr_data_write(BACKUP_RTC_KEY, 0x1234);
  78. return 1;
  79. }
  80. else
  81. {
  82. // wait for rtc registers update
  83. rtc_wait_update_finish();
  84. // wait for the register write to complete
  85. rtc_wait_config_finish();
  86. // enable the rtc second
  87. nvic_irq_enable(RTC_IRQn, 6, 0);
  88. rtc_interrupt_enable(RTC_TS_INT, TRUE);
  89. return 0;
  90. }
  91. }
  92. //
  93. void TM_RTC_SetDataTimeUnix(uint32_t unixTime)
  94. {
  95. TM_RTC_t data;
  96. TM_RTC_GetDateTimeFromUnix(&data, unixTime);
  97. rtc_counter_set(unixTime);
  98. rtc_wait_config_finish();
  99. bpr_data_write(BACKUP_RTC_UPDATE, 0x1234);
  100. }
  101. /**
  102. * @brief set time. convert the input clock to a second.
  103. * the time basic : 1970.1.1
  104. * legitimate year: 1970 ~ 2099
  105. * @param calendar
  106. * @retval 0: set time right.
  107. * 1: set time failed.
  108. */
  109. TM_RTC_Result_t TM_RTC_SetDateTime(TM_RTC_t* data)
  110. {
  111. uint32_t seccount = 0;
  112. if (data->year > 99 ||
  113. data->month == 0 ||
  114. data->month > 12 ||
  115. data->date == 0 ||
  116. data->date > TM_RTC_Months[TM_RTC_LEAP_YEAR(2000 + data->year) ? 1 : 0][data->month - 1] ||
  117. data->hours > 23 ||
  118. data->minutes > 59 ||
  119. data->seconds > 59 ||
  120. data->day == 0 ||
  121. data->day > 7)
  122. {
  123. return TM_RTC_Result_Error;
  124. }
  125. // enable pwc and bpr clocks
  126. crm_periph_clock_enable(CRM_PWC_PERIPH_CLOCK, TRUE);
  127. crm_periph_clock_enable(CRM_BPR_PERIPH_CLOCK, TRUE);
  128. // enable write access to bpr domain
  129. pwc_battery_powered_domain_access(TRUE);
  130. // set the rtc counter value
  131. seccount = TM_RTC_GetUnixTimeStamp(data);
  132. rtc_counter_set(seccount);
  133. // wait for the register write to complete
  134. rtc_wait_config_finish();
  135. return TM_RTC_Result_Ok;
  136. }
  137. //
  138. TM_RTC_Result_t TM_RTC_SetDateTimeString(char* str)
  139. {
  140. TM_RTC_t tmp;
  141. uint8_t i = 0;
  142. // Get date
  143. tmp.date = 0;
  144. while (TM_RTC_CHARISNUM(*(str + i))) {
  145. tmp.date = tmp.date * 10 + TM_RTC_CHAR2NUM(*(str + i));
  146. i++;
  147. }
  148. i++;
  149. // Get month
  150. tmp.month = 0;
  151. while (TM_RTC_CHARISNUM(*(str + i))) {
  152. tmp.month = tmp.month * 10 + TM_RTC_CHAR2NUM(*(str + i));
  153. i++;
  154. }
  155. i++;
  156. // Get year
  157. tmp.year = 0;
  158. while (TM_RTC_CHARISNUM(*(str + i))) {
  159. tmp.year = tmp.year * 10 + TM_RTC_CHAR2NUM(*(str + i));
  160. i++;
  161. }
  162. i++;
  163. // Get day in a week
  164. tmp.day = 0;
  165. while (TM_RTC_CHARISNUM(*(str + i))) {
  166. tmp.day = tmp.day * 10 + TM_RTC_CHAR2NUM(*(str + i));
  167. i++;
  168. }
  169. i++;
  170. // Get hours
  171. tmp.hours = 0;
  172. while (TM_RTC_CHARISNUM(*(str + i))) {
  173. tmp.hours = tmp.hours * 10 + TM_RTC_CHAR2NUM(*(str + i));
  174. i++;
  175. }
  176. i++;
  177. // Get minutes
  178. tmp.minutes = 0;
  179. while (TM_RTC_CHARISNUM(*(str + i))) {
  180. tmp.minutes = tmp.minutes * 10 + TM_RTC_CHAR2NUM(*(str + i));
  181. i++;
  182. }
  183. i++;
  184. // Get seconds
  185. tmp.seconds = 0;
  186. while (TM_RTC_CHARISNUM(*(str + i))) {
  187. tmp.seconds = tmp.seconds * 10 + TM_RTC_CHAR2NUM(*(str + i));
  188. i++;
  189. }
  190. i++;
  191. // Return status from set date time function
  192. return TM_RTC_SetDateTime(&tmp);
  193. }
  194. //
  195. void TM_RTC_GetDateTime(TM_RTC_t* data, TM_RTC_Format_t format)
  196. {
  197. (void)format;
  198. uint32_t unix = rtc_counter_get();
  199. TM_RTC_GetDateTimeFromUnix(data, unix);
  200. }
  201. //
  202. uint32_t TM_RTC_GetUnixTimeStamp(TM_RTC_t* data)
  203. {
  204. uint32_t days = 0, seconds = 0;
  205. uint16_t i;
  206. uint16_t year = (uint16_t)(data->year + 2000);
  207. // Year is below offset year
  208. if (year < TM_RTC_OFFSET_YEAR) {
  209. return 0;
  210. }
  211. // Days in back years
  212. for (i = TM_RTC_OFFSET_YEAR; i < year; i++) {
  213. days += TM_RTC_DAYS_IN_YEAR(i);
  214. }
  215. // Days in current year
  216. for (i = 1; i < data->month; i++) {
  217. days += TM_RTC_Months[TM_RTC_LEAP_YEAR(year)][i - 1];
  218. }
  219. // Day starts with 1
  220. days += data->date - 1;
  221. seconds = days * TM_RTC_SECONDS_PER_DAY;
  222. seconds += data->hours * TM_RTC_SECONDS_PER_HOUR;
  223. seconds += data->minutes * TM_RTC_SECONDS_PER_MINUTE;
  224. seconds += data->seconds;
  225. // seconds = days * 86400;
  226. return seconds;
  227. }
  228. //
  229. void TM_RTC_GetDateTimeFromUnix(TM_RTC_t* data, uint32_t unix)
  230. {
  231. uint16_t year;
  232. // Store unix time to unix in struct
  233. data->unix = unix;
  234. // Get seconds from unix
  235. data->seconds = unix % 60;
  236. // Go to minutes
  237. unix /= 60;
  238. // Get minutes
  239. data->minutes = unix % 60;
  240. // Go to hours
  241. unix /= 60;
  242. // Get hours
  243. data->hours = unix % 24;
  244. // Go to days
  245. unix /= 24;
  246. // Get week day
  247. // Monday is day one
  248. data->day = (unix + 3) % 7 + 1;
  249. // Get year
  250. year = 1970;
  251. while (1) {
  252. if (TM_RTC_LEAP_YEAR(year)) {
  253. if (unix >= 366) {
  254. unix -= 366;
  255. } else {
  256. break;
  257. }
  258. } else if (unix >= 365) {
  259. unix -= 365;
  260. } else {
  261. break;
  262. }
  263. year++;
  264. }
  265. // Get year in xx format
  266. data->year = (uint8_t) (year - 2000);
  267. // Get month
  268. for (data->month = 0; data->month < 12; data->month++) {
  269. if (TM_RTC_LEAP_YEAR(year) && unix >= (uint32_t)TM_RTC_Months[1][data->month]) {
  270. unix -= TM_RTC_Months[1][data->month];
  271. } else if (unix >= (uint32_t)TM_RTC_Months[0][data->month]) {
  272. unix -= TM_RTC_Months[0][data->month];
  273. } else {
  274. break;
  275. }
  276. }
  277. // Get month
  278. // Month starts with 1
  279. data->month++;
  280. // Get date
  281. // Date starts with 1
  282. data->date = unix + 1;
  283. }
  284. //
  285. void TM_RTC_PrintTime(void)
  286. {
  287. TM_RTC_t data;
  288. uint32_t unix = rtc_counter_get();
  289. TM_RTC_GetDateTimeFromUnix(&data, unix);
  290. printf("%02d.%02d.%02d %02d:%02d:%02d\r\n", data.date, data.month, data.year,
  291. data.hours, data.minutes, data.seconds);
  292. }
  293. //
  294. uint32_t RTC_GetUnixTime(void)
  295. {
  296. TM_RTC_t currentTime;
  297. TM_RTC_GetDateTime(&currentTime, TM_RTC_Format_BIN);
  298. return TM_RTC_GetUnixTimeStamp(&currentTime);
  299. }
  300. //
  301. void rtc_subtim_init(void)
  302. {
  303. crm_clocks_freq_type crm_clocks_freq_struct = {0};
  304. crm_periph_clock_enable(CRM_TMR5_PERIPH_CLOCK, TRUE);
  305. crm_clocks_freq_get(&crm_clocks_freq_struct);
  306. tmr_base_init(TMR5, 9999, 24000 - 1);
  307. tmr_cnt_dir_set(TMR5, TMR_COUNT_UP);
  308. tmr_flag_clear(TMR5, TMR_OVF_FLAG);
  309. NVIC_ClearPendingIRQ(TMR5_GLOBAL_IRQn);
  310. nvic_irq_enable(TMR5_GLOBAL_IRQn, 5, 0);
  311. tmr_counter_enable(TMR5, TRUE);
  312. tmr_interrupt_enable(TMR5, TMR_OVF_INT, TRUE);
  313. }
  314. //
  315. uint64_t rtc_get_ms(void)
  316. {
  317. return ((uint64_t)RTC_GetUnixTime()*1000 + TMR5->cval/10);
  318. }
  319. //
  320. uint32_t rtc_foo(void)
  321. {
  322. return tmr_counter_value_get(TMR5);
  323. }
  324. //
  325. void rtc_set_in_ms(uint64_t ms)
  326. {
  327. TM_RTC_SetDataTimeUnix(ms);
  328. }
  329. //
  330. void TMR5_GLOBAL_IRQHandler(void)
  331. {
  332. if (tmr_flag_get(TMR5, TMR_OVF_FLAG) != RESET)
  333. {
  334. tmr_flag_clear(TMR5, TMR_OVF_FLAG);
  335. tmr_interrupt_enable(TMR5, TMR_OVF_INT, FALSE);
  336. tmr_counter_enable(TMR5, FALSE);
  337. }
  338. }
  339. //
  340. void RTC_IRQHandler(void)
  341. {
  342. if (rtc_flag_get(RTC_TS_FLAG) != RESET)
  343. {
  344. rtc_flag_clear(RTC_TS_FLAG);
  345. tmr_interrupt_enable(TMR5, TMR_OVF_INT, TRUE);
  346. tmr_counter_enable(TMR5, TRUE);
  347. TMR5->cval = 0;
  348. }
  349. }