Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of mbed-dev by
targets/TARGET_NUVOTON/TARGET_NANO100/rtc_api.c@188:60408c49b6d4, 2018-09-20 (annotated)
- Committer:
- WaleedElmughrabi
- Date:
- Thu Sep 20 16:11:23 2018 +0000
- Revision:
- 188:60408c49b6d4
- Parent:
- 186:707f6e361f3e
Fork modified for BG96 error
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
AnnaBridge | 174:b96e65c34a4d | 1 | /* mbed Microcontroller Library |
AnnaBridge | 174:b96e65c34a4d | 2 | * Copyright (c) 2015-2017 Nuvoton |
AnnaBridge | 174:b96e65c34a4d | 3 | * |
AnnaBridge | 174:b96e65c34a4d | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
AnnaBridge | 174:b96e65c34a4d | 5 | * you may not use this file except in compliance with the License. |
AnnaBridge | 174:b96e65c34a4d | 6 | * You may obtain a copy of the License at |
AnnaBridge | 174:b96e65c34a4d | 7 | * |
AnnaBridge | 174:b96e65c34a4d | 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
AnnaBridge | 174:b96e65c34a4d | 9 | * |
AnnaBridge | 174:b96e65c34a4d | 10 | * Unless required by applicable law or agreed to in writing, software |
AnnaBridge | 174:b96e65c34a4d | 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
AnnaBridge | 174:b96e65c34a4d | 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
AnnaBridge | 174:b96e65c34a4d | 13 | * See the License for the specific language governing permissions and |
AnnaBridge | 174:b96e65c34a4d | 14 | * limitations under the License. |
AnnaBridge | 174:b96e65c34a4d | 15 | */ |
AnnaBridge | 184:08ed48f1de7f | 16 | |
AnnaBridge | 174:b96e65c34a4d | 17 | #include "rtc_api.h" |
AnnaBridge | 174:b96e65c34a4d | 18 | |
AnnaBridge | 174:b96e65c34a4d | 19 | #if DEVICE_RTC |
AnnaBridge | 174:b96e65c34a4d | 20 | |
AnnaBridge | 174:b96e65c34a4d | 21 | #include "mbed_wait_api.h" |
AnnaBridge | 174:b96e65c34a4d | 22 | #include "mbed_error.h" |
AnnaBridge | 174:b96e65c34a4d | 23 | #include "nu_modutil.h" |
AnnaBridge | 174:b96e65c34a4d | 24 | #include "nu_miscutil.h" |
AnnaBridge | 174:b96e65c34a4d | 25 | #include "mbed_mktime.h" |
AnnaBridge | 174:b96e65c34a4d | 26 | |
AnnaBridge | 184:08ed48f1de7f | 27 | /* Micro seconds per second */ |
AnnaBridge | 184:08ed48f1de7f | 28 | #define NU_US_PER_SEC 1000000 |
AnnaBridge | 184:08ed48f1de7f | 29 | /* Timer clock per second |
AnnaBridge | 184:08ed48f1de7f | 30 | * |
AnnaBridge | 184:08ed48f1de7f | 31 | * NOTE: This dependents on real hardware. |
AnnaBridge | 184:08ed48f1de7f | 32 | */ |
AnnaBridge | 184:08ed48f1de7f | 33 | #define NU_RTCCLK_PER_SEC (__LXT) |
AnnaBridge | 174:b96e65c34a4d | 34 | |
AnnaBridge | 184:08ed48f1de7f | 35 | /* Strategy for implementation of RTC HAL |
AnnaBridge | 184:08ed48f1de7f | 36 | * |
AnnaBridge | 184:08ed48f1de7f | 37 | * H/W RTC just supports year range 2000~2099, which cannot fully cover POSIX time (starting since 2970) |
AnnaBridge | 184:08ed48f1de7f | 38 | * and date time of struct TM (starting since 1900). |
AnnaBridge | 184:08ed48f1de7f | 39 | * |
AnnaBridge | 184:08ed48f1de7f | 40 | * To conquer the difficulty, we don't use H/W RTC to keep real date time. Instead, we use it to keep |
AnnaBridge | 184:08ed48f1de7f | 41 | * elapsed time in seconds since one reference time point. The strategy would be: |
AnnaBridge | 184:08ed48f1de7f | 42 | * |
AnnaBridge | 184:08ed48f1de7f | 43 | * 1. Choose DATETIME_HWRTC_ORIGIN (00:00:00 UTC, Saturday, 1 January 2000) as reference time point of H/W RTC. |
AnnaBridge | 184:08ed48f1de7f | 44 | * 2. t_hwrtc_origin = DATETIME_HWRTC_ORIGIN in POSIX time |
AnnaBridge | 184:08ed48f1de7f | 45 | * 3. t_hwrtc_elapsed = t_hwrtc_origin + elapsed time since t_hwrtc_origin |
AnnaBridge | 184:08ed48f1de7f | 46 | * 4. t_write = POSIX time set by rtc_write(). |
AnnaBridge | 184:08ed48f1de7f | 47 | * 5. t_present = rtc_read() = t_write + (t_hwrtc_elapsed - t_hwrtc_origin) |
AnnaBridge | 184:08ed48f1de7f | 48 | * |
AnnaBridge | 184:08ed48f1de7f | 49 | * 1900 |
AnnaBridge | 184:08ed48f1de7f | 50 | * |---------------------------------------------------------------------------------| |
AnnaBridge | 184:08ed48f1de7f | 51 | * 1970 t_write t_present |
AnnaBridge | 184:08ed48f1de7f | 52 | * |---------|-------|-----------------|---------------------------------------------| |
AnnaBridge | 184:08ed48f1de7f | 53 | * |
AnnaBridge | 184:08ed48f1de7f | 54 | * 2000 |
AnnaBridge | 184:08ed48f1de7f | 55 | * |-----------------|---------------------------------------------------------------| |
AnnaBridge | 184:08ed48f1de7f | 56 | * t_hwrtc_origin t_hwrtc_elapsed |
AnnaBridge | 184:08ed48f1de7f | 57 | * |
AnnaBridge | 184:08ed48f1de7f | 58 | */ |
AnnaBridge | 184:08ed48f1de7f | 59 | /* Start year of struct TM*/ |
AnnaBridge | 184:08ed48f1de7f | 60 | #define NU_TM_YEAR0 1900 |
AnnaBridge | 184:08ed48f1de7f | 61 | /* Start year of POSIX time (set_time()/time()) */ |
AnnaBridge | 184:08ed48f1de7f | 62 | #define NU_POSIX_YEAR0 1970 |
AnnaBridge | 184:08ed48f1de7f | 63 | /* Start year of H/W RTC */ |
AnnaBridge | 184:08ed48f1de7f | 64 | #define NU_HWRTC_YEAR0 2000 |
AnnaBridge | 184:08ed48f1de7f | 65 | |
AnnaBridge | 184:08ed48f1de7f | 66 | /* RTC H/W origin time: 00:00:00 UTC, Saturday, 1 January 2000 */ |
AnnaBridge | 184:08ed48f1de7f | 67 | static const S_RTC_TIME_DATA_T DATETIME_HWRTC_ORIGIN = { |
AnnaBridge | 184:08ed48f1de7f | 68 | 2000, /* Year value, range between 2000 ~ 2099 */ |
AnnaBridge | 184:08ed48f1de7f | 69 | 1, /* Month value, range between 1 ~ 12 */ |
AnnaBridge | 184:08ed48f1de7f | 70 | 1, /* Day value, range between 1 ~ 31 */ |
AnnaBridge | 184:08ed48f1de7f | 71 | RTC_SATURDAY, /* Day of the week */ |
AnnaBridge | 184:08ed48f1de7f | 72 | 0, /* Hour value, range between 0 ~ 23 */ |
AnnaBridge | 184:08ed48f1de7f | 73 | 0, /* Minute value, range between 0 ~ 59 */ |
AnnaBridge | 184:08ed48f1de7f | 74 | 0, /* Second value, range between 0 ~ 59 */ |
AnnaBridge | 184:08ed48f1de7f | 75 | RTC_CLOCK_24, /* 12-Hour (RTC_CLOCK_12) / 24-Hour (RTC_CLOCK_24) */ |
AnnaBridge | 184:08ed48f1de7f | 76 | 0 /* RTC_AM / RTC_PM (used only for 12-Hour) */ |
AnnaBridge | 184:08ed48f1de7f | 77 | }; |
AnnaBridge | 184:08ed48f1de7f | 78 | /* t_hwrtc_origin initialized or not? */ |
AnnaBridge | 184:08ed48f1de7f | 79 | static bool t_hwrtc_origin_inited = 0; |
AnnaBridge | 184:08ed48f1de7f | 80 | /* POSIX time of DATETIME_HWRTC_ORIGIN (since 00:00:00 UTC, Thursday, 1 January 1970) */ |
AnnaBridge | 184:08ed48f1de7f | 81 | static time_t t_hwrtc_origin = 0; |
AnnaBridge | 184:08ed48f1de7f | 82 | /* POSIX time set by rtc_write() */ |
AnnaBridge | 184:08ed48f1de7f | 83 | static time_t t_write = 0; |
AnnaBridge | 184:08ed48f1de7f | 84 | /* Convert date time from H/W RTC to struct TM */ |
AnnaBridge | 184:08ed48f1de7f | 85 | static void rtc_convert_datetime_hwrtc_to_tm(struct tm *datetime_tm, const S_RTC_TIME_DATA_T *datetime_hwrtc); |
AnnaBridge | 174:b96e65c34a4d | 86 | |
AnnaBridge | 174:b96e65c34a4d | 87 | static const struct nu_modinit_s rtc_modinit = {RTC_0, RTC_MODULE, 0, 0, 0, RTC_IRQn, NULL}; |
AnnaBridge | 174:b96e65c34a4d | 88 | |
AnnaBridge | 174:b96e65c34a4d | 89 | void rtc_init(void) |
AnnaBridge | 174:b96e65c34a4d | 90 | { |
AnnaBridge | 174:b96e65c34a4d | 91 | if (rtc_isenabled()) { |
AnnaBridge | 174:b96e65c34a4d | 92 | return; |
AnnaBridge | 174:b96e65c34a4d | 93 | } |
AnnaBridge | 184:08ed48f1de7f | 94 | |
AnnaBridge | 174:b96e65c34a4d | 95 | RTC_Open(NULL); |
AnnaBridge | 184:08ed48f1de7f | 96 | |
AnnaBridge | 184:08ed48f1de7f | 97 | /* POSIX time origin (00:00:00 UTC, Thursday, 1 January 1970) */ |
AnnaBridge | 184:08ed48f1de7f | 98 | rtc_write(0); |
AnnaBridge | 174:b96e65c34a4d | 99 | } |
AnnaBridge | 174:b96e65c34a4d | 100 | |
AnnaBridge | 174:b96e65c34a4d | 101 | void rtc_free(void) |
AnnaBridge | 174:b96e65c34a4d | 102 | { |
Anna Bridge |
186:707f6e361f3e | 103 | CLK_DisableModuleClock(rtc_modinit.clkidx); |
AnnaBridge | 174:b96e65c34a4d | 104 | } |
AnnaBridge | 174:b96e65c34a4d | 105 | |
AnnaBridge | 174:b96e65c34a4d | 106 | int rtc_isenabled(void) |
AnnaBridge | 174:b96e65c34a4d | 107 | { |
AnnaBridge | 174:b96e65c34a4d | 108 | // NOTE: To access (RTC) registers, clock must be enabled first. |
AnnaBridge | 174:b96e65c34a4d | 109 | if (! (CLK->APBCLK & CLK_APBCLK_RTC_EN_Msk)) { |
AnnaBridge | 174:b96e65c34a4d | 110 | // Enable IP clock |
AnnaBridge | 174:b96e65c34a4d | 111 | CLK_EnableModuleClock(rtc_modinit.clkidx); |
AnnaBridge | 174:b96e65c34a4d | 112 | } |
AnnaBridge | 184:08ed48f1de7f | 113 | |
AnnaBridge | 174:b96e65c34a4d | 114 | // NOTE: Check RTC Init Active flag to support crossing reset cycle. |
AnnaBridge | 174:b96e65c34a4d | 115 | return !! (RTC->INIR & RTC_INIR_ACTIVE_Msk); |
AnnaBridge | 174:b96e65c34a4d | 116 | } |
AnnaBridge | 174:b96e65c34a4d | 117 | |
AnnaBridge | 184:08ed48f1de7f | 118 | time_t rtc_read(void) |
AnnaBridge | 184:08ed48f1de7f | 119 | { |
AnnaBridge | 184:08ed48f1de7f | 120 | /* NOTE: After boot, RTC time registers are not synced immediately, about 1 sec latency. |
AnnaBridge | 184:08ed48f1de7f | 121 | * RTC time got (through RTC_GetDateAndTime()) in this sec would be last-synced and incorrect. |
AnnaBridge | 184:08ed48f1de7f | 122 | */ |
AnnaBridge | 184:08ed48f1de7f | 123 | if (! rtc_isenabled()) { |
AnnaBridge | 184:08ed48f1de7f | 124 | rtc_init(); |
AnnaBridge | 184:08ed48f1de7f | 125 | } |
AnnaBridge | 184:08ed48f1de7f | 126 | |
AnnaBridge | 184:08ed48f1de7f | 127 | /* Used for intermediary between date time of H/W RTC and POSIX time */ |
AnnaBridge | 184:08ed48f1de7f | 128 | struct tm datetime_tm; |
AnnaBridge | 184:08ed48f1de7f | 129 | |
AnnaBridge | 184:08ed48f1de7f | 130 | if (! t_hwrtc_origin_inited) { |
AnnaBridge | 184:08ed48f1de7f | 131 | t_hwrtc_origin_inited = 1; |
AnnaBridge | 184:08ed48f1de7f | 132 | |
AnnaBridge | 184:08ed48f1de7f | 133 | /* Convert date time from H/W RTC to struct TM */ |
AnnaBridge | 184:08ed48f1de7f | 134 | rtc_convert_datetime_hwrtc_to_tm(&datetime_tm, &DATETIME_HWRTC_ORIGIN); |
AnnaBridge | 184:08ed48f1de7f | 135 | /* Convert date time of struct TM to POSIX time */ |
AnnaBridge | 184:08ed48f1de7f | 136 | if (! _rtc_maketime(&datetime_tm, &t_hwrtc_origin, RTC_FULL_LEAP_YEAR_SUPPORT)) { |
AnnaBridge | 184:08ed48f1de7f | 137 | return 0; |
AnnaBridge | 184:08ed48f1de7f | 138 | } |
Anna Bridge |
186:707f6e361f3e | 139 | |
Anna Bridge |
186:707f6e361f3e | 140 | /* Load t_write from RTC spare register to cross reset cycle */ |
Anna Bridge |
186:707f6e361f3e | 141 | RTC_WaitAccessEnable(); |
Anna Bridge |
186:707f6e361f3e | 142 | t_write = RTC_READ_SPARE_REGISTER(0); |
Anna Bridge |
186:707f6e361f3e | 143 | RTC_WaitAccessEnable(); |
Anna Bridge |
186:707f6e361f3e | 144 | while (! (RTC->SPRCTL & RTC_SPRCTL_SPRRDY_Msk)); |
AnnaBridge | 184:08ed48f1de7f | 145 | } |
AnnaBridge | 184:08ed48f1de7f | 146 | |
AnnaBridge | 184:08ed48f1de7f | 147 | S_RTC_TIME_DATA_T hwrtc_datetime_2K_present; |
Anna Bridge |
186:707f6e361f3e | 148 | RTC_WaitAccessEnable(); |
AnnaBridge | 184:08ed48f1de7f | 149 | RTC_GetDateAndTime(&hwrtc_datetime_2K_present); |
AnnaBridge | 184:08ed48f1de7f | 150 | /* Convert date time from H/W RTC to struct TM */ |
AnnaBridge | 184:08ed48f1de7f | 151 | rtc_convert_datetime_hwrtc_to_tm(&datetime_tm, &hwrtc_datetime_2K_present); |
AnnaBridge | 184:08ed48f1de7f | 152 | /* Convert date time of struct TM to POSIX time */ |
AnnaBridge | 184:08ed48f1de7f | 153 | time_t t_hwrtc_elapsed; |
AnnaBridge | 184:08ed48f1de7f | 154 | if (! _rtc_maketime(&datetime_tm, &t_hwrtc_elapsed, RTC_FULL_LEAP_YEAR_SUPPORT)) { |
AnnaBridge | 184:08ed48f1de7f | 155 | return 0; |
AnnaBridge | 184:08ed48f1de7f | 156 | } |
AnnaBridge | 184:08ed48f1de7f | 157 | |
AnnaBridge | 184:08ed48f1de7f | 158 | /* Present time in POSIX time */ |
AnnaBridge | 184:08ed48f1de7f | 159 | time_t t_present = t_write + (t_hwrtc_elapsed - t_hwrtc_origin); |
AnnaBridge | 184:08ed48f1de7f | 160 | return t_present; |
AnnaBridge | 184:08ed48f1de7f | 161 | } |
AnnaBridge | 184:08ed48f1de7f | 162 | |
AnnaBridge | 184:08ed48f1de7f | 163 | void rtc_write(time_t t) |
AnnaBridge | 184:08ed48f1de7f | 164 | { |
AnnaBridge | 184:08ed48f1de7f | 165 | if (! rtc_isenabled()) { |
AnnaBridge | 184:08ed48f1de7f | 166 | rtc_init(); |
AnnaBridge | 184:08ed48f1de7f | 167 | } |
AnnaBridge | 184:08ed48f1de7f | 168 | |
AnnaBridge | 184:08ed48f1de7f | 169 | t_write = t; |
AnnaBridge | 184:08ed48f1de7f | 170 | |
Anna Bridge |
186:707f6e361f3e | 171 | /* Store t_write to RTC spare register to cross reset cycle */ |
Anna Bridge |
186:707f6e361f3e | 172 | RTC_WaitAccessEnable(); |
Anna Bridge |
186:707f6e361f3e | 173 | RTC_WRITE_SPARE_REGISTER(0, t_write); |
Anna Bridge |
186:707f6e361f3e | 174 | RTC_WaitAccessEnable(); |
Anna Bridge |
186:707f6e361f3e | 175 | while (! (RTC->SPRCTL & RTC_SPRCTL_SPRRDY_Msk)); |
Anna Bridge |
186:707f6e361f3e | 176 | |
Anna Bridge |
186:707f6e361f3e | 177 | RTC_WaitAccessEnable(); |
AnnaBridge | 184:08ed48f1de7f | 178 | RTC_SetDateAndTime((S_RTC_TIME_DATA_T *) &DATETIME_HWRTC_ORIGIN); |
AnnaBridge | 184:08ed48f1de7f | 179 | /* NOTE: When engine is clocked by low power clock source (LXT/LIRC), we need to wait for 3 engine clocks. */ |
AnnaBridge | 184:08ed48f1de7f | 180 | wait_us((NU_US_PER_SEC / NU_RTCCLK_PER_SEC) * 3); |
AnnaBridge | 184:08ed48f1de7f | 181 | } |
AnnaBridge | 184:08ed48f1de7f | 182 | |
AnnaBridge | 174:b96e65c34a4d | 183 | /* |
AnnaBridge | 174:b96e65c34a4d | 184 | struct tm |
AnnaBridge | 174:b96e65c34a4d | 185 | tm_sec seconds after the minute 0-61 |
AnnaBridge | 174:b96e65c34a4d | 186 | tm_min minutes after the hour 0-59 |
AnnaBridge | 174:b96e65c34a4d | 187 | tm_hour hours since midnight 0-23 |
AnnaBridge | 174:b96e65c34a4d | 188 | tm_mday day of the month 1-31 |
AnnaBridge | 174:b96e65c34a4d | 189 | tm_mon months since January 0-11 |
AnnaBridge | 174:b96e65c34a4d | 190 | tm_year years since 1900 |
AnnaBridge | 174:b96e65c34a4d | 191 | tm_wday days since Sunday 0-6 |
AnnaBridge | 174:b96e65c34a4d | 192 | tm_yday days since January 1 0-365 |
AnnaBridge | 174:b96e65c34a4d | 193 | tm_isdst Daylight Saving Time flag |
AnnaBridge | 174:b96e65c34a4d | 194 | */ |
AnnaBridge | 184:08ed48f1de7f | 195 | static void rtc_convert_datetime_hwrtc_to_tm(struct tm *datetime_tm, const S_RTC_TIME_DATA_T *datetime_hwrtc) |
AnnaBridge | 174:b96e65c34a4d | 196 | { |
AnnaBridge | 184:08ed48f1de7f | 197 | datetime_tm->tm_year = datetime_hwrtc->u32Year - NU_TM_YEAR0; |
AnnaBridge | 184:08ed48f1de7f | 198 | datetime_tm->tm_mon = datetime_hwrtc->u32Month - 1; |
AnnaBridge | 184:08ed48f1de7f | 199 | datetime_tm->tm_mday = datetime_hwrtc->u32Day; |
AnnaBridge | 184:08ed48f1de7f | 200 | datetime_tm->tm_wday = datetime_hwrtc->u32DayOfWeek; |
AnnaBridge | 184:08ed48f1de7f | 201 | datetime_tm->tm_hour = datetime_hwrtc->u32Hour; |
AnnaBridge | 184:08ed48f1de7f | 202 | if (datetime_hwrtc->u32TimeScale == RTC_CLOCK_12 && datetime_hwrtc->u32AmPm == RTC_PM) { |
AnnaBridge | 184:08ed48f1de7f | 203 | datetime_tm->tm_hour += 12; |
AnnaBridge | 176:447f873cad2f | 204 | } |
AnnaBridge | 184:08ed48f1de7f | 205 | datetime_tm->tm_min = datetime_hwrtc->u32Minute; |
AnnaBridge | 184:08ed48f1de7f | 206 | datetime_tm->tm_sec = datetime_hwrtc->u32Second; |
AnnaBridge | 174:b96e65c34a4d | 207 | } |
AnnaBridge | 174:b96e65c34a4d | 208 | |
AnnaBridge | 174:b96e65c34a4d | 209 | #endif |
AnnaBridge | 184:08ed48f1de7f | 210 |