3030#include "cyhal_rtc.h"
3131#include "cyhal_system.h"
3232
33+ /**
34+ * \addtogroup group_hal_psoc6_rtc RTC (Real Time Clock)
35+ * \ingroup group_hal_psoc6
36+ * \{
37+ *
38+ * Internally the PSoC6 RTC only stores the year as a two digit BCD value
39+ * (0-99); no century information is stored. On RTC initialization the HAL must,
40+ * as a result, assume a default century. If cyhal_rtc_write has been called
41+ * with a different century than the default, its value must be stored and that
42+ * value must persist through deep sleep, hibernate, software resets, etc. PSoC6
43+ * hardware provides a number of BREG registers which exist in the BACKUP domain
44+ * and will persist over these power modes and resets. The HAL uses the highest
45+ * indexed BACKUP->BREG register to store the century for the RTC.
46+ *
47+ * Therefore do not use the highest indexed BACKUP->BREG register as it is
48+ * reserved for internal HAL usage.
49+ * \} group_hal_psoc6_wdt
50+ */
51+
3352#ifdef CY_IP_MXS40SRSS_RTC_INSTANCES
3453
3554#if defined(__cplusplus )
@@ -40,9 +59,15 @@ extern "C" {
4059#define CYHAL_RTC_STATE_ENABLED 1
4160#define CYHAL_RTC_STATE_TIME_SET 2
4261#define CYHAL_RTC_DEFAULT_PRIORITY 5
43- #define CYHAL_RTC_CENTURY 2000
62+ #define CYHAL_RTC_INIT_CENTURY 2000
4463#define CYHAL_TM_YEAR_BASE 1900
4564
65+ #define CYHAL_RTC_BREG (BACKUP->BREG[SRSS_BACKUP_NUM_BREG-1])
66+ #define CYHAL_RTC_BREG_CENTURY_Pos 0UL
67+ #define CYHAL_RTC_BREG_CENTURY_Msk 0x0000FFFFUL
68+ #define CYHAL_RTC_BREG_STATE_Pos 16UL
69+ #define CYHAL_RTC_BREG_STATE_Msk 0xFFFF0000UL
70+
4671/** Wrapper around the PDL Cy_RTC_DeepSleepCallback to adapt the function signature */
4772static cy_en_syspm_status_t cyhal_rtc_syspm_callback (cy_stc_syspm_callback_params_t * params , cy_en_syspm_callback_mode_t mode )
4873{
@@ -59,15 +84,39 @@ static cy_stc_syspm_callback_t cyhal_rtc_pm_cb = {
5984
6085static cyhal_rtc_event_callback_t cyhal_rtc_user_handler ;
6186static void * cyhal_rtc_handler_arg ;
62- static uint8_t cyhal_rtc_initialized = CYHAL_RTC_STATE_UNINITIALIZED ;
87+
88+ /* Returns century portion of BREG register used to store century info */
89+ static inline uint16_t get_rtc_century ()
90+ {
91+ return _FLD2VAL (CYHAL_RTC_BREG_CENTURY , CYHAL_RTC_BREG );
92+ }
93+
94+ /* Sets century portion of BREG register used to store century info */
95+ static inline void set_rtc_century (uint16_t century )
96+ {
97+ CYHAL_RTC_BREG &= CYHAL_RTC_BREG_STATE_Msk ;
98+ CYHAL_RTC_BREG |= _VAL2FLD (CYHAL_RTC_BREG_CENTURY , century );
99+ }
100+
101+ /* Returns state portion of BREG register used to store century info */
102+ static inline uint16_t get_rtc_state ()
103+ {
104+ return _FLD2VAL (CYHAL_RTC_BREG_STATE , CYHAL_RTC_BREG );
105+ }
106+
107+ /* Sets state portion of BREG register used to store century info */
108+ static inline void set_rtc_state (uint16_t init )
109+ {
110+ CYHAL_RTC_BREG &= CYHAL_RTC_BREG_CENTURY_Msk ;
111+ CYHAL_RTC_BREG |= _VAL2FLD (CYHAL_RTC_BREG_STATE , init );
112+ }
63113
64114/** Wrapper around the PDL RTC interrupt handler to adapt the function signature */
65115static void cyhal_rtc_internal_handler (void )
66116{
67117 Cy_RTC_Interrupt (dst , NULL != dst );
68118}
69119
70- /* Override weak function from PDL */
71120void Cy_RTC_Alarm1Interrupt (void )
72121{
73122 if (NULL != cyhal_rtc_user_handler )
@@ -76,24 +125,50 @@ void Cy_RTC_Alarm1Interrupt(void)
76125 }
77126}
78127
128+ void Cy_RTC_CenturyInterrupt (void )
129+ {
130+ set_rtc_century (get_rtc_century () + 100 );
131+ }
132+
79133cy_rslt_t cyhal_rtc_init (cyhal_rtc_t * obj )
80134{
81135 CY_ASSERT (NULL != obj );
82136 cy_rslt_t rslt = CY_RSLT_SUCCESS ;
83- if (cyhal_rtc_initialized == CYHAL_RTC_STATE_UNINITIALIZED )
137+ if (get_rtc_state () == CYHAL_RTC_STATE_UNINITIALIZED )
84138 {
85- static const cy_stc_sysint_t irqCfg = {.intrSrc = srss_interrupt_backup_IRQn , .intrPriority = CYHAL_RTC_DEFAULT_PRIORITY };
86- Cy_SysInt_Init (& irqCfg , & cyhal_rtc_internal_handler );
139+ if (Cy_RTC_IsExternalResetOccurred ())
140+ {
141+ // Reset to default time
142+ static const cy_stc_rtc_config_t defaultTime = {
143+ .dayOfWeek = CY_RTC_SATURDAY ,
144+ .date = 1 ,
145+ .month = 1 ,
146+ .year = 0 ,
147+ };
148+ Cy_RTC_SetDateAndTime (& defaultTime );
149+ set_rtc_century (CYHAL_RTC_INIT_CENTURY );
150+ }
87151
88152 if (Cy_SysPm_RegisterCallback (& cyhal_rtc_pm_cb ))
89153 {
90- cyhal_rtc_initialized = CYHAL_RTC_STATE_ENABLED ;
154+ set_rtc_state ( CYHAL_RTC_STATE_ENABLED ) ;
91155 }
92156 else
93157 {
94158 rslt = CY_RSLT_RTC_NOT_INITIALIZED ;
95159 }
96160 }
161+ else if (get_rtc_state () == CYHAL_RTC_STATE_ENABLED || get_rtc_state () == CYHAL_RTC_STATE_TIME_SET )
162+ {
163+ if (Cy_RTC_GetInterruptStatus () & CY_RTC_INTR_CENTURY )
164+ Cy_RTC_CenturyInterrupt ();
165+ }
166+
167+ Cy_RTC_ClearInterrupt (CY_RTC_INTR_CENTURY );
168+ Cy_RTC_SetInterruptMask (CY_RTC_INTR_CENTURY );
169+ static const cy_stc_sysint_t irqCfg = {.intrSrc = srss_interrupt_backup_IRQn , .intrPriority = CYHAL_RTC_DEFAULT_PRIORITY };
170+ Cy_SysInt_Init (& irqCfg , & cyhal_rtc_internal_handler );
171+
97172 if (rslt == CY_RSLT_SUCCESS )
98173 {
99174 dst = NULL ;
@@ -108,25 +183,28 @@ void cyhal_rtc_free(cyhal_rtc_t *obj)
108183 CY_ASSERT (NULL != obj );
109184 NVIC_DisableIRQ (srss_interrupt_backup_IRQn );
110185
186+ Cy_RTC_SetInterruptMask (CY_RTC_INTR_CENTURY );
111187 dst = NULL ;
112188}
113189
114190bool cyhal_rtc_is_enabled (cyhal_rtc_t * obj )
115191{
116192 CY_ASSERT (NULL != obj );
117- return (cyhal_rtc_initialized == CYHAL_RTC_STATE_TIME_SET );
193+ return (get_rtc_state () == CYHAL_RTC_STATE_TIME_SET );
118194}
119195
120196cy_rslt_t cyhal_rtc_read (cyhal_rtc_t * obj , struct tm * time )
121197{
122- // The number of days that precede each month of the year, not including Feb 29
123198 CY_ASSERT (NULL != obj );
199+ // The number of days that precede each month of the year, not including Feb 29
124200 static const uint16_t CUMULATIVE_DAYS [] = {0 , 31 , 59 , 90 , 120 , 151 , 181 , 212 , 243 , 273 , 304 , 334 };
201+
125202 cy_stc_rtc_config_t dateTime ;
126203 uint32_t savedIntrStatus = cyhal_system_critical_section_enter ();
127204 Cy_RTC_GetDateAndTime (& dateTime );
128- int year = dateTime .year + CYHAL_RTC_CENTURY ;
205+ int year = dateTime .year + get_rtc_century () ;
129206 cyhal_system_critical_section_exit (savedIntrStatus );
207+
130208 time -> tm_sec = dateTime .sec ;
131209 time -> tm_min = dateTime .min ;
132210 time -> tm_hour = dateTime .hour ;
@@ -137,16 +215,13 @@ cy_rslt_t cyhal_rtc_read(cyhal_rtc_t *obj, struct tm *time)
137215 time -> tm_yday = CUMULATIVE_DAYS [time -> tm_mon ] + dateTime .date - 1u +
138216 ((dateTime .month >= 3 && Cy_RTC_IsLeapYear (year )) ? 1u : 0u );
139217 time -> tm_isdst = -1 ;
218+
140219 return CY_RSLT_SUCCESS ;
141220}
142221
143222cy_rslt_t cyhal_rtc_write (cyhal_rtc_t * obj , const struct tm * time )
144223{
145224 CY_ASSERT (NULL != obj );
146- int year = CYHAL_TM_YEAR_BASE + time -> tm_year ;
147- if (year < 2000 || year > 2099 ) {
148- return CY_RSLT_RTC_BAD_ARGUMENT ;
149- }
150225 uint32_t year2digit = time -> tm_year % 100 ;
151226 cy_stc_rtc_config_t newtime = {
152227 .sec = time -> tm_sec ,
@@ -158,18 +233,25 @@ cy_rslt_t cyhal_rtc_write(cyhal_rtc_t *obj, const struct tm *time)
158233 .month = time -> tm_mon + 1 ,
159234 .year = year2digit
160235 };
236+
161237 cy_rslt_t rslt ;
162238 uint32_t retry = 0 ;
163239 static const uint32_t MAX_RETRY = 10 , RETRY_DELAY_MS = 1 ;
164240 do {
165241 if (retry != 0 )
166242 Cy_SysLib_Delay (RETRY_DELAY_MS );
243+ uint32_t savedIntrStatus = cyhal_system_critical_section_enter ();
167244 rslt = (cy_rslt_t )Cy_RTC_SetDateAndTime (& newtime );
245+ if (rslt == CY_RSLT_SUCCESS )
246+ set_rtc_century (time -> tm_year - year2digit + CYHAL_TM_YEAR_BASE );
247+ cyhal_system_critical_section_exit (savedIntrStatus );
168248 ++ retry ;
169249 } while (rslt == CY_RTC_INVALID_STATE && retry < MAX_RETRY );
250+
170251 while (CY_RTC_BUSY == Cy_RTC_GetSyncStatus ()) { }
252+
171253 if (rslt == CY_RSLT_SUCCESS )
172- cyhal_rtc_initialized = CYHAL_RTC_STATE_TIME_SET ;
254+ set_rtc_state ( CYHAL_RTC_STATE_TIME_SET ) ;
173255 return rslt ;
174256}
175257
@@ -240,13 +322,13 @@ void cyhal_rtc_register_callback(cyhal_rtc_t *obj, cyhal_rtc_event_callback_t ca
240322 cyhal_system_critical_section_exit (savedIntrStatus );
241323}
242324
243- void cyhal_rtc_enable_event (cyhal_rtc_t * obj , cyhal_rtc_event_t event , uint8_t intrPriority , bool enable )
325+ void cyhal_rtc_enable_event (cyhal_rtc_t * obj , cyhal_rtc_event_t event , uint8_t intr_priority , bool enable )
244326{
245327 CY_ASSERT (NULL != obj );
246328 CY_ASSERT (CYHAL_RTC_ALARM == event );
247329 Cy_RTC_ClearInterrupt (CY_RTC_INTR_ALARM1 | CY_RTC_INTR_ALARM2 );
248- Cy_RTC_SetInterruptMask (enable ? CY_RTC_INTR_ALARM1 : 0 );
249- NVIC_SetPriority (srss_interrupt_backup_IRQn , intrPriority );
330+ Cy_RTC_SetInterruptMask (( enable ? CY_RTC_INTR_ALARM1 : 0 ) | CY_RTC_INTR_CENTURY );
331+ NVIC_SetPriority (srss_interrupt_backup_IRQn , intr_priority );
250332}
251333
252334#if defined(__cplusplus )
0 commit comments