mirror of https://github.com/ARMmbed/mbed-os.git
Store RTC century and RTC state information in persistent BREG register.
parent
3fdb820b26
commit
563edb294d
|
|
@ -30,6 +30,25 @@
|
||||||
#include "cyhal_rtc.h"
|
#include "cyhal_rtc.h"
|
||||||
#include "cyhal_system.h"
|
#include "cyhal_system.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \addtogroup group_hal_psoc6_rtc RTC (Real Time Clock)
|
||||||
|
* \ingroup group_hal_psoc6
|
||||||
|
* \{
|
||||||
|
*
|
||||||
|
* Internally the PSoC6 RTC only stores the year as a two digit BCD value
|
||||||
|
* (0-99); no century information is stored. On RTC initialization the HAL must,
|
||||||
|
* as a result, assume a default century. If cyhal_rtc_write has been called
|
||||||
|
* with a different century than the default, its value must be stored and that
|
||||||
|
* value must persist through deep sleep, hibernate, software resets, etc. PSoC6
|
||||||
|
* hardware provides a number of BREG registers which exist in the BACKUP domain
|
||||||
|
* and will persist over these power modes and resets. The HAL uses the highest
|
||||||
|
* indexed BACKUP->BREG register to store the century for the RTC.
|
||||||
|
*
|
||||||
|
* Therefore do not use the highest indexed BACKUP->BREG register as it is
|
||||||
|
* reserved for internal HAL usage.
|
||||||
|
* \} group_hal_psoc6_wdt
|
||||||
|
*/
|
||||||
|
|
||||||
#ifdef CY_IP_MXS40SRSS_RTC_INSTANCES
|
#ifdef CY_IP_MXS40SRSS_RTC_INSTANCES
|
||||||
|
|
||||||
#if defined(__cplusplus)
|
#if defined(__cplusplus)
|
||||||
|
|
@ -40,9 +59,15 @@ extern "C" {
|
||||||
#define CYHAL_RTC_STATE_ENABLED 1
|
#define CYHAL_RTC_STATE_ENABLED 1
|
||||||
#define CYHAL_RTC_STATE_TIME_SET 2
|
#define CYHAL_RTC_STATE_TIME_SET 2
|
||||||
#define CYHAL_RTC_DEFAULT_PRIORITY 5
|
#define CYHAL_RTC_DEFAULT_PRIORITY 5
|
||||||
#define CYHAL_RTC_CENTURY 2000
|
#define CYHAL_RTC_INIT_CENTURY 2000
|
||||||
#define CYHAL_TM_YEAR_BASE 1900
|
#define CYHAL_TM_YEAR_BASE 1900
|
||||||
|
|
||||||
|
#define CYHAL_RTC_BREG (BACKUP->BREG[SRSS_BACKUP_NUM_BREG-1])
|
||||||
|
#define CYHAL_RTC_BREG_CENTURY_Pos 0UL
|
||||||
|
#define CYHAL_RTC_BREG_CENTURY_Msk 0x0000FFFFUL
|
||||||
|
#define CYHAL_RTC_BREG_STATE_Pos 16UL
|
||||||
|
#define CYHAL_RTC_BREG_STATE_Msk 0xFFFF0000UL
|
||||||
|
|
||||||
/** Wrapper around the PDL Cy_RTC_DeepSleepCallback to adapt the function signature */
|
/** Wrapper around the PDL Cy_RTC_DeepSleepCallback to adapt the function signature */
|
||||||
static cy_en_syspm_status_t cyhal_rtc_syspm_callback(cy_stc_syspm_callback_params_t *params, cy_en_syspm_callback_mode_t mode)
|
static cy_en_syspm_status_t cyhal_rtc_syspm_callback(cy_stc_syspm_callback_params_t *params, cy_en_syspm_callback_mode_t mode)
|
||||||
{
|
{
|
||||||
|
|
@ -59,7 +84,32 @@ static cy_stc_syspm_callback_t cyhal_rtc_pm_cb = {
|
||||||
|
|
||||||
static cyhal_rtc_event_callback_t cyhal_rtc_user_handler;
|
static cyhal_rtc_event_callback_t cyhal_rtc_user_handler;
|
||||||
static void *cyhal_rtc_handler_arg;
|
static void *cyhal_rtc_handler_arg;
|
||||||
static uint8_t cyhal_rtc_initialized = CYHAL_RTC_STATE_UNINITIALIZED;
|
|
||||||
|
/* Returns century portion of BREG register used to store century info */
|
||||||
|
static inline uint16_t get_rtc_century()
|
||||||
|
{
|
||||||
|
return _FLD2VAL(CYHAL_RTC_BREG_CENTURY, CYHAL_RTC_BREG);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sets century portion of BREG register used to store century info */
|
||||||
|
static inline void set_rtc_century(uint16_t century)
|
||||||
|
{
|
||||||
|
CYHAL_RTC_BREG &= CYHAL_RTC_BREG_STATE_Msk;
|
||||||
|
CYHAL_RTC_BREG |= _VAL2FLD(CYHAL_RTC_BREG_CENTURY, century);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns state portion of BREG register used to store century info */
|
||||||
|
static inline uint16_t get_rtc_state()
|
||||||
|
{
|
||||||
|
return _FLD2VAL(CYHAL_RTC_BREG_STATE, CYHAL_RTC_BREG);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sets state portion of BREG register used to store century info */
|
||||||
|
static inline void set_rtc_state(uint16_t init)
|
||||||
|
{
|
||||||
|
CYHAL_RTC_BREG &= CYHAL_RTC_BREG_CENTURY_Msk;
|
||||||
|
CYHAL_RTC_BREG |= _VAL2FLD(CYHAL_RTC_BREG_STATE, init);
|
||||||
|
}
|
||||||
|
|
||||||
/** Wrapper around the PDL RTC interrupt handler to adapt the function signature */
|
/** Wrapper around the PDL RTC interrupt handler to adapt the function signature */
|
||||||
static void cyhal_rtc_internal_handler(void)
|
static void cyhal_rtc_internal_handler(void)
|
||||||
|
|
@ -67,7 +117,6 @@ static void cyhal_rtc_internal_handler(void)
|
||||||
Cy_RTC_Interrupt(dst, NULL != dst);
|
Cy_RTC_Interrupt(dst, NULL != dst);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Override weak function from PDL */
|
|
||||||
void Cy_RTC_Alarm1Interrupt(void)
|
void Cy_RTC_Alarm1Interrupt(void)
|
||||||
{
|
{
|
||||||
if (NULL != cyhal_rtc_user_handler)
|
if (NULL != cyhal_rtc_user_handler)
|
||||||
|
|
@ -76,24 +125,50 @@ void Cy_RTC_Alarm1Interrupt(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Cy_RTC_CenturyInterrupt(void)
|
||||||
|
{
|
||||||
|
set_rtc_century(get_rtc_century() + 100);
|
||||||
|
}
|
||||||
|
|
||||||
cy_rslt_t cyhal_rtc_init(cyhal_rtc_t *obj)
|
cy_rslt_t cyhal_rtc_init(cyhal_rtc_t *obj)
|
||||||
{
|
{
|
||||||
CY_ASSERT(NULL != obj);
|
CY_ASSERT(NULL != obj);
|
||||||
cy_rslt_t rslt = CY_RSLT_SUCCESS;
|
cy_rslt_t rslt = CY_RSLT_SUCCESS;
|
||||||
if (cyhal_rtc_initialized == CYHAL_RTC_STATE_UNINITIALIZED)
|
if (get_rtc_state() == CYHAL_RTC_STATE_UNINITIALIZED)
|
||||||
{
|
{
|
||||||
static const cy_stc_sysint_t irqCfg = {.intrSrc = srss_interrupt_backup_IRQn, .intrPriority = CYHAL_RTC_DEFAULT_PRIORITY};
|
if (Cy_RTC_IsExternalResetOccurred())
|
||||||
Cy_SysInt_Init(&irqCfg, &cyhal_rtc_internal_handler);
|
{
|
||||||
|
// Reset to default time
|
||||||
|
static const cy_stc_rtc_config_t defaultTime = {
|
||||||
|
.dayOfWeek = CY_RTC_SATURDAY,
|
||||||
|
.date = 1,
|
||||||
|
.month = 1,
|
||||||
|
.year = 0,
|
||||||
|
};
|
||||||
|
Cy_RTC_SetDateAndTime(&defaultTime);
|
||||||
|
set_rtc_century(CYHAL_RTC_INIT_CENTURY);
|
||||||
|
}
|
||||||
|
|
||||||
if (Cy_SysPm_RegisterCallback(&cyhal_rtc_pm_cb))
|
if (Cy_SysPm_RegisterCallback(&cyhal_rtc_pm_cb))
|
||||||
{
|
{
|
||||||
cyhal_rtc_initialized = CYHAL_RTC_STATE_ENABLED;
|
set_rtc_state(CYHAL_RTC_STATE_ENABLED);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
rslt = CY_RSLT_RTC_NOT_INITIALIZED;
|
rslt = CY_RSLT_RTC_NOT_INITIALIZED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if(get_rtc_state() == CYHAL_RTC_STATE_ENABLED || get_rtc_state() == CYHAL_RTC_STATE_TIME_SET)
|
||||||
|
{
|
||||||
|
if(Cy_RTC_GetInterruptStatus() & CY_RTC_INTR_CENTURY)
|
||||||
|
Cy_RTC_CenturyInterrupt();
|
||||||
|
}
|
||||||
|
|
||||||
|
Cy_RTC_ClearInterrupt(CY_RTC_INTR_CENTURY);
|
||||||
|
Cy_RTC_SetInterruptMask(CY_RTC_INTR_CENTURY);
|
||||||
|
static const cy_stc_sysint_t irqCfg = {.intrSrc = srss_interrupt_backup_IRQn, .intrPriority = CYHAL_RTC_DEFAULT_PRIORITY};
|
||||||
|
Cy_SysInt_Init(&irqCfg, &cyhal_rtc_internal_handler);
|
||||||
|
|
||||||
if (rslt == CY_RSLT_SUCCESS)
|
if (rslt == CY_RSLT_SUCCESS)
|
||||||
{
|
{
|
||||||
dst = NULL;
|
dst = NULL;
|
||||||
|
|
@ -108,25 +183,28 @@ void cyhal_rtc_free(cyhal_rtc_t *obj)
|
||||||
CY_ASSERT(NULL != obj);
|
CY_ASSERT(NULL != obj);
|
||||||
NVIC_DisableIRQ(srss_interrupt_backup_IRQn);
|
NVIC_DisableIRQ(srss_interrupt_backup_IRQn);
|
||||||
|
|
||||||
|
Cy_RTC_SetInterruptMask(CY_RTC_INTR_CENTURY);
|
||||||
dst = NULL;
|
dst = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cyhal_rtc_is_enabled(cyhal_rtc_t *obj)
|
bool cyhal_rtc_is_enabled(cyhal_rtc_t *obj)
|
||||||
{
|
{
|
||||||
CY_ASSERT(NULL != obj);
|
CY_ASSERT(NULL != obj);
|
||||||
return (cyhal_rtc_initialized == CYHAL_RTC_STATE_TIME_SET);
|
return (get_rtc_state() == CYHAL_RTC_STATE_TIME_SET);
|
||||||
}
|
}
|
||||||
|
|
||||||
cy_rslt_t cyhal_rtc_read(cyhal_rtc_t *obj, struct tm *time)
|
cy_rslt_t cyhal_rtc_read(cyhal_rtc_t *obj, struct tm *time)
|
||||||
{
|
{
|
||||||
// The number of days that precede each month of the year, not including Feb 29
|
|
||||||
CY_ASSERT(NULL != obj);
|
CY_ASSERT(NULL != obj);
|
||||||
|
// The number of days that precede each month of the year, not including Feb 29
|
||||||
static const uint16_t CUMULATIVE_DAYS[] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
|
static const uint16_t CUMULATIVE_DAYS[] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
|
||||||
|
|
||||||
cy_stc_rtc_config_t dateTime;
|
cy_stc_rtc_config_t dateTime;
|
||||||
uint32_t savedIntrStatus = cyhal_system_critical_section_enter();
|
uint32_t savedIntrStatus = cyhal_system_critical_section_enter();
|
||||||
Cy_RTC_GetDateAndTime(&dateTime);
|
Cy_RTC_GetDateAndTime(&dateTime);
|
||||||
int year = dateTime.year + CYHAL_RTC_CENTURY;
|
int year = dateTime.year + get_rtc_century();
|
||||||
cyhal_system_critical_section_exit(savedIntrStatus);
|
cyhal_system_critical_section_exit(savedIntrStatus);
|
||||||
|
|
||||||
time->tm_sec = dateTime.sec;
|
time->tm_sec = dateTime.sec;
|
||||||
time->tm_min = dateTime.min;
|
time->tm_min = dateTime.min;
|
||||||
time->tm_hour = dateTime.hour;
|
time->tm_hour = dateTime.hour;
|
||||||
|
|
@ -137,16 +215,13 @@ cy_rslt_t cyhal_rtc_read(cyhal_rtc_t *obj, struct tm *time)
|
||||||
time->tm_yday = CUMULATIVE_DAYS[time->tm_mon] + dateTime.date - 1u +
|
time->tm_yday = CUMULATIVE_DAYS[time->tm_mon] + dateTime.date - 1u +
|
||||||
((dateTime.month >= 3 && Cy_RTC_IsLeapYear(year)) ? 1u : 0u);
|
((dateTime.month >= 3 && Cy_RTC_IsLeapYear(year)) ? 1u : 0u);
|
||||||
time->tm_isdst = -1;
|
time->tm_isdst = -1;
|
||||||
|
|
||||||
return CY_RSLT_SUCCESS;
|
return CY_RSLT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
cy_rslt_t cyhal_rtc_write(cyhal_rtc_t *obj, const struct tm *time)
|
cy_rslt_t cyhal_rtc_write(cyhal_rtc_t *obj, const struct tm *time)
|
||||||
{
|
{
|
||||||
CY_ASSERT(NULL != obj);
|
CY_ASSERT(NULL != obj);
|
||||||
int year = CYHAL_TM_YEAR_BASE + time->tm_year;
|
|
||||||
if (year < 2000 || year > 2099) {
|
|
||||||
return CY_RSLT_RTC_BAD_ARGUMENT;
|
|
||||||
}
|
|
||||||
uint32_t year2digit = time->tm_year % 100;
|
uint32_t year2digit = time->tm_year % 100;
|
||||||
cy_stc_rtc_config_t newtime = {
|
cy_stc_rtc_config_t newtime = {
|
||||||
.sec = time->tm_sec,
|
.sec = time->tm_sec,
|
||||||
|
|
@ -158,18 +233,25 @@ cy_rslt_t cyhal_rtc_write(cyhal_rtc_t *obj, const struct tm *time)
|
||||||
.month = time->tm_mon + 1,
|
.month = time->tm_mon + 1,
|
||||||
.year = year2digit
|
.year = year2digit
|
||||||
};
|
};
|
||||||
|
|
||||||
cy_rslt_t rslt;
|
cy_rslt_t rslt;
|
||||||
uint32_t retry = 0;
|
uint32_t retry = 0;
|
||||||
static const uint32_t MAX_RETRY = 10, RETRY_DELAY_MS = 1;
|
static const uint32_t MAX_RETRY = 10, RETRY_DELAY_MS = 1;
|
||||||
do {
|
do {
|
||||||
if (retry != 0)
|
if (retry != 0)
|
||||||
Cy_SysLib_Delay(RETRY_DELAY_MS);
|
Cy_SysLib_Delay(RETRY_DELAY_MS);
|
||||||
|
uint32_t savedIntrStatus = cyhal_system_critical_section_enter();
|
||||||
rslt = (cy_rslt_t)Cy_RTC_SetDateAndTime(&newtime);
|
rslt = (cy_rslt_t)Cy_RTC_SetDateAndTime(&newtime);
|
||||||
|
if (rslt == CY_RSLT_SUCCESS)
|
||||||
|
set_rtc_century(time->tm_year - year2digit + CYHAL_TM_YEAR_BASE);
|
||||||
|
cyhal_system_critical_section_exit(savedIntrStatus);
|
||||||
++retry;
|
++retry;
|
||||||
} while (rslt == CY_RTC_INVALID_STATE && retry < MAX_RETRY);
|
} while (rslt == CY_RTC_INVALID_STATE && retry < MAX_RETRY);
|
||||||
|
|
||||||
while (CY_RTC_BUSY == Cy_RTC_GetSyncStatus()) { }
|
while (CY_RTC_BUSY == Cy_RTC_GetSyncStatus()) { }
|
||||||
|
|
||||||
if (rslt == CY_RSLT_SUCCESS)
|
if (rslt == CY_RSLT_SUCCESS)
|
||||||
cyhal_rtc_initialized = CYHAL_RTC_STATE_TIME_SET;
|
set_rtc_state(CYHAL_RTC_STATE_TIME_SET);
|
||||||
return rslt;
|
return rslt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -240,13 +322,13 @@ void cyhal_rtc_register_callback(cyhal_rtc_t *obj, cyhal_rtc_event_callback_t ca
|
||||||
cyhal_system_critical_section_exit(savedIntrStatus);
|
cyhal_system_critical_section_exit(savedIntrStatus);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cyhal_rtc_enable_event(cyhal_rtc_t *obj, cyhal_rtc_event_t event, uint8_t intrPriority, bool enable)
|
void cyhal_rtc_enable_event(cyhal_rtc_t *obj, cyhal_rtc_event_t event, uint8_t intr_priority, bool enable)
|
||||||
{
|
{
|
||||||
CY_ASSERT(NULL != obj);
|
CY_ASSERT(NULL != obj);
|
||||||
CY_ASSERT(CYHAL_RTC_ALARM == event);
|
CY_ASSERT(CYHAL_RTC_ALARM == event);
|
||||||
Cy_RTC_ClearInterrupt(CY_RTC_INTR_ALARM1 | CY_RTC_INTR_ALARM2);
|
Cy_RTC_ClearInterrupt(CY_RTC_INTR_ALARM1 | CY_RTC_INTR_ALARM2);
|
||||||
Cy_RTC_SetInterruptMask(enable ? CY_RTC_INTR_ALARM1 : 0);
|
Cy_RTC_SetInterruptMask((enable ? CY_RTC_INTR_ALARM1 : 0) | CY_RTC_INTR_CENTURY);
|
||||||
NVIC_SetPriority(srss_interrupt_backup_IRQn, intrPriority);
|
NVIC_SetPriority(srss_interrupt_backup_IRQn, intr_priority);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(__cplusplus)
|
#if defined(__cplusplus)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue