Skip to content

Commit 563edb2

Browse files
Store RTC century and RTC state information in persistent BREG register.
1 parent 3fdb820 commit 563edb2

File tree

1 file changed

+100
-18
lines changed
  • targets/TARGET_Cypress/TARGET_PSOC6/psoc6csp/hal/source

1 file changed

+100
-18
lines changed

targets/TARGET_Cypress/TARGET_PSOC6/psoc6csp/hal/source/cyhal_rtc.c

Lines changed: 100 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,25 @@
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 */
4772
static 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

6085
static cyhal_rtc_event_callback_t cyhal_rtc_user_handler;
6186
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+
}
63113

64114
/** Wrapper around the PDL RTC interrupt handler to adapt the function signature */
65115
static void cyhal_rtc_internal_handler(void)
66116
{
67117
Cy_RTC_Interrupt(dst, NULL != dst);
68118
}
69119

70-
/* Override weak function from PDL */
71120
void 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+
79133
cy_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

114190
bool 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

120196
cy_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

143222
cy_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

Comments
 (0)