| /* |
| * Copyright (c) 2015, Freescale Semiconductor, Inc. |
| * Copyright 2016-2017 NXP |
| * All rights reserved. |
| * |
| * SPDX-License-Identifier: BSD-3-Clause |
| */ |
| |
| #include "fsl_rtc.h" |
| |
| /******************************************************************************* |
| * Definitions |
| ******************************************************************************/ |
| |
| /* Component ID definition, used by tools. */ |
| #ifndef FSL_COMPONENT_ID |
| #define FSL_COMPONENT_ID "platform.drivers.rtc" |
| #endif |
| |
| #define SECONDS_IN_A_DAY (86400U) |
| #define SECONDS_IN_A_HOUR (3600U) |
| #define SECONDS_IN_A_MINUTE (60U) |
| #define DAYS_IN_A_YEAR (365U) |
| #define YEAR_RANGE_START (1970U) |
| #define YEAR_RANGE_END (2099U) |
| |
| /******************************************************************************* |
| * Prototypes |
| ******************************************************************************/ |
| /*! |
| * @brief Checks whether the date and time passed in is valid |
| * |
| * @param datetime Pointer to structure where the date and time details are stored |
| * |
| * @return Returns false if the date & time details are out of range; true if in range |
| */ |
| static bool RTC_CheckDatetimeFormat(const rtc_datetime_t *datetime); |
| |
| /*! |
| * @brief Converts time data from datetime to seconds |
| * |
| * @param datetime Pointer to datetime structure where the date and time details are stored |
| * |
| * @return The result of the conversion in seconds |
| */ |
| static uint32_t RTC_ConvertDatetimeToSeconds(const rtc_datetime_t *datetime); |
| |
| /*! |
| * @brief Converts time data from seconds to a datetime structure |
| * |
| * @param seconds Seconds value that needs to be converted to datetime format |
| * @param datetime Pointer to the datetime structure where the result of the conversion is stored |
| */ |
| static void RTC_ConvertSecondsToDatetime(uint32_t seconds, rtc_datetime_t *datetime); |
| |
| /******************************************************************************* |
| * Code |
| ******************************************************************************/ |
| static bool RTC_CheckDatetimeFormat(const rtc_datetime_t *datetime) |
| { |
| assert(datetime); |
| |
| /* Table of days in a month for a non leap year. First entry in the table is not used, |
| * valid months start from 1 |
| */ |
| uint8_t daysPerMonth[] = {0U, 31U, 28U, 31U, 30U, 31U, 30U, 31U, 31U, 30U, 31U, 30U, 31U}; |
| |
| /* Check year, month, hour, minute, seconds */ |
| if ((datetime->year < YEAR_RANGE_START) || (datetime->year > YEAR_RANGE_END) || (datetime->month > 12U) || |
| (datetime->month < 1U) || (datetime->hour >= 24U) || (datetime->minute >= 60U) || (datetime->second >= 60U)) |
| { |
| /* If not correct then error*/ |
| return false; |
| } |
| |
| /* Adjust the days in February for a leap year */ |
| if ((((datetime->year & 3U) == 0) && (datetime->year % 100 != 0)) || (datetime->year % 400 == 0)) |
| { |
| daysPerMonth[2] = 29U; |
| } |
| |
| /* Check the validity of the day */ |
| if ((datetime->day > daysPerMonth[datetime->month]) || (datetime->day < 1U)) |
| { |
| return false; |
| } |
| |
| return true; |
| } |
| |
| static uint32_t RTC_ConvertDatetimeToSeconds(const rtc_datetime_t *datetime) |
| { |
| assert(datetime); |
| |
| /* Number of days from begin of the non Leap-year*/ |
| /* Number of days from begin of the non Leap-year*/ |
| uint16_t monthDays[] = {0U, 0U, 31U, 59U, 90U, 120U, 151U, 181U, 212U, 243U, 273U, 304U, 334U}; |
| uint32_t seconds; |
| |
| /* Compute number of days from 1970 till given year*/ |
| seconds = (datetime->year - 1970U) * DAYS_IN_A_YEAR; |
| /* Add leap year days */ |
| seconds += ((datetime->year / 4) - (1970U / 4)); |
| /* Add number of days till given month*/ |
| seconds += monthDays[datetime->month]; |
| /* Add days in given month. We subtract the current day as it is |
| * represented in the hours, minutes and seconds field*/ |
| seconds += (datetime->day - 1); |
| /* For leap year if month less than or equal to Febraury, decrement day counter*/ |
| if ((!(datetime->year & 3U)) && (datetime->month <= 2U)) |
| { |
| seconds--; |
| } |
| |
| seconds = (seconds * SECONDS_IN_A_DAY) + (datetime->hour * SECONDS_IN_A_HOUR) + |
| (datetime->minute * SECONDS_IN_A_MINUTE) + datetime->second; |
| |
| return seconds; |
| } |
| |
| static void RTC_ConvertSecondsToDatetime(uint32_t seconds, rtc_datetime_t *datetime) |
| { |
| assert(datetime); |
| |
| uint32_t x; |
| uint32_t secondsRemaining, days; |
| uint16_t daysInYear; |
| /* Table of days in a month for a non leap year. First entry in the table is not used, |
| * valid months start from 1 |
| */ |
| uint8_t daysPerMonth[] = {0U, 31U, 28U, 31U, 30U, 31U, 30U, 31U, 31U, 30U, 31U, 30U, 31U}; |
| |
| /* Start with the seconds value that is passed in to be converted to date time format */ |
| secondsRemaining = seconds; |
| |
| /* Calcuate the number of days, we add 1 for the current day which is represented in the |
| * hours and seconds field |
| */ |
| days = secondsRemaining / SECONDS_IN_A_DAY + 1; |
| |
| /* Update seconds left*/ |
| secondsRemaining = secondsRemaining % SECONDS_IN_A_DAY; |
| |
| /* Calculate the datetime hour, minute and second fields */ |
| datetime->hour = secondsRemaining / SECONDS_IN_A_HOUR; |
| secondsRemaining = secondsRemaining % SECONDS_IN_A_HOUR; |
| datetime->minute = secondsRemaining / 60U; |
| datetime->second = secondsRemaining % SECONDS_IN_A_MINUTE; |
| |
| /* Calculate year */ |
| daysInYear = DAYS_IN_A_YEAR; |
| datetime->year = YEAR_RANGE_START; |
| while (days > daysInYear) |
| { |
| /* Decrease day count by a year and increment year by 1 */ |
| days -= daysInYear; |
| datetime->year++; |
| |
| /* Adjust the number of days for a leap year */ |
| if (datetime->year & 3U) |
| { |
| daysInYear = DAYS_IN_A_YEAR; |
| } |
| else |
| { |
| daysInYear = DAYS_IN_A_YEAR + 1; |
| } |
| } |
| |
| /* Adjust the days in February for a leap year */ |
| if (!(datetime->year & 3U)) |
| { |
| daysPerMonth[2] = 29U; |
| } |
| |
| for (x = 1U; x <= 12U; x++) |
| { |
| if (days <= daysPerMonth[x]) |
| { |
| datetime->month = x; |
| break; |
| } |
| else |
| { |
| days -= daysPerMonth[x]; |
| } |
| } |
| |
| datetime->day = days; |
| } |
| |
| /*! |
| * brief Ungates the RTC clock and configures the peripheral for basic operation. |
| * |
| * This function issues a software reset if the timer invalid flag is set. |
| * |
| * note This API should be called at the beginning of the application using the RTC driver. |
| * |
| * param base RTC peripheral base address |
| * param config Pointer to the user's RTC configuration structure. |
| */ |
| void RTC_Init(RTC_Type *base, const rtc_config_t *config) |
| { |
| assert(config); |
| |
| uint32_t reg; |
| |
| #if defined(RTC_CLOCKS) |
| #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) |
| CLOCK_EnableClock(kCLOCK_Rtc0); |
| #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ |
| #endif /* RTC_CLOCKS */ |
| |
| /* Issue a software reset if timer is invalid */ |
| if (RTC_GetStatusFlags(RTC) & kRTC_TimeInvalidFlag) |
| { |
| RTC_Reset(RTC); |
| } |
| |
| reg = base->CR; |
| /* Setup the update mode and supervisor access mode */ |
| #if !(defined(FSL_FEATURE_RTC_HAS_NO_CR_OSCE) && FSL_FEATURE_RTC_HAS_NO_CR_OSCE) |
| reg &= ~(RTC_CR_UM_MASK | RTC_CR_SUP_MASK); |
| reg |= RTC_CR_UM(config->updateMode) | RTC_CR_SUP(config->supervisorAccess); |
| #else |
| reg &= ~RTC_CR_UM_MASK; |
| reg |= RTC_CR_UM(config->updateMode); |
| #endif |
| |
| #if defined(FSL_FEATURE_RTC_HAS_WAKEUP_PIN_SELECTION) && FSL_FEATURE_RTC_HAS_WAKEUP_PIN_SELECTION |
| /* Setup the wakeup pin select */ |
| reg &= ~(RTC_CR_WPS_MASK); |
| reg |= RTC_CR_WPS(config->wakeupSelect); |
| #endif /* FSL_FEATURE_RTC_HAS_WAKEUP_PIN */ |
| base->CR = reg; |
| |
| /* Configure the RTC time compensation register */ |
| base->TCR = (RTC_TCR_CIR(config->compensationInterval) | RTC_TCR_TCR(config->compensationTime)); |
| |
| #if defined(FSL_FEATURE_RTC_HAS_TSIC) && FSL_FEATURE_RTC_HAS_TSIC |
| /* Configure RTC timer seconds interrupt to be generated once per second */ |
| base->IER &= ~(RTC_IER_TSIC_MASK | RTC_IER_TSIE_MASK); |
| #endif |
| } |
| |
| /*! |
| * brief Fills in the RTC config struct with the default settings. |
| * |
| * The default values are as follows. |
| * code |
| * config->wakeupSelect = false; |
| * config->updateMode = false; |
| * config->supervisorAccess = false; |
| * config->compensationInterval = 0; |
| * config->compensationTime = 0; |
| * endcode |
| * param config Pointer to the user's RTC configuration structure. |
| */ |
| void RTC_GetDefaultConfig(rtc_config_t *config) |
| { |
| assert(config); |
| |
| /* Initializes the configure structure to zero. */ |
| memset(config, 0, sizeof(*config)); |
| |
| /* Wakeup pin will assert if the RTC interrupt asserts or if the wakeup pin is turned on */ |
| config->wakeupSelect = false; |
| /* Registers cannot be written when locked */ |
| config->updateMode = false; |
| /* Non-supervisor mode write accesses are not supported and will generate a bus error */ |
| config->supervisorAccess = false; |
| /* Compensation interval used by the crystal compensation logic */ |
| config->compensationInterval = 0; |
| /* Compensation time used by the crystal compensation logic */ |
| config->compensationTime = 0; |
| } |
| |
| /*! |
| * brief Sets the RTC date and time according to the given time structure. |
| * |
| * The RTC counter must be stopped prior to calling this function because writes to the RTC |
| * seconds register fail if the RTC counter is running. |
| * |
| * param base RTC peripheral base address |
| * param datetime Pointer to the structure where the date and time details are stored. |
| * |
| * return kStatus_Success: Success in setting the time and starting the RTC |
| * kStatus_InvalidArgument: Error because the datetime format is incorrect |
| */ |
| status_t RTC_SetDatetime(RTC_Type *base, const rtc_datetime_t *datetime) |
| { |
| assert(datetime); |
| |
| /* Return error if the time provided is not valid */ |
| if (!(RTC_CheckDatetimeFormat(datetime))) |
| { |
| return kStatus_InvalidArgument; |
| } |
| |
| /* Set time in seconds */ |
| base->TSR = RTC_ConvertDatetimeToSeconds(datetime); |
| |
| return kStatus_Success; |
| } |
| |
| /*! |
| * brief Gets the RTC time and stores it in the given time structure. |
| * |
| * param base RTC peripheral base address |
| * param datetime Pointer to the structure where the date and time details are stored. |
| */ |
| void RTC_GetDatetime(RTC_Type *base, rtc_datetime_t *datetime) |
| { |
| assert(datetime); |
| |
| uint32_t seconds = 0; |
| |
| seconds = base->TSR; |
| RTC_ConvertSecondsToDatetime(seconds, datetime); |
| } |
| |
| /*! |
| * brief Sets the RTC alarm time. |
| * |
| * The function checks whether the specified alarm time is greater than the present |
| * time. If not, the function does not set the alarm and returns an error. |
| * |
| * param base RTC peripheral base address |
| * param alarmTime Pointer to the structure where the alarm time is stored. |
| * |
| * return kStatus_Success: success in setting the RTC alarm |
| * kStatus_InvalidArgument: Error because the alarm datetime format is incorrect |
| * kStatus_Fail: Error because the alarm time has already passed |
| */ |
| status_t RTC_SetAlarm(RTC_Type *base, const rtc_datetime_t *alarmTime) |
| { |
| assert(alarmTime); |
| |
| uint32_t alarmSeconds = 0; |
| uint32_t currSeconds = 0; |
| |
| /* Return error if the alarm time provided is not valid */ |
| if (!(RTC_CheckDatetimeFormat(alarmTime))) |
| { |
| return kStatus_InvalidArgument; |
| } |
| |
| alarmSeconds = RTC_ConvertDatetimeToSeconds(alarmTime); |
| |
| /* Get the current time */ |
| currSeconds = base->TSR; |
| |
| /* Return error if the alarm time has passed */ |
| if (alarmSeconds < currSeconds) |
| { |
| return kStatus_Fail; |
| } |
| |
| /* Set alarm in seconds*/ |
| base->TAR = alarmSeconds; |
| |
| return kStatus_Success; |
| } |
| |
| /*! |
| * brief Returns the RTC alarm time. |
| * |
| * param base RTC peripheral base address |
| * param datetime Pointer to the structure where the alarm date and time details are stored. |
| */ |
| void RTC_GetAlarm(RTC_Type *base, rtc_datetime_t *datetime) |
| { |
| assert(datetime); |
| |
| uint32_t alarmSeconds = 0; |
| |
| /* Get alarm in seconds */ |
| alarmSeconds = base->TAR; |
| |
| RTC_ConvertSecondsToDatetime(alarmSeconds, datetime); |
| } |
| |
| /*! |
| * brief Enables the selected RTC interrupts. |
| * |
| * param base RTC peripheral base address |
| * param mask The interrupts to enable. This is a logical OR of members of the |
| * enumeration ::rtc_interrupt_enable_t |
| */ |
| void RTC_EnableInterrupts(RTC_Type *base, uint32_t mask) |
| { |
| uint32_t tmp32 = 0U; |
| |
| /* RTC_IER */ |
| if (kRTC_TimeInvalidInterruptEnable == (kRTC_TimeInvalidInterruptEnable & mask)) |
| { |
| tmp32 |= RTC_IER_TIIE_MASK; |
| } |
| if (kRTC_TimeOverflowInterruptEnable == (kRTC_TimeOverflowInterruptEnable & mask)) |
| { |
| tmp32 |= RTC_IER_TOIE_MASK; |
| } |
| if (kRTC_AlarmInterruptEnable == (kRTC_AlarmInterruptEnable & mask)) |
| { |
| tmp32 |= RTC_IER_TAIE_MASK; |
| } |
| if (kRTC_SecondsInterruptEnable == (kRTC_SecondsInterruptEnable & mask)) |
| { |
| tmp32 |= RTC_IER_TSIE_MASK; |
| } |
| #if defined(FSL_FEATURE_RTC_HAS_MONOTONIC) && (FSL_FEATURE_RTC_HAS_MONOTONIC) |
| if (kRTC_MonotonicOverflowInterruptEnable == (kRTC_MonotonicOverflowInterruptEnable & mask)) |
| { |
| tmp32 |= RTC_IER_MOIE_MASK; |
| } |
| #endif /* FSL_FEATURE_RTC_HAS_MONOTONIC */ |
| base->IER |= tmp32; |
| |
| #if (defined(FSL_FEATURE_RTC_HAS_TIR) && FSL_FEATURE_RTC_HAS_TIR) |
| tmp32 = 0U; |
| |
| /* RTC_TIR */ |
| if (kRTC_TestModeInterruptEnable == (kRTC_TestModeInterruptEnable & mask)) |
| { |
| tmp32 |= RTC_TIR_TMIE_MASK; |
| } |
| if (kRTC_FlashSecurityInterruptEnable == (kRTC_FlashSecurityInterruptEnable & mask)) |
| { |
| tmp32 |= RTC_TIR_FSIE_MASK; |
| } |
| #if (defined(FSL_FEATURE_RTC_HAS_TIR_TPIE) && FSL_FEATURE_RTC_HAS_TIR_TPIE) |
| if (kRTC_TamperPinInterruptEnable == (kRTC_TamperPinInterruptEnable & mask)) |
| { |
| tmp32 |= RTC_TIR_TPIE_MASK; |
| } |
| #endif /* FSL_FEATURE_RTC_HAS_TIR_TPIE */ |
| #if (defined(FSL_FEATURE_RTC_HAS_TIR_SIE) && FSL_FEATURE_RTC_HAS_TIR_SIE) |
| if (kRTC_SecurityModuleInterruptEnable == (kRTC_SecurityModuleInterruptEnable & mask)) |
| { |
| tmp32 |= RTC_TIR_SIE_MASK; |
| } |
| #endif /* FSL_FEATURE_RTC_HAS_TIR_SIE */ |
| #if (defined(FSL_FEATURE_RTC_HAS_TIR_LCIE) && FSL_FEATURE_RTC_HAS_TIR_LCIE) |
| if (kRTC_LossOfClockInterruptEnable == (kRTC_LossOfClockInterruptEnable & mask)) |
| { |
| tmp32 |= RTC_TIR_LCIE_MASK; |
| } |
| #endif /* FSL_FEATURE_RTC_HAS_TIR_LCIE */ |
| base->TIR |= tmp32; |
| #endif /* FSL_FEATURE_RTC_HAS_TIR */ |
| } |
| |
| /*! |
| * brief Disables the selected RTC interrupts. |
| * |
| * param base RTC peripheral base address |
| * param mask The interrupts to enable. This is a logical OR of members of the |
| * enumeration ::rtc_interrupt_enable_t |
| */ |
| void RTC_DisableInterrupts(RTC_Type *base, uint32_t mask) |
| { |
| uint32_t tmp32 = 0U; |
| |
| /* RTC_IER */ |
| if (kRTC_TimeInvalidInterruptEnable == (kRTC_TimeInvalidInterruptEnable & mask)) |
| { |
| tmp32 |= RTC_IER_TIIE_MASK; |
| } |
| if (kRTC_TimeOverflowInterruptEnable == (kRTC_TimeOverflowInterruptEnable & mask)) |
| { |
| tmp32 |= RTC_IER_TOIE_MASK; |
| } |
| if (kRTC_AlarmInterruptEnable == (kRTC_AlarmInterruptEnable & mask)) |
| { |
| tmp32 |= RTC_IER_TAIE_MASK; |
| } |
| if (kRTC_SecondsInterruptEnable == (kRTC_SecondsInterruptEnable & mask)) |
| { |
| tmp32 |= RTC_IER_TSIE_MASK; |
| } |
| #if defined(FSL_FEATURE_RTC_HAS_MONOTONIC) && (FSL_FEATURE_RTC_HAS_MONOTONIC) |
| if (kRTC_MonotonicOverflowInterruptEnable == (kRTC_MonotonicOverflowInterruptEnable & mask)) |
| { |
| tmp32 |= RTC_IER_MOIE_MASK; |
| } |
| #endif /* FSL_FEATURE_RTC_HAS_MONOTONIC */ |
| base->IER &= (uint32_t)(~tmp32); |
| |
| #if (defined(FSL_FEATURE_RTC_HAS_TIR) && FSL_FEATURE_RTC_HAS_TIR) |
| tmp32 = 0U; |
| |
| /* RTC_TIR */ |
| if (kRTC_TestModeInterruptEnable == (kRTC_TestModeInterruptEnable & mask)) |
| { |
| tmp32 |= RTC_TIR_TMIE_MASK; |
| } |
| if (kRTC_FlashSecurityInterruptEnable == (kRTC_FlashSecurityInterruptEnable & mask)) |
| { |
| tmp32 |= RTC_TIR_FSIE_MASK; |
| } |
| #if (defined(FSL_FEATURE_RTC_HAS_TIR_TPIE) && FSL_FEATURE_RTC_HAS_TIR_TPIE) |
| if (kRTC_TamperPinInterruptEnable == (kRTC_TamperPinInterruptEnable & mask)) |
| { |
| tmp32 |= RTC_TIR_TPIE_MASK; |
| } |
| #endif /* FSL_FEATURE_RTC_HAS_TIR_TPIE */ |
| #if (defined(FSL_FEATURE_RTC_HAS_TIR_SIE) && FSL_FEATURE_RTC_HAS_TIR_SIE) |
| if (kRTC_SecurityModuleInterruptEnable == (kRTC_SecurityModuleInterruptEnable & mask)) |
| { |
| tmp32 |= RTC_TIR_SIE_MASK; |
| } |
| #endif /* FSL_FEATURE_RTC_HAS_TIR_SIE */ |
| #if (defined(FSL_FEATURE_RTC_HAS_TIR_LCIE) && FSL_FEATURE_RTC_HAS_TIR_LCIE) |
| if (kRTC_LossOfClockInterruptEnable == (kRTC_LossOfClockInterruptEnable & mask)) |
| { |
| tmp32 |= RTC_TIR_LCIE_MASK; |
| } |
| #endif /* FSL_FEATURE_RTC_HAS_TIR_LCIE */ |
| base->TIR &= (uint32_t)(~tmp32); |
| #endif /* FSL_FEATURE_RTC_HAS_TIR */ |
| } |
| |
| /*! |
| * brief Gets the enabled RTC interrupts. |
| * |
| * param base RTC peripheral base address |
| * |
| * return The enabled interrupts. This is the logical OR of members of the |
| * enumeration ::rtc_interrupt_enable_t |
| */ |
| uint32_t RTC_GetEnabledInterrupts(RTC_Type *base) |
| { |
| uint32_t tmp32 = 0U; |
| |
| /* RTC_IER */ |
| if (RTC_IER_TIIE_MASK == (RTC_IER_TIIE_MASK & base->IER)) |
| { |
| tmp32 |= kRTC_TimeInvalidInterruptEnable; |
| } |
| if (RTC_IER_TOIE_MASK == (RTC_IER_TOIE_MASK & base->IER)) |
| { |
| tmp32 |= kRTC_TimeOverflowInterruptEnable; |
| } |
| if (RTC_IER_TAIE_MASK == (RTC_IER_TAIE_MASK & base->IER)) |
| { |
| tmp32 |= kRTC_AlarmInterruptEnable; |
| } |
| if (RTC_IER_TSIE_MASK == (RTC_IER_TSIE_MASK & base->IER)) |
| { |
| tmp32 |= kRTC_SecondsInterruptEnable; |
| } |
| #if defined(FSL_FEATURE_RTC_HAS_MONOTONIC) && (FSL_FEATURE_RTC_HAS_MONOTONIC) |
| if (RTC_IER_MOIE_MASK == (RTC_IER_MOIE_MASK & base->IER)) |
| { |
| tmp32 |= kRTC_MonotonicOverflowInterruptEnable; |
| } |
| #endif /* FSL_FEATURE_RTC_HAS_MONOTONIC */ |
| |
| #if (defined(FSL_FEATURE_RTC_HAS_TIR) && FSL_FEATURE_RTC_HAS_TIR) |
| /* RTC_TIR */ |
| if (RTC_TIR_TMIE_MASK == (RTC_TIR_TMIE_MASK & base->TIR)) |
| { |
| tmp32 |= kRTC_TestModeInterruptEnable; |
| } |
| if (RTC_TIR_FSIE_MASK == (RTC_TIR_FSIE_MASK & base->TIR)) |
| { |
| tmp32 |= kRTC_FlashSecurityInterruptEnable; |
| } |
| #if (defined(FSL_FEATURE_RTC_HAS_TIR_TPIE) && FSL_FEATURE_RTC_HAS_TIR_TPIE) |
| if (RTC_TIR_TPIE_MASK == (RTC_TIR_TPIE_MASK & base->TIR)) |
| { |
| tmp32 |= kRTC_TamperPinInterruptEnable; |
| } |
| #endif /* FSL_FEATURE_RTC_HAS_TIR_TPIE */ |
| #if (defined(FSL_FEATURE_RTC_HAS_TIR_SIE) && FSL_FEATURE_RTC_HAS_TIR_SIE) |
| if (RTC_TIR_SIE_MASK == (RTC_TIR_SIE_MASK & base->TIR)) |
| { |
| tmp32 |= kRTC_SecurityModuleInterruptEnable; |
| } |
| #endif /* FSL_FEATURE_RTC_HAS_TIR_SIE */ |
| #if (defined(FSL_FEATURE_RTC_HAS_TIR_LCIE) && FSL_FEATURE_RTC_HAS_TIR_LCIE) |
| if (RTC_TIR_LCIE_MASK == (RTC_TIR_LCIE_MASK & base->TIR)) |
| { |
| tmp32 |= kRTC_LossOfClockInterruptEnable; |
| } |
| #endif /* FSL_FEATURE_RTC_HAS_TIR_LCIE */ |
| #endif /* FSL_FEATURE_RTC_HAS_TIR */ |
| |
| return tmp32; |
| } |
| |
| /*! |
| * brief Gets the RTC status flags. |
| * |
| * param base RTC peripheral base address |
| * |
| * return The status flags. This is the logical OR of members of the |
| * enumeration ::rtc_status_flags_t |
| */ |
| uint32_t RTC_GetStatusFlags(RTC_Type *base) |
| { |
| uint32_t tmp32 = 0U; |
| |
| /* RTC_SR */ |
| if (RTC_SR_TIF_MASK == (RTC_SR_TIF_MASK & base->SR)) |
| { |
| tmp32 |= kRTC_TimeInvalidFlag; |
| } |
| if (RTC_SR_TOF_MASK == (RTC_SR_TOF_MASK & base->SR)) |
| { |
| tmp32 |= kRTC_TimeOverflowFlag; |
| } |
| if (RTC_SR_TAF_MASK == (RTC_SR_TAF_MASK & base->SR)) |
| { |
| tmp32 |= kRTC_AlarmFlag; |
| } |
| #if defined(FSL_FEATURE_RTC_HAS_MONOTONIC) && (FSL_FEATURE_RTC_HAS_MONOTONIC) |
| if (RTC_SR_MOF_MASK == (RTC_SR_MOF_MASK & base->SR)) |
| { |
| tmp32 |= kRTC_MonotonicOverflowFlag; |
| } |
| #endif /* FSL_FEATURE_RTC_HAS_MONOTONIC */ |
| #if (defined(FSL_FEATURE_RTC_HAS_SR_TIDF) && FSL_FEATURE_RTC_HAS_SR_TIDF) |
| if (RTC_SR_TIDF_MASK == (RTC_SR_TIDF_MASK & base->SR)) |
| { |
| tmp32 |= kRTC_TamperInterruptDetectFlag; |
| } |
| #endif /* FSL_FEATURE_RTC_HAS_SR_TIDF */ |
| |
| #if (defined(FSL_FEATURE_RTC_HAS_TDR) && FSL_FEATURE_RTC_HAS_TDR) |
| /* RTC_TDR */ |
| if (RTC_TDR_TMF_MASK == (RTC_TDR_TMF_MASK & base->TDR)) |
| { |
| tmp32 |= kRTC_TestModeFlag; |
| } |
| if (RTC_TDR_FSF_MASK == (RTC_TDR_FSF_MASK & base->TDR)) |
| { |
| tmp32 |= kRTC_FlashSecurityFlag; |
| } |
| #if (defined(FSL_FEATURE_RTC_HAS_TDR_TPF) && FSL_FEATURE_RTC_HAS_TDR_TPF) |
| if (RTC_TDR_TPF_MASK == (RTC_TDR_TPF_MASK & base->TDR)) |
| { |
| tmp32 |= kRTC_TamperPinFlag; |
| } |
| #endif /* FSL_FEATURE_RTC_HAS_TDR_TPF */ |
| #if (defined(FSL_FEATURE_RTC_HAS_TDR_STF) && FSL_FEATURE_RTC_HAS_TDR_STF) |
| if (RTC_TDR_STF_MASK == (RTC_TDR_STF_MASK & base->TDR)) |
| { |
| tmp32 |= kRTC_SecurityTamperFlag; |
| } |
| #endif /* FSL_FEATURE_RTC_HAS_TDR_STF */ |
| #if (defined(FSL_FEATURE_RTC_HAS_TDR_LCTF) && FSL_FEATURE_RTC_HAS_TDR_LCTF) |
| if (RTC_TDR_LCTF_MASK == (RTC_TDR_LCTF_MASK & base->TDR)) |
| { |
| tmp32 |= kRTC_LossOfClockTamperFlag; |
| } |
| #endif /* FSL_FEATURE_RTC_HAS_TDR_LCTF */ |
| #endif /* FSL_FEATURE_RTC_HAS_TDR */ |
| |
| return tmp32; |
| } |
| |
| /*! |
| * brief Clears the RTC status flags. |
| * |
| * param base RTC peripheral base address |
| * param mask The status flags to clear. This is a logical OR of members of the |
| * enumeration ::rtc_status_flags_t |
| */ |
| void RTC_ClearStatusFlags(RTC_Type *base, uint32_t mask) |
| { |
| /* The alarm flag is cleared by writing to the TAR register */ |
| if (mask & kRTC_AlarmFlag) |
| { |
| base->TAR = 0U; |
| } |
| |
| /* The timer overflow flag is cleared by initializing the TSR register. |
| * The time counter should be disabled for this write to be successful |
| */ |
| if (mask & kRTC_TimeOverflowFlag) |
| { |
| base->TSR = 1U; |
| } |
| |
| /* The timer overflow flag is cleared by initializing the TSR register. |
| * The time counter should be disabled for this write to be successful |
| */ |
| if (mask & kRTC_TimeInvalidFlag) |
| { |
| base->TSR = 1U; |
| } |
| |
| #if (defined(FSL_FEATURE_RTC_HAS_TDR) && FSL_FEATURE_RTC_HAS_TDR) |
| /* To clear, write logic one to this flag after exiting from all test modes */ |
| if (kRTC_TestModeFlag == (kRTC_TestModeFlag & mask)) |
| { |
| base->TDR = RTC_TDR_TMF_MASK; |
| } |
| /* To clear, write logic one to this flag after flash security is enabled */ |
| if (kRTC_FlashSecurityFlag == (kRTC_FlashSecurityFlag & mask)) |
| { |
| base->TDR = RTC_TDR_FSF_MASK; |
| } |
| #if (defined(FSL_FEATURE_RTC_HAS_TDR_TPF) && FSL_FEATURE_RTC_HAS_TDR_TPF) |
| /* To clear, write logic one to the corresponding flag after that tamper pin negates */ |
| if (kRTC_TamperPinFlag == (kRTC_TamperPinFlag & mask)) |
| { |
| base->TDR = RTC_TDR_TPF_MASK; |
| } |
| #endif /* FSL_FEATURE_RTC_HAS_TDR_TPF */ |
| #if (defined(FSL_FEATURE_RTC_HAS_TDR_STF) && FSL_FEATURE_RTC_HAS_TDR_STF) |
| /* To clear, write logic one to this flag after security module has negated its tamper detect */ |
| if (kRTC_SecurityTamperFlag == (kRTC_SecurityTamperFlag & mask)) |
| { |
| base->TDR = RTC_TDR_STF_MASK; |
| } |
| #endif /* FSL_FEATURE_RTC_HAS_TDR_STF */ |
| #if (defined(FSL_FEATURE_RTC_HAS_TDR_LCTF) && FSL_FEATURE_RTC_HAS_TDR_LCTF) |
| /* To clear, write logic one to this flag after loss of clock negates */ |
| if (kRTC_LossOfClockTamperFlag == (kRTC_LossOfClockTamperFlag & mask)) |
| { |
| base->TDR = RTC_TDR_LCTF_MASK; |
| } |
| #endif /* FSL_FEATURE_RTC_HAS_TDR_LCTF */ |
| #endif /* FSL_FEATURE_RTC_HAS_TDR */ |
| } |
| |
| #if defined(FSL_FEATURE_RTC_HAS_MONOTONIC) && (FSL_FEATURE_RTC_HAS_MONOTONIC) |
| |
| /*! |
| * brief Reads the values of the Monotonic Counter High and Monotonic Counter Low and returns |
| * them as a single value. |
| * |
| * param base RTC peripheral base address |
| * param counter Pointer to variable where the value is stored. |
| */ |
| void RTC_GetMonotonicCounter(RTC_Type *base, uint64_t *counter) |
| { |
| assert(counter); |
| |
| *counter = (((uint64_t)base->MCHR << 32) | ((uint64_t)base->MCLR)); |
| } |
| |
| /*! |
| * brief Writes values Monotonic Counter High and Monotonic Counter Low by decomposing |
| * the given single value. The Monotonic Overflow Flag in RTC_SR is cleared due to the API. |
| * |
| * param base RTC peripheral base address |
| * param counter Counter value |
| */ |
| void RTC_SetMonotonicCounter(RTC_Type *base, uint64_t counter) |
| { |
| /* Prepare to initialize the register with the new value written */ |
| base->MER &= ~RTC_MER_MCE_MASK; |
| |
| base->MCHR = (uint32_t)((counter) >> 32); |
| base->MCLR = (uint32_t)(counter); |
| } |
| |
| /*! |
| * brief Increments the Monotonic Counter by one. |
| * |
| * Increments the Monotonic Counter (registers RTC_MCLR and RTC_MCHR accordingly) by setting |
| * the monotonic counter enable (MER[MCE]) and then writing to the RTC_MCLR register. A write to the |
| * monotonic counter low that causes it to overflow also increments the monotonic counter high. |
| * |
| * param base RTC peripheral base address |
| * |
| * return kStatus_Success: success |
| * kStatus_Fail: error occurred, either time invalid or monotonic overflow flag was found |
| */ |
| status_t RTC_IncrementMonotonicCounter(RTC_Type *base) |
| { |
| if (base->SR & (RTC_SR_MOF_MASK | RTC_SR_TIF_MASK)) |
| { |
| return kStatus_Fail; |
| } |
| |
| /* Prepare to switch to increment mode */ |
| base->MER |= RTC_MER_MCE_MASK; |
| /* Write anything so the counter increments*/ |
| base->MCLR = 1U; |
| |
| return kStatus_Success; |
| } |
| |
| #endif /* FSL_FEATURE_RTC_HAS_MONOTONIC */ |