mirror of https://github.com/ARMmbed/mbed-os.git
commit
ec7a13de62
|
@ -24,8 +24,65 @@
|
||||||
#include "nu_miscutil.h"
|
#include "nu_miscutil.h"
|
||||||
#include "mbed_mktime.h"
|
#include "mbed_mktime.h"
|
||||||
|
|
||||||
#define YEAR0 1900
|
/* Micro seconds per second */
|
||||||
//#define EPOCH_YR 1970
|
#define NU_US_PER_SEC 1000000
|
||||||
|
/* Timer clock per second
|
||||||
|
*
|
||||||
|
* NOTE: This dependents on real hardware.
|
||||||
|
*/
|
||||||
|
#define NU_RTCCLK_PER_SEC ((CLK->CLKSEL3 & CLK_CLKSEL3_SC0SEL_Msk) ? __LIRC : __LXT)
|
||||||
|
|
||||||
|
/* Strategy for implementation of RTC HAL
|
||||||
|
*
|
||||||
|
* H/W RTC just supports year range 2000~2099, which cannot fully cover POSIX time (starting since 2970)
|
||||||
|
* and date time of struct TM (starting since 1900).
|
||||||
|
*
|
||||||
|
* To conquer the difficulty, we don't use H/W RTC to keep real date time. Instead, we use it to keep
|
||||||
|
* elapsed time in seconds since one reference time point. The strategy would be:
|
||||||
|
*
|
||||||
|
* 1. Choose DATETIME_HWRTC_ORIGIN (00:00:00 UTC, Saturday, 1 January 2000) as reference time point of H/W RTC.
|
||||||
|
* 2. t_hwrtc_origin = DATETIME_HWRTC_ORIGIN in POSIX time
|
||||||
|
* 3. t_hwrtc_elapsed = t_hwrtc_origin + elapsed time since t_hwrtc_origin
|
||||||
|
* 4. t_write = POSIX time set by rtc_write().
|
||||||
|
* 5. t_present = rtc_read() = t_write + (t_hwrtc_elapsed - t_hwrtc_origin)
|
||||||
|
*
|
||||||
|
* 1900
|
||||||
|
* |---------------------------------------------------------------------------------|
|
||||||
|
* 1970 t_write t_present
|
||||||
|
* |---------|-------|-----------------|---------------------------------------------|
|
||||||
|
*
|
||||||
|
* 2000
|
||||||
|
* |-----------------|---------------------------------------------------------------|
|
||||||
|
* t_hwrtc_origin t_hwrtc_elapsed
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
/* Start year of struct TM*/
|
||||||
|
#define NU_TM_YEAR0 1900
|
||||||
|
/* Start year of POSIX time (set_time()/time()) */
|
||||||
|
#define NU_POSIX_YEAR0 1970
|
||||||
|
/* Start year of H/W RTC */
|
||||||
|
#define NU_HWRTC_YEAR0 2000
|
||||||
|
|
||||||
|
/* RTC H/W origin time: 00:00:00 UTC, Saturday, 1 January 2000 */
|
||||||
|
static const S_RTC_TIME_DATA_T DATETIME_HWRTC_ORIGIN = {
|
||||||
|
2000, /* Year value, range between 2000 ~ 2099 */
|
||||||
|
1, /* Month value, range between 1 ~ 12 */
|
||||||
|
1, /* Day value, range between 1 ~ 31 */
|
||||||
|
RTC_SATURDAY, /* Day of the week */
|
||||||
|
0, /* Hour value, range between 0 ~ 23 */
|
||||||
|
0, /* Minute value, range between 0 ~ 59 */
|
||||||
|
0, /* Second value, range between 0 ~ 59 */
|
||||||
|
RTC_CLOCK_24, /* 12-Hour (RTC_CLOCK_12) / 24-Hour (RTC_CLOCK_24) */
|
||||||
|
0 /* RTC_AM / RTC_PM (used only for 12-Hour) */
|
||||||
|
};
|
||||||
|
/* t_hwrtc_origin initialized or not? */
|
||||||
|
static bool t_hwrtc_origin_inited = 0;
|
||||||
|
/* POSIX time of DATETIME_HWRTC_ORIGIN (since 00:00:00 UTC, Thursday, 1 January 1970) */
|
||||||
|
static time_t t_hwrtc_origin = 0;
|
||||||
|
/* POSIX time set by rtc_write() */
|
||||||
|
static time_t t_write = 0;
|
||||||
|
/* Convert date time from H/W RTC to struct TM */
|
||||||
|
static void rtc_convert_datetime_hwrtc_to_tm(struct tm *datetime_tm, const S_RTC_TIME_DATA_T *datetime_hwrtc);
|
||||||
|
|
||||||
static const struct nu_modinit_s rtc_modinit = {RTC_0, RTC_MODULE, 0, 0, 0, RTC_IRQn, NULL};
|
static const struct nu_modinit_s rtc_modinit = {RTC_0, RTC_MODULE, 0, 0, 0, RTC_IRQn, NULL};
|
||||||
|
|
||||||
|
@ -36,6 +93,9 @@ void rtc_init(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
RTC_Open(NULL);
|
RTC_Open(NULL);
|
||||||
|
|
||||||
|
/* POSIX time origin (00:00:00 UTC, Thursday, 1 January 1970) */
|
||||||
|
rtc_write(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void rtc_free(void)
|
void rtc_free(void)
|
||||||
|
@ -55,6 +115,57 @@ int rtc_isenabled(void)
|
||||||
return !! (RTC->INIT & RTC_INIT_ACTIVE_Msk);
|
return !! (RTC->INIT & RTC_INIT_ACTIVE_Msk);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
time_t rtc_read(void)
|
||||||
|
{
|
||||||
|
/* NOTE: After boot, RTC time registers are not synced immediately, about 1 sec latency.
|
||||||
|
* RTC time got (through RTC_GetDateAndTime()) in this sec would be last-synced and incorrect.
|
||||||
|
*/
|
||||||
|
if (! rtc_isenabled()) {
|
||||||
|
rtc_init();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Used for intermediary between date time of H/W RTC and POSIX time */
|
||||||
|
struct tm datetime_tm;
|
||||||
|
|
||||||
|
if (! t_hwrtc_origin_inited) {
|
||||||
|
t_hwrtc_origin_inited = 1;
|
||||||
|
|
||||||
|
/* Convert date time from H/W RTC to struct TM */
|
||||||
|
rtc_convert_datetime_hwrtc_to_tm(&datetime_tm, &DATETIME_HWRTC_ORIGIN);
|
||||||
|
/* Convert date time of struct TM to POSIX time */
|
||||||
|
if (! _rtc_maketime(&datetime_tm, &t_hwrtc_origin, RTC_FULL_LEAP_YEAR_SUPPORT)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
S_RTC_TIME_DATA_T hwrtc_datetime_2K_present;
|
||||||
|
RTC_GetDateAndTime(&hwrtc_datetime_2K_present);
|
||||||
|
/* Convert date time from H/W RTC to struct TM */
|
||||||
|
rtc_convert_datetime_hwrtc_to_tm(&datetime_tm, &hwrtc_datetime_2K_present);
|
||||||
|
/* Convert date time of struct TM to POSIX time */
|
||||||
|
time_t t_hwrtc_elapsed;
|
||||||
|
if (! _rtc_maketime(&datetime_tm, &t_hwrtc_elapsed, RTC_FULL_LEAP_YEAR_SUPPORT)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Present time in POSIX time */
|
||||||
|
time_t t_present = t_write + (t_hwrtc_elapsed - t_hwrtc_origin);
|
||||||
|
return t_present;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rtc_write(time_t t)
|
||||||
|
{
|
||||||
|
if (! rtc_isenabled()) {
|
||||||
|
rtc_init();
|
||||||
|
}
|
||||||
|
|
||||||
|
t_write = t;
|
||||||
|
|
||||||
|
RTC_SetDateAndTime((S_RTC_TIME_DATA_T *) &DATETIME_HWRTC_ORIGIN);
|
||||||
|
/* NOTE: When engine is clocked by low power clock source (LXT/LIRC), we need to wait for 3 engine clocks. */
|
||||||
|
wait_us((NU_US_PER_SEC / NU_RTCCLK_PER_SEC) * 3);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
struct tm
|
struct tm
|
||||||
tm_sec seconds after the minute 0-61
|
tm_sec seconds after the minute 0-61
|
||||||
|
@ -67,69 +178,18 @@ int rtc_isenabled(void)
|
||||||
tm_yday days since January 1 0-365
|
tm_yday days since January 1 0-365
|
||||||
tm_isdst Daylight Saving Time flag
|
tm_isdst Daylight Saving Time flag
|
||||||
*/
|
*/
|
||||||
|
static void rtc_convert_datetime_hwrtc_to_tm(struct tm *datetime_tm, const S_RTC_TIME_DATA_T *datetime_hwrtc)
|
||||||
time_t rtc_read(void)
|
|
||||||
{
|
{
|
||||||
// NOTE: After boot, RTC time registers are not synced immediately, about 1 sec latency.
|
datetime_tm->tm_year = datetime_hwrtc->u32Year - NU_TM_YEAR0;
|
||||||
// RTC time got (through RTC_GetDateAndTime()) in this sec would be last-synced and incorrect.
|
datetime_tm->tm_mon = datetime_hwrtc->u32Month - 1;
|
||||||
if (! rtc_isenabled()) {
|
datetime_tm->tm_mday = datetime_hwrtc->u32Day;
|
||||||
rtc_init();
|
datetime_tm->tm_wday = datetime_hwrtc->u32DayOfWeek;
|
||||||
|
datetime_tm->tm_hour = datetime_hwrtc->u32Hour;
|
||||||
|
if (datetime_hwrtc->u32TimeScale == RTC_CLOCK_12 && datetime_hwrtc->u32AmPm == RTC_PM) {
|
||||||
|
datetime_tm->tm_hour += 12;
|
||||||
}
|
}
|
||||||
|
datetime_tm->tm_min = datetime_hwrtc->u32Minute;
|
||||||
S_RTC_TIME_DATA_T rtc_datetime;
|
datetime_tm->tm_sec = datetime_hwrtc->u32Second;
|
||||||
RTC_GetDateAndTime(&rtc_datetime);
|
|
||||||
|
|
||||||
struct tm timeinfo;
|
|
||||||
|
|
||||||
// Convert struct tm to S_RTC_TIME_DATA_T
|
|
||||||
timeinfo.tm_year = rtc_datetime.u32Year - YEAR0;
|
|
||||||
timeinfo.tm_mon = rtc_datetime.u32Month - 1;
|
|
||||||
timeinfo.tm_mday = rtc_datetime.u32Day;
|
|
||||||
timeinfo.tm_wday = rtc_datetime.u32DayOfWeek;
|
|
||||||
timeinfo.tm_hour = rtc_datetime.u32Hour;
|
|
||||||
if (rtc_datetime.u32TimeScale == RTC_CLOCK_12 && rtc_datetime.u32AmPm == RTC_PM) {
|
|
||||||
timeinfo.tm_hour += 12;
|
|
||||||
}
|
|
||||||
timeinfo.tm_min = rtc_datetime.u32Minute;
|
|
||||||
timeinfo.tm_sec = rtc_datetime.u32Second;
|
|
||||||
|
|
||||||
// Convert to timestamp
|
|
||||||
time_t t;
|
|
||||||
if (_rtc_maketime(&timeinfo, &t, RTC_FULL_LEAP_YEAR_SUPPORT) == false) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
|
|
||||||
void rtc_write(time_t t)
|
|
||||||
{
|
|
||||||
if (! rtc_isenabled()) {
|
|
||||||
rtc_init();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert timestamp to struct tm
|
|
||||||
struct tm timeinfo;
|
|
||||||
if (_rtc_localtime(t, &timeinfo, RTC_FULL_LEAP_YEAR_SUPPORT) == false) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
S_RTC_TIME_DATA_T rtc_datetime;
|
|
||||||
|
|
||||||
// Convert S_RTC_TIME_DATA_T to struct tm
|
|
||||||
rtc_datetime.u32Year = timeinfo.tm_year + YEAR0;
|
|
||||||
rtc_datetime.u32Month = timeinfo.tm_mon + 1;
|
|
||||||
rtc_datetime.u32Day = timeinfo.tm_mday;
|
|
||||||
rtc_datetime.u32DayOfWeek = timeinfo.tm_wday;
|
|
||||||
rtc_datetime.u32Hour = timeinfo.tm_hour;
|
|
||||||
rtc_datetime.u32Minute = timeinfo.tm_min;
|
|
||||||
rtc_datetime.u32Second = timeinfo.tm_sec;
|
|
||||||
rtc_datetime.u32TimeScale = RTC_CLOCK_24;
|
|
||||||
|
|
||||||
// NOTE: Timing issue with write to RTC registers. This delay is empirical, not rational.
|
|
||||||
RTC_SetDateAndTime(&rtc_datetime);
|
|
||||||
//nu_nop(6000);
|
|
||||||
wait_us(100);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -24,8 +24,65 @@
|
||||||
#include "nu_miscutil.h"
|
#include "nu_miscutil.h"
|
||||||
#include "mbed_mktime.h"
|
#include "mbed_mktime.h"
|
||||||
|
|
||||||
#define YEAR0 1900
|
/* Micro seconds per second */
|
||||||
//#define EPOCH_YR 1970
|
#define NU_US_PER_SEC 1000000
|
||||||
|
/* Timer clock per second
|
||||||
|
*
|
||||||
|
* NOTE: This dependents on real hardware.
|
||||||
|
*/
|
||||||
|
#define NU_RTCCLK_PER_SEC ((CLK->CLKSEL3 & CLK_CLKSEL3_SC0SEL_Msk) ? __LIRC : __LXT)
|
||||||
|
|
||||||
|
/* Strategy for implementation of RTC HAL
|
||||||
|
*
|
||||||
|
* H/W RTC just supports year range 2000~2099, which cannot fully cover POSIX time (starting since 2970)
|
||||||
|
* and date time of struct TM (starting since 1900).
|
||||||
|
*
|
||||||
|
* To conquer the difficulty, we don't use H/W RTC to keep real date time. Instead, we use it to keep
|
||||||
|
* elapsed time in seconds since one reference time point. The strategy would be:
|
||||||
|
*
|
||||||
|
* 1. Choose DATETIME_HWRTC_ORIGIN (00:00:00 UTC, Saturday, 1 January 2000) as reference time point of H/W RTC.
|
||||||
|
* 2. t_hwrtc_origin = DATETIME_HWRTC_ORIGIN in POSIX time
|
||||||
|
* 3. t_hwrtc_elapsed = t_hwrtc_origin + elapsed time since t_hwrtc_origin
|
||||||
|
* 4. t_write = POSIX time set by rtc_write().
|
||||||
|
* 5. t_present = rtc_read() = t_write + (t_hwrtc_elapsed - t_hwrtc_origin)
|
||||||
|
*
|
||||||
|
* 1900
|
||||||
|
* |---------------------------------------------------------------------------------|
|
||||||
|
* 1970 t_write t_present
|
||||||
|
* |---------|-------|-----------------|---------------------------------------------|
|
||||||
|
*
|
||||||
|
* 2000
|
||||||
|
* |-----------------|---------------------------------------------------------------|
|
||||||
|
* t_hwrtc_origin t_hwrtc_elapsed
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
/* Start year of struct TM*/
|
||||||
|
#define NU_TM_YEAR0 1900
|
||||||
|
/* Start year of POSIX time (set_time()/time()) */
|
||||||
|
#define NU_POSIX_YEAR0 1970
|
||||||
|
/* Start year of H/W RTC */
|
||||||
|
#define NU_HWRTC_YEAR0 2000
|
||||||
|
|
||||||
|
/* RTC H/W origin time: 00:00:00 UTC, Saturday, 1 January 2000 */
|
||||||
|
static const S_RTC_TIME_DATA_T DATETIME_HWRTC_ORIGIN = {
|
||||||
|
2000, /* Year value, range between 2000 ~ 2099 */
|
||||||
|
1, /* Month value, range between 1 ~ 12 */
|
||||||
|
1, /* Day value, range between 1 ~ 31 */
|
||||||
|
RTC_SATURDAY, /* Day of the week */
|
||||||
|
0, /* Hour value, range between 0 ~ 23 */
|
||||||
|
0, /* Minute value, range between 0 ~ 59 */
|
||||||
|
0, /* Second value, range between 0 ~ 59 */
|
||||||
|
RTC_CLOCK_24, /* 12-Hour (RTC_CLOCK_12) / 24-Hour (RTC_CLOCK_24) */
|
||||||
|
0 /* RTC_AM / RTC_PM (used only for 12-Hour) */
|
||||||
|
};
|
||||||
|
/* t_hwrtc_origin initialized or not? */
|
||||||
|
static bool t_hwrtc_origin_inited = 0;
|
||||||
|
/* POSIX time of DATETIME_HWRTC_ORIGIN (since 00:00:00 UTC, Thursday, 1 January 1970) */
|
||||||
|
static time_t t_hwrtc_origin = 0;
|
||||||
|
/* POSIX time set by rtc_write() */
|
||||||
|
static time_t t_write = 0;
|
||||||
|
/* Convert date time from H/W RTC to struct TM */
|
||||||
|
static void rtc_convert_datetime_hwrtc_to_tm(struct tm *datetime_tm, const S_RTC_TIME_DATA_T *datetime_hwrtc);
|
||||||
|
|
||||||
static const struct nu_modinit_s rtc_modinit = {RTC_0, RTC_MODULE, 0, 0, 0, RTC_IRQn, NULL};
|
static const struct nu_modinit_s rtc_modinit = {RTC_0, RTC_MODULE, 0, 0, 0, RTC_IRQn, NULL};
|
||||||
|
|
||||||
|
@ -36,6 +93,9 @@ void rtc_init(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
RTC_Open(NULL);
|
RTC_Open(NULL);
|
||||||
|
|
||||||
|
/* POSIX time origin (00:00:00 UTC, Thursday, 1 January 1970) */
|
||||||
|
rtc_write(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void rtc_free(void)
|
void rtc_free(void)
|
||||||
|
@ -54,6 +114,58 @@ int rtc_isenabled(void)
|
||||||
// NOTE: Check RTC Init Active flag to support crossing reset cycle.
|
// NOTE: Check RTC Init Active flag to support crossing reset cycle.
|
||||||
return !! (RTC->INIT & RTC_INIT_ACTIVE_Msk);
|
return !! (RTC->INIT & RTC_INIT_ACTIVE_Msk);
|
||||||
}
|
}
|
||||||
|
time_t rtc_read(void)
|
||||||
|
{
|
||||||
|
/* NOTE: After boot, RTC time registers are not synced immediately, about 1 sec latency.
|
||||||
|
* RTC time got (through RTC_GetDateAndTime()) in this sec would be last-synced and incorrect.
|
||||||
|
* NUC472/M453: Known issue
|
||||||
|
* M487: Fixed
|
||||||
|
*/
|
||||||
|
if (! rtc_isenabled()) {
|
||||||
|
rtc_init();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Used for intermediary between date time of H/W RTC and POSIX time */
|
||||||
|
struct tm datetime_tm;
|
||||||
|
|
||||||
|
if (! t_hwrtc_origin_inited) {
|
||||||
|
t_hwrtc_origin_inited = 1;
|
||||||
|
|
||||||
|
/* Convert date time from H/W RTC to struct TM */
|
||||||
|
rtc_convert_datetime_hwrtc_to_tm(&datetime_tm, &DATETIME_HWRTC_ORIGIN);
|
||||||
|
/* Convert date time of struct TM to POSIX time */
|
||||||
|
if (! _rtc_maketime(&datetime_tm, &t_hwrtc_origin, RTC_FULL_LEAP_YEAR_SUPPORT)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
S_RTC_TIME_DATA_T hwrtc_datetime_2K_present;
|
||||||
|
RTC_GetDateAndTime(&hwrtc_datetime_2K_present);
|
||||||
|
/* Convert date time from H/W RTC to struct TM */
|
||||||
|
rtc_convert_datetime_hwrtc_to_tm(&datetime_tm, &hwrtc_datetime_2K_present);
|
||||||
|
/* Convert date time of struct TM to POSIX time */
|
||||||
|
time_t t_hwrtc_elapsed;
|
||||||
|
if (! _rtc_maketime(&datetime_tm, &t_hwrtc_elapsed, RTC_FULL_LEAP_YEAR_SUPPORT)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Present time in POSIX time */
|
||||||
|
time_t t_present = t_write + (t_hwrtc_elapsed - t_hwrtc_origin);
|
||||||
|
return t_present;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rtc_write(time_t t)
|
||||||
|
{
|
||||||
|
if (! rtc_isenabled()) {
|
||||||
|
rtc_init();
|
||||||
|
}
|
||||||
|
|
||||||
|
t_write = t;
|
||||||
|
|
||||||
|
RTC_SetDateAndTime((S_RTC_TIME_DATA_T *) &DATETIME_HWRTC_ORIGIN);
|
||||||
|
/* NOTE: When engine is clocked by low power clock source (LXT/LIRC), we need to wait for 3 engine clocks. */
|
||||||
|
wait_us((NU_US_PER_SEC / NU_RTCCLK_PER_SEC) * 3);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
struct tm
|
struct tm
|
||||||
|
@ -67,70 +179,18 @@ int rtc_isenabled(void)
|
||||||
tm_yday days since January 1 0-365
|
tm_yday days since January 1 0-365
|
||||||
tm_isdst Daylight Saving Time flag
|
tm_isdst Daylight Saving Time flag
|
||||||
*/
|
*/
|
||||||
|
static void rtc_convert_datetime_hwrtc_to_tm(struct tm *datetime_tm, const S_RTC_TIME_DATA_T *datetime_hwrtc)
|
||||||
time_t rtc_read(void)
|
|
||||||
{
|
{
|
||||||
// NOTE: After boot, RTC time registers are not synced immediately, about 1 sec latency.
|
datetime_tm->tm_year = datetime_hwrtc->u32Year - NU_TM_YEAR0;
|
||||||
// RTC time got (through RTC_GetDateAndTime()) in this sec would be last-synced and incorrect.
|
datetime_tm->tm_mon = datetime_hwrtc->u32Month - 1;
|
||||||
// NUC472/M453: Known issue
|
datetime_tm->tm_mday = datetime_hwrtc->u32Day;
|
||||||
// M487: Fixed
|
datetime_tm->tm_wday = datetime_hwrtc->u32DayOfWeek;
|
||||||
if (! rtc_isenabled()) {
|
datetime_tm->tm_hour = datetime_hwrtc->u32Hour;
|
||||||
rtc_init();
|
if (datetime_hwrtc->u32TimeScale == RTC_CLOCK_12 && datetime_hwrtc->u32AmPm == RTC_PM) {
|
||||||
|
datetime_tm->tm_hour += 12;
|
||||||
}
|
}
|
||||||
|
datetime_tm->tm_min = datetime_hwrtc->u32Minute;
|
||||||
S_RTC_TIME_DATA_T rtc_datetime;
|
datetime_tm->tm_sec = datetime_hwrtc->u32Second;
|
||||||
RTC_GetDateAndTime(&rtc_datetime);
|
|
||||||
|
|
||||||
struct tm timeinfo;
|
|
||||||
|
|
||||||
// Convert struct tm to S_RTC_TIME_DATA_T
|
|
||||||
timeinfo.tm_year = rtc_datetime.u32Year - YEAR0;
|
|
||||||
timeinfo.tm_mon = rtc_datetime.u32Month - 1;
|
|
||||||
timeinfo.tm_mday = rtc_datetime.u32Day;
|
|
||||||
timeinfo.tm_wday = rtc_datetime.u32DayOfWeek;
|
|
||||||
timeinfo.tm_hour = rtc_datetime.u32Hour;
|
|
||||||
if (rtc_datetime.u32TimeScale == RTC_CLOCK_12 && rtc_datetime.u32AmPm == RTC_PM) {
|
|
||||||
timeinfo.tm_hour += 12;
|
|
||||||
}
|
|
||||||
timeinfo.tm_min = rtc_datetime.u32Minute;
|
|
||||||
timeinfo.tm_sec = rtc_datetime.u32Second;
|
|
||||||
|
|
||||||
// Convert to timestamp
|
|
||||||
time_t t;
|
|
||||||
if (_rtc_maketime(&timeinfo, &t, RTC_FULL_LEAP_YEAR_SUPPORT) == false) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
|
|
||||||
void rtc_write(time_t t)
|
|
||||||
{
|
|
||||||
if (! rtc_isenabled()) {
|
|
||||||
rtc_init();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert timestamp to struct tm
|
|
||||||
struct tm timeinfo;
|
|
||||||
if (_rtc_localtime(t, &timeinfo, RTC_FULL_LEAP_YEAR_SUPPORT) == false) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
S_RTC_TIME_DATA_T rtc_datetime;
|
|
||||||
|
|
||||||
// Convert S_RTC_TIME_DATA_T to struct tm
|
|
||||||
rtc_datetime.u32Year = timeinfo.tm_year + YEAR0;
|
|
||||||
rtc_datetime.u32Month = timeinfo.tm_mon + 1;
|
|
||||||
rtc_datetime.u32Day = timeinfo.tm_mday;
|
|
||||||
rtc_datetime.u32DayOfWeek = timeinfo.tm_wday;
|
|
||||||
rtc_datetime.u32Hour = timeinfo.tm_hour;
|
|
||||||
rtc_datetime.u32Minute = timeinfo.tm_min;
|
|
||||||
rtc_datetime.u32Second = timeinfo.tm_sec;
|
|
||||||
rtc_datetime.u32TimeScale = RTC_CLOCK_24;
|
|
||||||
|
|
||||||
// NOTE: Timing issue with write to RTC registers. This delay is empirical, not rational.
|
|
||||||
RTC_SetDateAndTime(&rtc_datetime);
|
|
||||||
wait_us(100);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -24,8 +24,65 @@
|
||||||
#include "nu_miscutil.h"
|
#include "nu_miscutil.h"
|
||||||
#include "mbed_mktime.h"
|
#include "mbed_mktime.h"
|
||||||
|
|
||||||
#define YEAR0 1900
|
/* Micro seconds per second */
|
||||||
|
#define NU_US_PER_SEC 1000000
|
||||||
|
/* Timer clock per second
|
||||||
|
*
|
||||||
|
* NOTE: This dependents on real hardware.
|
||||||
|
*/
|
||||||
|
#define NU_RTCCLK_PER_SEC (__LXT)
|
||||||
|
|
||||||
|
/* Strategy for implementation of RTC HAL
|
||||||
|
*
|
||||||
|
* H/W RTC just supports year range 2000~2099, which cannot fully cover POSIX time (starting since 2970)
|
||||||
|
* and date time of struct TM (starting since 1900).
|
||||||
|
*
|
||||||
|
* To conquer the difficulty, we don't use H/W RTC to keep real date time. Instead, we use it to keep
|
||||||
|
* elapsed time in seconds since one reference time point. The strategy would be:
|
||||||
|
*
|
||||||
|
* 1. Choose DATETIME_HWRTC_ORIGIN (00:00:00 UTC, Saturday, 1 January 2000) as reference time point of H/W RTC.
|
||||||
|
* 2. t_hwrtc_origin = DATETIME_HWRTC_ORIGIN in POSIX time
|
||||||
|
* 3. t_hwrtc_elapsed = t_hwrtc_origin + elapsed time since t_hwrtc_origin
|
||||||
|
* 4. t_write = POSIX time set by rtc_write().
|
||||||
|
* 5. t_present = rtc_read() = t_write + (t_hwrtc_elapsed - t_hwrtc_origin)
|
||||||
|
*
|
||||||
|
* 1900
|
||||||
|
* |---------------------------------------------------------------------------------|
|
||||||
|
* 1970 t_write t_present
|
||||||
|
* |---------|-------|-----------------|---------------------------------------------|
|
||||||
|
*
|
||||||
|
* 2000
|
||||||
|
* |-----------------|---------------------------------------------------------------|
|
||||||
|
* t_hwrtc_origin t_hwrtc_elapsed
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
/* Start year of struct TM*/
|
||||||
|
#define NU_TM_YEAR0 1900
|
||||||
|
/* Start year of POSIX time (set_time()/time()) */
|
||||||
|
#define NU_POSIX_YEAR0 1970
|
||||||
|
/* Start year of H/W RTC */
|
||||||
|
#define NU_HWRTC_YEAR0 2000
|
||||||
|
|
||||||
|
/* RTC H/W origin time: 00:00:00 UTC, Saturday, 1 January 2000 */
|
||||||
|
static const S_RTC_TIME_DATA_T DATETIME_HWRTC_ORIGIN = {
|
||||||
|
2000, /* Year value, range between 2000 ~ 2099 */
|
||||||
|
1, /* Month value, range between 1 ~ 12 */
|
||||||
|
1, /* Day value, range between 1 ~ 31 */
|
||||||
|
RTC_SATURDAY, /* Day of the week */
|
||||||
|
0, /* Hour value, range between 0 ~ 23 */
|
||||||
|
0, /* Minute value, range between 0 ~ 59 */
|
||||||
|
0, /* Second value, range between 0 ~ 59 */
|
||||||
|
RTC_CLOCK_24, /* 12-Hour (RTC_CLOCK_12) / 24-Hour (RTC_CLOCK_24) */
|
||||||
|
0 /* RTC_AM / RTC_PM (used only for 12-Hour) */
|
||||||
|
};
|
||||||
|
/* t_hwrtc_origin initialized or not? */
|
||||||
|
static bool t_hwrtc_origin_inited = 0;
|
||||||
|
/* POSIX time of DATETIME_HWRTC_ORIGIN (since 00:00:00 UTC, Thursday, 1 January 1970) */
|
||||||
|
static time_t t_hwrtc_origin = 0;
|
||||||
|
/* POSIX time set by rtc_write() */
|
||||||
|
static time_t t_write = 0;
|
||||||
|
/* Convert date time from H/W RTC to struct TM */
|
||||||
|
static void rtc_convert_datetime_hwrtc_to_tm(struct tm *datetime_tm, const S_RTC_TIME_DATA_T *datetime_hwrtc);
|
||||||
|
|
||||||
static const struct nu_modinit_s rtc_modinit = {RTC_0, RTC_MODULE, 0, 0, 0, RTC_IRQn, NULL};
|
static const struct nu_modinit_s rtc_modinit = {RTC_0, RTC_MODULE, 0, 0, 0, RTC_IRQn, NULL};
|
||||||
|
|
||||||
|
@ -36,6 +93,9 @@ void rtc_init(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
RTC_Open(NULL);
|
RTC_Open(NULL);
|
||||||
|
|
||||||
|
/* POSIX time origin (00:00:00 UTC, Thursday, 1 January 1970) */
|
||||||
|
rtc_write(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void rtc_free(void)
|
void rtc_free(void)
|
||||||
|
@ -55,6 +115,57 @@ int rtc_isenabled(void)
|
||||||
return !! (RTC->INIR & RTC_INIR_ACTIVE_Msk);
|
return !! (RTC->INIR & RTC_INIR_ACTIVE_Msk);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
time_t rtc_read(void)
|
||||||
|
{
|
||||||
|
/* NOTE: After boot, RTC time registers are not synced immediately, about 1 sec latency.
|
||||||
|
* RTC time got (through RTC_GetDateAndTime()) in this sec would be last-synced and incorrect.
|
||||||
|
*/
|
||||||
|
if (! rtc_isenabled()) {
|
||||||
|
rtc_init();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Used for intermediary between date time of H/W RTC and POSIX time */
|
||||||
|
struct tm datetime_tm;
|
||||||
|
|
||||||
|
if (! t_hwrtc_origin_inited) {
|
||||||
|
t_hwrtc_origin_inited = 1;
|
||||||
|
|
||||||
|
/* Convert date time from H/W RTC to struct TM */
|
||||||
|
rtc_convert_datetime_hwrtc_to_tm(&datetime_tm, &DATETIME_HWRTC_ORIGIN);
|
||||||
|
/* Convert date time of struct TM to POSIX time */
|
||||||
|
if (! _rtc_maketime(&datetime_tm, &t_hwrtc_origin, RTC_FULL_LEAP_YEAR_SUPPORT)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
S_RTC_TIME_DATA_T hwrtc_datetime_2K_present;
|
||||||
|
RTC_GetDateAndTime(&hwrtc_datetime_2K_present);
|
||||||
|
/* Convert date time from H/W RTC to struct TM */
|
||||||
|
rtc_convert_datetime_hwrtc_to_tm(&datetime_tm, &hwrtc_datetime_2K_present);
|
||||||
|
/* Convert date time of struct TM to POSIX time */
|
||||||
|
time_t t_hwrtc_elapsed;
|
||||||
|
if (! _rtc_maketime(&datetime_tm, &t_hwrtc_elapsed, RTC_FULL_LEAP_YEAR_SUPPORT)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Present time in POSIX time */
|
||||||
|
time_t t_present = t_write + (t_hwrtc_elapsed - t_hwrtc_origin);
|
||||||
|
return t_present;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rtc_write(time_t t)
|
||||||
|
{
|
||||||
|
if (! rtc_isenabled()) {
|
||||||
|
rtc_init();
|
||||||
|
}
|
||||||
|
|
||||||
|
t_write = t;
|
||||||
|
|
||||||
|
RTC_SetDateAndTime((S_RTC_TIME_DATA_T *) &DATETIME_HWRTC_ORIGIN);
|
||||||
|
/* NOTE: When engine is clocked by low power clock source (LXT/LIRC), we need to wait for 3 engine clocks. */
|
||||||
|
wait_us((NU_US_PER_SEC / NU_RTCCLK_PER_SEC) * 3);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
struct tm
|
struct tm
|
||||||
tm_sec seconds after the minute 0-61
|
tm_sec seconds after the minute 0-61
|
||||||
|
@ -67,68 +178,19 @@ int rtc_isenabled(void)
|
||||||
tm_yday days since January 1 0-365
|
tm_yday days since January 1 0-365
|
||||||
tm_isdst Daylight Saving Time flag
|
tm_isdst Daylight Saving Time flag
|
||||||
*/
|
*/
|
||||||
|
static void rtc_convert_datetime_hwrtc_to_tm(struct tm *datetime_tm, const S_RTC_TIME_DATA_T *datetime_hwrtc)
|
||||||
time_t rtc_read(void)
|
|
||||||
{
|
{
|
||||||
// NOTE: After boot, RTC time registers are not synced immediately, about 1 sec latency.
|
datetime_tm->tm_year = datetime_hwrtc->u32Year - NU_TM_YEAR0;
|
||||||
// RTC time got (through RTC_GetDateAndTime()) in this sec would be last-synced and incorrect.
|
datetime_tm->tm_mon = datetime_hwrtc->u32Month - 1;
|
||||||
if (! rtc_isenabled()) {
|
datetime_tm->tm_mday = datetime_hwrtc->u32Day;
|
||||||
rtc_init();
|
datetime_tm->tm_wday = datetime_hwrtc->u32DayOfWeek;
|
||||||
|
datetime_tm->tm_hour = datetime_hwrtc->u32Hour;
|
||||||
|
if (datetime_hwrtc->u32TimeScale == RTC_CLOCK_12 && datetime_hwrtc->u32AmPm == RTC_PM) {
|
||||||
|
datetime_tm->tm_hour += 12;
|
||||||
}
|
}
|
||||||
|
datetime_tm->tm_min = datetime_hwrtc->u32Minute;
|
||||||
S_RTC_TIME_DATA_T rtc_datetime;
|
datetime_tm->tm_sec = datetime_hwrtc->u32Second;
|
||||||
RTC_GetDateAndTime(&rtc_datetime);
|
|
||||||
|
|
||||||
struct tm timeinfo;
|
|
||||||
|
|
||||||
// Convert struct tm to S_RTC_TIME_DATA_T
|
|
||||||
timeinfo.tm_year = rtc_datetime.u32Year - YEAR0;
|
|
||||||
timeinfo.tm_mon = rtc_datetime.u32Month - 1;
|
|
||||||
timeinfo.tm_mday = rtc_datetime.u32Day;
|
|
||||||
timeinfo.tm_wday = rtc_datetime.u32DayOfWeek;
|
|
||||||
timeinfo.tm_hour = rtc_datetime.u32Hour;
|
|
||||||
if (rtc_datetime.u32TimeScale == RTC_CLOCK_12 && rtc_datetime.u32AmPm == RTC_PM) {
|
|
||||||
timeinfo.tm_hour += 12;
|
|
||||||
}
|
|
||||||
timeinfo.tm_min = rtc_datetime.u32Minute;
|
|
||||||
timeinfo.tm_sec = rtc_datetime.u32Second;
|
|
||||||
|
|
||||||
// Convert to timestamp
|
|
||||||
time_t t;
|
|
||||||
if (_rtc_maketime(&timeinfo, &t, RTC_FULL_LEAP_YEAR_SUPPORT) == false) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
|
|
||||||
void rtc_write(time_t t)
|
|
||||||
{
|
|
||||||
if (! rtc_isenabled()) {
|
|
||||||
rtc_init();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert timestamp to struct tm
|
|
||||||
struct tm timeinfo;
|
|
||||||
if (_rtc_localtime(t, &timeinfo, RTC_FULL_LEAP_YEAR_SUPPORT) == false) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
S_RTC_TIME_DATA_T rtc_datetime;
|
|
||||||
|
|
||||||
// Convert S_RTC_TIME_DATA_T to struct tm
|
|
||||||
rtc_datetime.u32Year = timeinfo.tm_year + YEAR0;
|
|
||||||
rtc_datetime.u32Month = timeinfo.tm_mon + 1;
|
|
||||||
rtc_datetime.u32Day = timeinfo.tm_mday;
|
|
||||||
rtc_datetime.u32DayOfWeek = timeinfo.tm_wday;
|
|
||||||
rtc_datetime.u32Hour = timeinfo.tm_hour;
|
|
||||||
rtc_datetime.u32Minute = timeinfo.tm_min;
|
|
||||||
rtc_datetime.u32Second = timeinfo.tm_sec;
|
|
||||||
rtc_datetime.u32TimeScale = RTC_CLOCK_24;
|
|
||||||
|
|
||||||
RTC_SetDateAndTime(&rtc_datetime);
|
|
||||||
// Wait 3 cycles of engine clock to ensure previous CTL write action is finish
|
|
||||||
wait_us(30 * 3);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -24,8 +24,65 @@
|
||||||
#include "nu_miscutil.h"
|
#include "nu_miscutil.h"
|
||||||
#include "mbed_mktime.h"
|
#include "mbed_mktime.h"
|
||||||
|
|
||||||
#define YEAR0 1900
|
/* Micro seconds per second */
|
||||||
//#define EPOCH_YR 1970
|
#define NU_US_PER_SEC 1000000
|
||||||
|
/* Timer clock per second
|
||||||
|
*
|
||||||
|
* NOTE: This dependents on real hardware.
|
||||||
|
*/
|
||||||
|
#define NU_RTCCLK_PER_SEC (__LXT)
|
||||||
|
|
||||||
|
/* Strategy for implementation of RTC HAL
|
||||||
|
*
|
||||||
|
* H/W RTC just supports year range 2000~2099, which cannot fully cover POSIX time (starting since 2970)
|
||||||
|
* and date time of struct TM (starting since 1900).
|
||||||
|
*
|
||||||
|
* To conquer the difficulty, we don't use H/W RTC to keep real date time. Instead, we use it to keep
|
||||||
|
* elapsed time in seconds since one reference time point. The strategy would be:
|
||||||
|
*
|
||||||
|
* 1. Choose DATETIME_HWRTC_ORIGIN (00:00:00 UTC, Saturday, 1 January 2000) as reference time point of H/W RTC.
|
||||||
|
* 2. t_hwrtc_origin = DATETIME_HWRTC_ORIGIN in POSIX time
|
||||||
|
* 3. t_hwrtc_elapsed = t_hwrtc_origin + elapsed time since t_hwrtc_origin
|
||||||
|
* 4. t_write = POSIX time set by rtc_write().
|
||||||
|
* 5. t_present = rtc_read() = t_write + (t_hwrtc_elapsed - t_hwrtc_origin)
|
||||||
|
*
|
||||||
|
* 1900
|
||||||
|
* |---------------------------------------------------------------------------------|
|
||||||
|
* 1970 t_write t_present
|
||||||
|
* |---------|-------|-----------------|---------------------------------------------|
|
||||||
|
*
|
||||||
|
* 2000
|
||||||
|
* |-----------------|---------------------------------------------------------------|
|
||||||
|
* t_hwrtc_origin t_hwrtc_elapsed
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
/* Start year of struct TM*/
|
||||||
|
#define NU_TM_YEAR0 1900
|
||||||
|
/* Start year of POSIX time (set_time()/time()) */
|
||||||
|
#define NU_POSIX_YEAR0 1970
|
||||||
|
/* Start year of H/W RTC */
|
||||||
|
#define NU_HWRTC_YEAR0 2000
|
||||||
|
|
||||||
|
/* RTC H/W origin time: 00:00:00 UTC, Saturday, 1 January 2000 */
|
||||||
|
static const S_RTC_TIME_DATA_T DATETIME_HWRTC_ORIGIN = {
|
||||||
|
2000, /* Year value, range between 2000 ~ 2099 */
|
||||||
|
1, /* Month value, range between 1 ~ 12 */
|
||||||
|
1, /* Day value, range between 1 ~ 31 */
|
||||||
|
RTC_SATURDAY, /* Day of the week */
|
||||||
|
0, /* Hour value, range between 0 ~ 23 */
|
||||||
|
0, /* Minute value, range between 0 ~ 59 */
|
||||||
|
0, /* Second value, range between 0 ~ 59 */
|
||||||
|
RTC_CLOCK_24, /* 12-Hour (RTC_CLOCK_12) / 24-Hour (RTC_CLOCK_24) */
|
||||||
|
0 /* RTC_AM / RTC_PM (used only for 12-Hour) */
|
||||||
|
};
|
||||||
|
/* t_hwrtc_origin initialized or not? */
|
||||||
|
static bool t_hwrtc_origin_inited = 0;
|
||||||
|
/* POSIX time of DATETIME_HWRTC_ORIGIN (since 00:00:00 UTC, Thursday, 1 January 1970) */
|
||||||
|
static time_t t_hwrtc_origin = 0;
|
||||||
|
/* POSIX time set by rtc_write() */
|
||||||
|
static time_t t_write = 0;
|
||||||
|
/* Convert date time from H/W RTC to struct TM */
|
||||||
|
static void rtc_convert_datetime_hwrtc_to_tm(struct tm *datetime_tm, const S_RTC_TIME_DATA_T *datetime_hwrtc);
|
||||||
|
|
||||||
static const struct nu_modinit_s rtc_modinit = {RTC_0, RTC_MODULE, 0, 0, 0, RTC_IRQn, NULL};
|
static const struct nu_modinit_s rtc_modinit = {RTC_0, RTC_MODULE, 0, 0, 0, RTC_IRQn, NULL};
|
||||||
|
|
||||||
|
@ -36,6 +93,9 @@ void rtc_init(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
RTC_Open(NULL);
|
RTC_Open(NULL);
|
||||||
|
|
||||||
|
/* POSIX time origin (00:00:00 UTC, Thursday, 1 January 1970) */
|
||||||
|
rtc_write(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void rtc_free(void)
|
void rtc_free(void)
|
||||||
|
@ -55,6 +115,57 @@ int rtc_isenabled(void)
|
||||||
return !! (RTC->INIT & RTC_INIT_INIT_Active_Msk);
|
return !! (RTC->INIT & RTC_INIT_INIT_Active_Msk);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
time_t rtc_read(void)
|
||||||
|
{
|
||||||
|
/* NOTE: After boot, RTC time registers are not synced immediately, about 1 sec latency.
|
||||||
|
* RTC time got (through RTC_GetDateAndTime()) in this sec would be last-synced and incorrect.
|
||||||
|
*/
|
||||||
|
if (! rtc_isenabled()) {
|
||||||
|
rtc_init();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Used for intermediary between date time of H/W RTC and POSIX time */
|
||||||
|
struct tm datetime_tm;
|
||||||
|
|
||||||
|
if (! t_hwrtc_origin_inited) {
|
||||||
|
t_hwrtc_origin_inited = 1;
|
||||||
|
|
||||||
|
/* Convert date time from H/W RTC to struct TM */
|
||||||
|
rtc_convert_datetime_hwrtc_to_tm(&datetime_tm, &DATETIME_HWRTC_ORIGIN);
|
||||||
|
/* Convert date time of struct TM to POSIX time */
|
||||||
|
if (! _rtc_maketime(&datetime_tm, &t_hwrtc_origin, RTC_FULL_LEAP_YEAR_SUPPORT)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
S_RTC_TIME_DATA_T hwrtc_datetime_2K_present;
|
||||||
|
RTC_GetDateAndTime(&hwrtc_datetime_2K_present);
|
||||||
|
/* Convert date time from H/W RTC to struct TM */
|
||||||
|
rtc_convert_datetime_hwrtc_to_tm(&datetime_tm, &hwrtc_datetime_2K_present);
|
||||||
|
/* Convert date time of struct TM to POSIX time */
|
||||||
|
time_t t_hwrtc_elapsed;
|
||||||
|
if (! _rtc_maketime(&datetime_tm, &t_hwrtc_elapsed, RTC_FULL_LEAP_YEAR_SUPPORT)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Present time in POSIX time */
|
||||||
|
time_t t_present = t_write + (t_hwrtc_elapsed - t_hwrtc_origin);
|
||||||
|
return t_present;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rtc_write(time_t t)
|
||||||
|
{
|
||||||
|
if (! rtc_isenabled()) {
|
||||||
|
rtc_init();
|
||||||
|
}
|
||||||
|
|
||||||
|
t_write = t;
|
||||||
|
|
||||||
|
RTC_SetDateAndTime((S_RTC_TIME_DATA_T *) &DATETIME_HWRTC_ORIGIN);
|
||||||
|
/* NOTE: When engine is clocked by low power clock source (LXT/LIRC), we need to wait for 3 engine clocks. */
|
||||||
|
wait_us((NU_US_PER_SEC / NU_RTCCLK_PER_SEC) * 3);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
struct tm
|
struct tm
|
||||||
tm_sec seconds after the minute 0-61
|
tm_sec seconds after the minute 0-61
|
||||||
|
@ -67,69 +178,18 @@ int rtc_isenabled(void)
|
||||||
tm_yday days since January 1 0-365
|
tm_yday days since January 1 0-365
|
||||||
tm_isdst Daylight Saving Time flag
|
tm_isdst Daylight Saving Time flag
|
||||||
*/
|
*/
|
||||||
|
static void rtc_convert_datetime_hwrtc_to_tm(struct tm *datetime_tm, const S_RTC_TIME_DATA_T *datetime_hwrtc)
|
||||||
time_t rtc_read(void)
|
|
||||||
{
|
{
|
||||||
// NOTE: After boot, RTC time registers are not synced immediately, about 1 sec latency.
|
datetime_tm->tm_year = datetime_hwrtc->u32Year - NU_TM_YEAR0;
|
||||||
// RTC time got (through RTC_GetDateAndTime()) in this sec would be last-synced and incorrect.
|
datetime_tm->tm_mon = datetime_hwrtc->u32Month - 1;
|
||||||
if (! rtc_isenabled()) {
|
datetime_tm->tm_mday = datetime_hwrtc->u32Day;
|
||||||
rtc_init();
|
datetime_tm->tm_wday = datetime_hwrtc->u32DayOfWeek;
|
||||||
|
datetime_tm->tm_hour = datetime_hwrtc->u32Hour;
|
||||||
|
if (datetime_hwrtc->u32TimeScale == RTC_CLOCK_12 && datetime_hwrtc->u32AmPm == RTC_PM) {
|
||||||
|
datetime_tm->tm_hour += 12;
|
||||||
}
|
}
|
||||||
|
datetime_tm->tm_min = datetime_hwrtc->u32Minute;
|
||||||
S_RTC_TIME_DATA_T rtc_datetime;
|
datetime_tm->tm_sec = datetime_hwrtc->u32Second;
|
||||||
RTC_GetDateAndTime(&rtc_datetime);
|
|
||||||
|
|
||||||
struct tm timeinfo;
|
|
||||||
|
|
||||||
// Convert struct tm to S_RTC_TIME_DATA_T
|
|
||||||
timeinfo.tm_year = rtc_datetime.u32Year - YEAR0;
|
|
||||||
timeinfo.tm_mon = rtc_datetime.u32Month - 1;
|
|
||||||
timeinfo.tm_mday = rtc_datetime.u32Day;
|
|
||||||
timeinfo.tm_wday = rtc_datetime.u32DayOfWeek;
|
|
||||||
timeinfo.tm_hour = rtc_datetime.u32Hour;
|
|
||||||
if (rtc_datetime.u32TimeScale == RTC_CLOCK_12 && rtc_datetime.u32AmPm == RTC_PM) {
|
|
||||||
timeinfo.tm_hour += 12;
|
|
||||||
}
|
|
||||||
timeinfo.tm_min = rtc_datetime.u32Minute;
|
|
||||||
timeinfo.tm_sec = rtc_datetime.u32Second;
|
|
||||||
|
|
||||||
// Convert to timestamp
|
|
||||||
time_t t;
|
|
||||||
if (_rtc_maketime(&timeinfo, &t, RTC_FULL_LEAP_YEAR_SUPPORT) == false) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
|
|
||||||
void rtc_write(time_t t)
|
|
||||||
{
|
|
||||||
if (! rtc_isenabled()) {
|
|
||||||
rtc_init();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert timestamp to struct tm
|
|
||||||
struct tm timeinfo;
|
|
||||||
if (_rtc_localtime(t, &timeinfo, RTC_FULL_LEAP_YEAR_SUPPORT) == false) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
S_RTC_TIME_DATA_T rtc_datetime;
|
|
||||||
|
|
||||||
// Convert S_RTC_TIME_DATA_T to struct tm
|
|
||||||
rtc_datetime.u32Year = timeinfo.tm_year + YEAR0;
|
|
||||||
rtc_datetime.u32Month = timeinfo.tm_mon + 1;
|
|
||||||
rtc_datetime.u32Day = timeinfo.tm_mday;
|
|
||||||
rtc_datetime.u32DayOfWeek = timeinfo.tm_wday;
|
|
||||||
rtc_datetime.u32Hour = timeinfo.tm_hour;
|
|
||||||
rtc_datetime.u32Minute = timeinfo.tm_min;
|
|
||||||
rtc_datetime.u32Second = timeinfo.tm_sec;
|
|
||||||
rtc_datetime.u32TimeScale = RTC_CLOCK_24;
|
|
||||||
|
|
||||||
// NOTE: Timing issue with write to RTC registers. This delay is empirical, not rational.
|
|
||||||
RTC_SetDateAndTime(&rtc_datetime);
|
|
||||||
//nu_nop(6000);
|
|
||||||
wait_us(100);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue