Skip to content

Commit ec7a13d

Browse files
authored
Merge pull request #6049 from OpenNuvoton/nuvoton_rtc
Nuvoton: Rework RTC
2 parents df4ceee + 0271df1 commit ec7a13d

File tree

4 files changed

+481
-239
lines changed

4 files changed

+481
-239
lines changed

targets/TARGET_NUVOTON/TARGET_M451/rtc_api.c

Lines changed: 121 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
* See the License for the specific language governing permissions and
1414
* limitations under the License.
1515
*/
16-
16+
1717
#include "rtc_api.h"
1818

1919
#if DEVICE_RTC
@@ -24,8 +24,65 @@
2424
#include "nu_miscutil.h"
2525
#include "mbed_mktime.h"
2626

27-
#define YEAR0 1900
28-
//#define EPOCH_YR 1970
27+
/* Micro seconds per second */
28+
#define NU_US_PER_SEC 1000000
29+
/* Timer clock per second
30+
*
31+
* NOTE: This dependents on real hardware.
32+
*/
33+
#define NU_RTCCLK_PER_SEC ((CLK->CLKSEL3 & CLK_CLKSEL3_SC0SEL_Msk) ? __LIRC : __LXT)
34+
35+
/* Strategy for implementation of RTC HAL
36+
*
37+
* H/W RTC just supports year range 2000~2099, which cannot fully cover POSIX time (starting since 2970)
38+
* and date time of struct TM (starting since 1900).
39+
*
40+
* To conquer the difficulty, we don't use H/W RTC to keep real date time. Instead, we use it to keep
41+
* elapsed time in seconds since one reference time point. The strategy would be:
42+
*
43+
* 1. Choose DATETIME_HWRTC_ORIGIN (00:00:00 UTC, Saturday, 1 January 2000) as reference time point of H/W RTC.
44+
* 2. t_hwrtc_origin = DATETIME_HWRTC_ORIGIN in POSIX time
45+
* 3. t_hwrtc_elapsed = t_hwrtc_origin + elapsed time since t_hwrtc_origin
46+
* 4. t_write = POSIX time set by rtc_write().
47+
* 5. t_present = rtc_read() = t_write + (t_hwrtc_elapsed - t_hwrtc_origin)
48+
*
49+
* 1900
50+
* |---------------------------------------------------------------------------------|
51+
* 1970 t_write t_present
52+
* |---------|-------|-----------------|---------------------------------------------|
53+
*
54+
* 2000
55+
* |-----------------|---------------------------------------------------------------|
56+
* t_hwrtc_origin t_hwrtc_elapsed
57+
*
58+
*/
59+
/* Start year of struct TM*/
60+
#define NU_TM_YEAR0 1900
61+
/* Start year of POSIX time (set_time()/time()) */
62+
#define NU_POSIX_YEAR0 1970
63+
/* Start year of H/W RTC */
64+
#define NU_HWRTC_YEAR0 2000
65+
66+
/* RTC H/W origin time: 00:00:00 UTC, Saturday, 1 January 2000 */
67+
static const S_RTC_TIME_DATA_T DATETIME_HWRTC_ORIGIN = {
68+
2000, /* Year value, range between 2000 ~ 2099 */
69+
1, /* Month value, range between 1 ~ 12 */
70+
1, /* Day value, range between 1 ~ 31 */
71+
RTC_SATURDAY, /* Day of the week */
72+
0, /* Hour value, range between 0 ~ 23 */
73+
0, /* Minute value, range between 0 ~ 59 */
74+
0, /* Second value, range between 0 ~ 59 */
75+
RTC_CLOCK_24, /* 12-Hour (RTC_CLOCK_12) / 24-Hour (RTC_CLOCK_24) */
76+
0 /* RTC_AM / RTC_PM (used only for 12-Hour) */
77+
};
78+
/* t_hwrtc_origin initialized or not? */
79+
static bool t_hwrtc_origin_inited = 0;
80+
/* POSIX time of DATETIME_HWRTC_ORIGIN (since 00:00:00 UTC, Thursday, 1 January 1970) */
81+
static time_t t_hwrtc_origin = 0;
82+
/* POSIX time set by rtc_write() */
83+
static time_t t_write = 0;
84+
/* Convert date time from H/W RTC to struct TM */
85+
static void rtc_convert_datetime_hwrtc_to_tm(struct tm *datetime_tm, const S_RTC_TIME_DATA_T *datetime_hwrtc);
2986

3087
static const struct nu_modinit_s rtc_modinit = {RTC_0, RTC_MODULE, 0, 0, 0, RTC_IRQn, NULL};
3188

@@ -34,8 +91,11 @@ void rtc_init(void)
3491
if (rtc_isenabled()) {
3592
return;
3693
}
37-
94+
3895
RTC_Open(NULL);
96+
97+
/* POSIX time origin (00:00:00 UTC, Thursday, 1 January 1970) */
98+
rtc_write(0);
3999
}
40100

41101
void rtc_free(void)
@@ -50,56 +110,47 @@ int rtc_isenabled(void)
50110
// Enable IP clock
51111
CLK_EnableModuleClock(rtc_modinit.clkidx);
52112
}
53-
113+
54114
// NOTE: Check RTC Init Active flag to support crossing reset cycle.
55115
return !! (RTC->INIT & RTC_INIT_ACTIVE_Msk);
56116
}
57117

58-
/*
59-
struct tm
60-
tm_sec seconds after the minute 0-61
61-
tm_min minutes after the hour 0-59
62-
tm_hour hours since midnight 0-23
63-
tm_mday day of the month 1-31
64-
tm_mon months since January 0-11
65-
tm_year years since 1900
66-
tm_wday days since Sunday 0-6
67-
tm_yday days since January 1 0-365
68-
tm_isdst Daylight Saving Time flag
69-
*/
70-
71118
time_t rtc_read(void)
72119
{
73-
// NOTE: After boot, RTC time registers are not synced immediately, about 1 sec latency.
74-
// RTC time got (through RTC_GetDateAndTime()) in this sec would be last-synced and incorrect.
120+
/* NOTE: After boot, RTC time registers are not synced immediately, about 1 sec latency.
121+
* RTC time got (through RTC_GetDateAndTime()) in this sec would be last-synced and incorrect.
122+
*/
75123
if (! rtc_isenabled()) {
76124
rtc_init();
77125
}
78-
79-
S_RTC_TIME_DATA_T rtc_datetime;
80-
RTC_GetDateAndTime(&rtc_datetime);
81-
82-
struct tm timeinfo;
83-
84-
// Convert struct tm to S_RTC_TIME_DATA_T
85-
timeinfo.tm_year = rtc_datetime.u32Year - YEAR0;
86-
timeinfo.tm_mon = rtc_datetime.u32Month - 1;
87-
timeinfo.tm_mday = rtc_datetime.u32Day;
88-
timeinfo.tm_wday = rtc_datetime.u32DayOfWeek;
89-
timeinfo.tm_hour = rtc_datetime.u32Hour;
90-
if (rtc_datetime.u32TimeScale == RTC_CLOCK_12 && rtc_datetime.u32AmPm == RTC_PM) {
91-
timeinfo.tm_hour += 12;
126+
127+
/* Used for intermediary between date time of H/W RTC and POSIX time */
128+
struct tm datetime_tm;
129+
130+
if (! t_hwrtc_origin_inited) {
131+
t_hwrtc_origin_inited = 1;
132+
133+
/* Convert date time from H/W RTC to struct TM */
134+
rtc_convert_datetime_hwrtc_to_tm(&datetime_tm, &DATETIME_HWRTC_ORIGIN);
135+
/* Convert date time of struct TM to POSIX time */
136+
if (! _rtc_maketime(&datetime_tm, &t_hwrtc_origin, RTC_FULL_LEAP_YEAR_SUPPORT)) {
137+
return 0;
138+
}
92139
}
93-
timeinfo.tm_min = rtc_datetime.u32Minute;
94-
timeinfo.tm_sec = rtc_datetime.u32Second;
95140

96-
// Convert to timestamp
97-
time_t t;
98-
if (_rtc_maketime(&timeinfo, &t, RTC_FULL_LEAP_YEAR_SUPPORT) == false) {
141+
S_RTC_TIME_DATA_T hwrtc_datetime_2K_present;
142+
RTC_GetDateAndTime(&hwrtc_datetime_2K_present);
143+
/* Convert date time from H/W RTC to struct TM */
144+
rtc_convert_datetime_hwrtc_to_tm(&datetime_tm, &hwrtc_datetime_2K_present);
145+
/* Convert date time of struct TM to POSIX time */
146+
time_t t_hwrtc_elapsed;
147+
if (! _rtc_maketime(&datetime_tm, &t_hwrtc_elapsed, RTC_FULL_LEAP_YEAR_SUPPORT)) {
99148
return 0;
100149
}
101150

102-
return t;
151+
/* Present time in POSIX time */
152+
time_t t_present = t_write + (t_hwrtc_elapsed - t_hwrtc_origin);
153+
return t_present;
103154
}
104155

105156
void rtc_write(time_t t)
@@ -108,28 +159,37 @@ void rtc_write(time_t t)
108159
rtc_init();
109160
}
110161

111-
// Convert timestamp to struct tm
112-
struct tm timeinfo;
113-
if (_rtc_localtime(t, &timeinfo, RTC_FULL_LEAP_YEAR_SUPPORT) == false) {
114-
return;
115-
}
162+
t_write = t;
116163

117-
S_RTC_TIME_DATA_T rtc_datetime;
118-
119-
// Convert S_RTC_TIME_DATA_T to struct tm
120-
rtc_datetime.u32Year = timeinfo.tm_year + YEAR0;
121-
rtc_datetime.u32Month = timeinfo.tm_mon + 1;
122-
rtc_datetime.u32Day = timeinfo.tm_mday;
123-
rtc_datetime.u32DayOfWeek = timeinfo.tm_wday;
124-
rtc_datetime.u32Hour = timeinfo.tm_hour;
125-
rtc_datetime.u32Minute = timeinfo.tm_min;
126-
rtc_datetime.u32Second = timeinfo.tm_sec;
127-
rtc_datetime.u32TimeScale = RTC_CLOCK_24;
128-
129-
// NOTE: Timing issue with write to RTC registers. This delay is empirical, not rational.
130-
RTC_SetDateAndTime(&rtc_datetime);
131-
//nu_nop(6000);
132-
wait_us(100);
164+
RTC_SetDateAndTime((S_RTC_TIME_DATA_T *) &DATETIME_HWRTC_ORIGIN);
165+
/* NOTE: When engine is clocked by low power clock source (LXT/LIRC), we need to wait for 3 engine clocks. */
166+
wait_us((NU_US_PER_SEC / NU_RTCCLK_PER_SEC) * 3);
167+
}
168+
169+
/*
170+
struct tm
171+
tm_sec seconds after the minute 0-61
172+
tm_min minutes after the hour 0-59
173+
tm_hour hours since midnight 0-23
174+
tm_mday day of the month 1-31
175+
tm_mon months since January 0-11
176+
tm_year years since 1900
177+
tm_wday days since Sunday 0-6
178+
tm_yday days since January 1 0-365
179+
tm_isdst Daylight Saving Time flag
180+
*/
181+
static void rtc_convert_datetime_hwrtc_to_tm(struct tm *datetime_tm, const S_RTC_TIME_DATA_T *datetime_hwrtc)
182+
{
183+
datetime_tm->tm_year = datetime_hwrtc->u32Year - NU_TM_YEAR0;
184+
datetime_tm->tm_mon = datetime_hwrtc->u32Month - 1;
185+
datetime_tm->tm_mday = datetime_hwrtc->u32Day;
186+
datetime_tm->tm_wday = datetime_hwrtc->u32DayOfWeek;
187+
datetime_tm->tm_hour = datetime_hwrtc->u32Hour;
188+
if (datetime_hwrtc->u32TimeScale == RTC_CLOCK_12 && datetime_hwrtc->u32AmPm == RTC_PM) {
189+
datetime_tm->tm_hour += 12;
190+
}
191+
datetime_tm->tm_min = datetime_hwrtc->u32Minute;
192+
datetime_tm->tm_sec = datetime_hwrtc->u32Second;
133193
}
134194

135195
#endif

0 commit comments

Comments
 (0)