30
30
#include "cyhal_rtc.h"
31
31
#include "cyhal_system.h"
32
32
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
+
33
52
#ifdef CY_IP_MXS40SRSS_RTC_INSTANCES
34
53
35
54
#if defined(__cplusplus )
@@ -40,9 +59,15 @@ extern "C" {
40
59
#define CYHAL_RTC_STATE_ENABLED 1
41
60
#define CYHAL_RTC_STATE_TIME_SET 2
42
61
#define CYHAL_RTC_DEFAULT_PRIORITY 5
43
- #define CYHAL_RTC_CENTURY 2000
62
+ #define CYHAL_RTC_INIT_CENTURY 2000
44
63
#define CYHAL_TM_YEAR_BASE 1900
45
64
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
+
46
71
/** Wrapper around the PDL Cy_RTC_DeepSleepCallback to adapt the function signature */
47
72
static cy_en_syspm_status_t cyhal_rtc_syspm_callback (cy_stc_syspm_callback_params_t * params , cy_en_syspm_callback_mode_t mode )
48
73
{
@@ -59,15 +84,39 @@ static cy_stc_syspm_callback_t cyhal_rtc_pm_cb = {
59
84
60
85
static cyhal_rtc_event_callback_t cyhal_rtc_user_handler ;
61
86
static 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
+ }
63
113
64
114
/** Wrapper around the PDL RTC interrupt handler to adapt the function signature */
65
115
static void cyhal_rtc_internal_handler (void )
66
116
{
67
117
Cy_RTC_Interrupt (dst , NULL != dst );
68
118
}
69
119
70
- /* Override weak function from PDL */
71
120
void Cy_RTC_Alarm1Interrupt (void )
72
121
{
73
122
if (NULL != cyhal_rtc_user_handler )
@@ -76,24 +125,50 @@ void Cy_RTC_Alarm1Interrupt(void)
76
125
}
77
126
}
78
127
128
+ void Cy_RTC_CenturyInterrupt (void )
129
+ {
130
+ set_rtc_century (get_rtc_century () + 100 );
131
+ }
132
+
79
133
cy_rslt_t cyhal_rtc_init (cyhal_rtc_t * obj )
80
134
{
81
135
CY_ASSERT (NULL != obj );
82
136
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 )
84
138
{
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
+ }
87
151
88
152
if (Cy_SysPm_RegisterCallback (& cyhal_rtc_pm_cb ))
89
153
{
90
- cyhal_rtc_initialized = CYHAL_RTC_STATE_ENABLED ;
154
+ set_rtc_state ( CYHAL_RTC_STATE_ENABLED ) ;
91
155
}
92
156
else
93
157
{
94
158
rslt = CY_RSLT_RTC_NOT_INITIALIZED ;
95
159
}
96
160
}
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
+
97
172
if (rslt == CY_RSLT_SUCCESS )
98
173
{
99
174
dst = NULL ;
@@ -108,25 +183,28 @@ void cyhal_rtc_free(cyhal_rtc_t *obj)
108
183
CY_ASSERT (NULL != obj );
109
184
NVIC_DisableIRQ (srss_interrupt_backup_IRQn );
110
185
186
+ Cy_RTC_SetInterruptMask (CY_RTC_INTR_CENTURY );
111
187
dst = NULL ;
112
188
}
113
189
114
190
bool cyhal_rtc_is_enabled (cyhal_rtc_t * obj )
115
191
{
116
192
CY_ASSERT (NULL != obj );
117
- return (cyhal_rtc_initialized == CYHAL_RTC_STATE_TIME_SET );
193
+ return (get_rtc_state () == CYHAL_RTC_STATE_TIME_SET );
118
194
}
119
195
120
196
cy_rslt_t cyhal_rtc_read (cyhal_rtc_t * obj , struct tm * time )
121
197
{
122
- // The number of days that precede each month of the year, not including Feb 29
123
198
CY_ASSERT (NULL != obj );
199
+ // The number of days that precede each month of the year, not including Feb 29
124
200
static const uint16_t CUMULATIVE_DAYS [] = {0 , 31 , 59 , 90 , 120 , 151 , 181 , 212 , 243 , 273 , 304 , 334 };
201
+
125
202
cy_stc_rtc_config_t dateTime ;
126
203
uint32_t savedIntrStatus = cyhal_system_critical_section_enter ();
127
204
Cy_RTC_GetDateAndTime (& dateTime );
128
- int year = dateTime .year + CYHAL_RTC_CENTURY ;
205
+ int year = dateTime .year + get_rtc_century () ;
129
206
cyhal_system_critical_section_exit (savedIntrStatus );
207
+
130
208
time -> tm_sec = dateTime .sec ;
131
209
time -> tm_min = dateTime .min ;
132
210
time -> tm_hour = dateTime .hour ;
@@ -137,16 +215,13 @@ cy_rslt_t cyhal_rtc_read(cyhal_rtc_t *obj, struct tm *time)
137
215
time -> tm_yday = CUMULATIVE_DAYS [time -> tm_mon ] + dateTime .date - 1u +
138
216
((dateTime .month >= 3 && Cy_RTC_IsLeapYear (year )) ? 1u : 0u );
139
217
time -> tm_isdst = -1 ;
218
+
140
219
return CY_RSLT_SUCCESS ;
141
220
}
142
221
143
222
cy_rslt_t cyhal_rtc_write (cyhal_rtc_t * obj , const struct tm * time )
144
223
{
145
224
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
- }
150
225
uint32_t year2digit = time -> tm_year % 100 ;
151
226
cy_stc_rtc_config_t newtime = {
152
227
.sec = time -> tm_sec ,
@@ -158,18 +233,25 @@ cy_rslt_t cyhal_rtc_write(cyhal_rtc_t *obj, const struct tm *time)
158
233
.month = time -> tm_mon + 1 ,
159
234
.year = year2digit
160
235
};
236
+
161
237
cy_rslt_t rslt ;
162
238
uint32_t retry = 0 ;
163
239
static const uint32_t MAX_RETRY = 10 , RETRY_DELAY_MS = 1 ;
164
240
do {
165
241
if (retry != 0 )
166
242
Cy_SysLib_Delay (RETRY_DELAY_MS );
243
+ uint32_t savedIntrStatus = cyhal_system_critical_section_enter ();
167
244
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 );
168
248
++ retry ;
169
249
} while (rslt == CY_RTC_INVALID_STATE && retry < MAX_RETRY );
250
+
170
251
while (CY_RTC_BUSY == Cy_RTC_GetSyncStatus ()) { }
252
+
171
253
if (rslt == CY_RSLT_SUCCESS )
172
- cyhal_rtc_initialized = CYHAL_RTC_STATE_TIME_SET ;
254
+ set_rtc_state ( CYHAL_RTC_STATE_TIME_SET ) ;
173
255
return rslt ;
174
256
}
175
257
@@ -240,13 +322,13 @@ void cyhal_rtc_register_callback(cyhal_rtc_t *obj, cyhal_rtc_event_callback_t ca
240
322
cyhal_system_critical_section_exit (savedIntrStatus );
241
323
}
242
324
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 )
244
326
{
245
327
CY_ASSERT (NULL != obj );
246
328
CY_ASSERT (CYHAL_RTC_ALARM == event );
247
329
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 );
250
332
}
251
333
252
334
#if defined(__cplusplus )
0 commit comments