From 6065e3a94399b2f49603592cc3c8bea48f83bd07 Mon Sep 17 00:00:00 2001 From: ccli8 Date: Tue, 29 May 2018 15:33:34 +0800 Subject: [PATCH] [Nuvoton] Fix RTC cannot cross reset cycle --- targets/TARGET_NUVOTON/TARGET_M451/rtc_api.c | 18 ++++++++++++++++ targets/TARGET_NUVOTON/TARGET_M480/rtc_api.c | 14 +++++++++++++ .../device/StdDriver/nano100_rtc.h | 21 +++++++++++++++++++ .../TARGET_NUVOTON/TARGET_NANO100/rtc_api.c | 14 +++++++++++++ .../device/StdDriver/nuc472_rtc.h | 16 ++++++++++++++ .../TARGET_NUVOTON/TARGET_NUC472/rtc_api.c | 18 ++++++++++++++++ 6 files changed, 101 insertions(+) diff --git a/targets/TARGET_NUVOTON/TARGET_M451/rtc_api.c b/targets/TARGET_NUVOTON/TARGET_M451/rtc_api.c index c64d375bf9..90965e7c9b 100644 --- a/targets/TARGET_NUVOTON/TARGET_M451/rtc_api.c +++ b/targets/TARGET_NUVOTON/TARGET_M451/rtc_api.c @@ -136,9 +136,18 @@ time_t rtc_read(void) if (! _rtc_maketime(&datetime_tm, &t_hwrtc_origin, RTC_FULL_LEAP_YEAR_SUPPORT)) { return 0; } + + /* Load t_write from RTC spare register to cross reset cycle */ + RTC_WaitAccessEnable(); + RTC_EnableSpareAccess(); + RTC_WaitAccessEnable(); + t_write = RTC_READ_SPARE_REGISTER(0); + RTC_WaitAccessEnable(); + while (! (RTC->SPRCTL & RTC_SPRCTL_SPRRWRDY_Msk)); } S_RTC_TIME_DATA_T hwrtc_datetime_2K_present; + RTC_WaitAccessEnable(); 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); @@ -161,6 +170,15 @@ void rtc_write(time_t t) t_write = t; + /* Store t_write to RTC spare register to cross reset cycle */ + RTC_WaitAccessEnable(); + RTC_EnableSpareAccess(); + RTC_WaitAccessEnable(); + RTC_WRITE_SPARE_REGISTER(0, t_write); + RTC_WaitAccessEnable(); + while (! (RTC->SPRCTL & RTC_SPRCTL_SPRRWRDY_Msk)); + + RTC_WaitAccessEnable(); 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); diff --git a/targets/TARGET_NUVOTON/TARGET_M480/rtc_api.c b/targets/TARGET_NUVOTON/TARGET_M480/rtc_api.c index 4bcd67419a..75faa145cd 100644 --- a/targets/TARGET_NUVOTON/TARGET_M480/rtc_api.c +++ b/targets/TARGET_NUVOTON/TARGET_M480/rtc_api.c @@ -138,9 +138,16 @@ time_t rtc_read(void) if (! _rtc_maketime(&datetime_tm, &t_hwrtc_origin, RTC_FULL_LEAP_YEAR_SUPPORT)) { return 0; } + + /* Load t_write from RTC spare register to cross reset cycle */ + RTC_WaitAccessEnable(); + RTC_EnableSpareAccess(); + RTC_WaitAccessEnable(); + t_write = RTC_READ_SPARE_REGISTER(0); } S_RTC_TIME_DATA_T hwrtc_datetime_2K_present; + RTC_WaitAccessEnable(); 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); @@ -163,6 +170,13 @@ void rtc_write(time_t t) t_write = t; + /* Store t_write to RTC spare register to cross reset cycle */ + RTC_WaitAccessEnable(); + RTC_EnableSpareAccess(); + RTC_WaitAccessEnable(); + RTC_WRITE_SPARE_REGISTER(0, t_write); + + RTC_WaitAccessEnable(); 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); diff --git a/targets/TARGET_NUVOTON/TARGET_NANO100/device/StdDriver/nano100_rtc.h b/targets/TARGET_NUVOTON/TARGET_NANO100/device/StdDriver/nano100_rtc.h index b6c823446f..35652799b2 100644 --- a/targets/TARGET_NUVOTON/TARGET_NANO100/device/StdDriver/nano100_rtc.h +++ b/targets/TARGET_NUVOTON/TARGET_NANO100/device/StdDriver/nano100_rtc.h @@ -210,6 +210,26 @@ typedef struct { */ #define RTC_DISABLE_TICK_WAKEUP() (RTC->TTR &= ~RTC_TTR_TWKE_Msk); +/* Declare these inline functions here to avoid MISRA C 2004 rule 8.1 error */ +static __INLINE void RTC_WaitAccessEnable(void); + +/** + * @brief Wait RTC Access Enable + * + * @param None + * + * @return None + * + * @details This function is used to enable the maximum RTC read/write accessible time. + */ +static __INLINE void RTC_WaitAccessEnable(void) +{ + /* NOTE: When RTC->AER is written with RTC_WRITE_KEY frequently, we may lock in the loop here. + * A workaround is to re-initialize RTC->INIR without checking RTC->INIR[ACTIVE] flag. */ + RTC->INIR = RTC_INIT_KEY; + RTC->AER = RTC_WRITE_KEY; + while(!(RTC->AER & RTC_AER_ENF_Msk)) RTC->AER = RTC_WRITE_KEY; +} void RTC_Open(S_RTC_TIME_DATA_T *sPt); void RTC_Close(void); @@ -217,6 +237,7 @@ void RTC_32KCalibration(int32_t i32FrequencyX100); void RTC_SetTickPeriod(uint32_t u32TickSelection); void RTC_EnableInt(uint32_t u32IntFlagMask); void RTC_DisableInt(uint32_t u32IntFlagMask); +void RTC_EnableSpareAccess(void); uint32_t RTC_GetDayOfWeek(void); void RTC_DisableTamperDetection(void); void RTC_EnableTamperDetection(uint32_t u32PinCondition); diff --git a/targets/TARGET_NUVOTON/TARGET_NANO100/rtc_api.c b/targets/TARGET_NUVOTON/TARGET_NANO100/rtc_api.c index cdb7f01ccf..e8bdcf6f18 100644 --- a/targets/TARGET_NUVOTON/TARGET_NANO100/rtc_api.c +++ b/targets/TARGET_NUVOTON/TARGET_NANO100/rtc_api.c @@ -136,9 +136,16 @@ time_t rtc_read(void) if (! _rtc_maketime(&datetime_tm, &t_hwrtc_origin, RTC_FULL_LEAP_YEAR_SUPPORT)) { return 0; } + + /* Load t_write from RTC spare register to cross reset cycle */ + RTC_WaitAccessEnable(); + t_write = RTC_READ_SPARE_REGISTER(0); + RTC_WaitAccessEnable(); + while (! (RTC->SPRCTL & RTC_SPRCTL_SPRRDY_Msk)); } S_RTC_TIME_DATA_T hwrtc_datetime_2K_present; + RTC_WaitAccessEnable(); 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); @@ -161,6 +168,13 @@ void rtc_write(time_t t) t_write = t; + /* Store t_write to RTC spare register to cross reset cycle */ + RTC_WaitAccessEnable(); + RTC_WRITE_SPARE_REGISTER(0, t_write); + RTC_WaitAccessEnable(); + while (! (RTC->SPRCTL & RTC_SPRCTL_SPRRDY_Msk)); + + RTC_WaitAccessEnable(); 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); diff --git a/targets/TARGET_NUVOTON/TARGET_NUC472/device/StdDriver/nuc472_rtc.h b/targets/TARGET_NUVOTON/TARGET_NUC472/device/StdDriver/nuc472_rtc.h index 3d633b166d..1965b2081d 100644 --- a/targets/TARGET_NUVOTON/TARGET_NUC472/device/StdDriver/nuc472_rtc.h +++ b/targets/TARGET_NUVOTON/TARGET_NUC472/device/StdDriver/nuc472_rtc.h @@ -191,7 +191,23 @@ typedef struct { */ #define RTC_GET_TAMPER_FLAG(u32PinNum) ( (RTC->TAMPSTS & (1 << u32PinNum)) >> u32PinNum) +/* Declare these inline functions here to avoid MISRA C 2004 rule 8.1 error */ +static __INLINE void RTC_WaitAccessEnable(void); +/** + * @brief Wait RTC Access Enable + * + * @param None + * + * @return None + * + * @details This function is used to enable the maximum RTC read/write accessible time. + */ +static __INLINE void RTC_WaitAccessEnable(void) +{ + RTC->RWEN = RTC_WRITE_KEY; + while(!(RTC->RWEN & RTC_RWEN_RWENF_Msk)); +} void RTC_Open(S_RTC_TIME_DATA_T *sPt); void RTC_Close(void); diff --git a/targets/TARGET_NUVOTON/TARGET_NUC472/rtc_api.c b/targets/TARGET_NUVOTON/TARGET_NUC472/rtc_api.c index 3442f247a8..10500420af 100644 --- a/targets/TARGET_NUVOTON/TARGET_NUC472/rtc_api.c +++ b/targets/TARGET_NUVOTON/TARGET_NUC472/rtc_api.c @@ -136,9 +136,18 @@ time_t rtc_read(void) if (! _rtc_maketime(&datetime_tm, &t_hwrtc_origin, RTC_FULL_LEAP_YEAR_SUPPORT)) { return 0; } + + /* Load t_write from RTC spare register to cross reset cycle */ + RTC_WaitAccessEnable(); + RTC_EnableSpareAccess(); + RTC_WaitAccessEnable(); + t_write = RTC_READ_SPARE_REGISTER(0); + RTC_WaitAccessEnable(); + while (! (RTC->SPRCTL & RTC_SPRCTL_SPRRWRDY_Msk)); } S_RTC_TIME_DATA_T hwrtc_datetime_2K_present; + RTC_WaitAccessEnable(); 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); @@ -161,6 +170,15 @@ void rtc_write(time_t t) t_write = t; + /* Store t_write to RTC spare register to cross reset cycle */ + RTC_WaitAccessEnable(); + RTC_EnableSpareAccess(); + RTC_WaitAccessEnable(); + RTC_WRITE_SPARE_REGISTER(0, t_write); + RTC_WaitAccessEnable(); + while (! (RTC->SPRCTL & RTC_SPRCTL_SPRRWRDY_Msk)); + + RTC_WaitAccessEnable(); 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);