2022-06-24 22:28:36 +08:00

230 lines
7.3 KiB
C

/*
* Copyright 2021 MindMotion Microelectronics Co., Ltd.
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "hal_rtc.h"
/* Initialize RTC. */
void RTC_Init(RTC_Type * RTCx, RTC_Init_Type * init)
{
uint32_t temp = ( (init->ClockFreq / init->CountFreq) - 1u);
RTC_PutPrescalerValue(RTCx, temp);
}
/* Get the current status flags of the RTC module. */
uint32_t RTC_GetStatus(RTC_Type * RTCx)
{
return RTCx->CRL;
}
/* Clear the status flag of the RTC module. */
void RTC_ClearStatus(RTC_Type * RTCx, uint32_t status)
{
RTCx->CRL &= ~status;
}
/* Set the counter hopping frequency, open configration module before put data into RTC register. */
void RTC_PutPrescalerValue(RTC_Type * RTCx, uint32_t div)
{
RTCx->CRL |= RTC_CRL_CNF_MASK; /* Enable the configuration mode. */
RTCx->PRLH = div >> 16u; /* Setup the upper 16-bit value of prescaler, RTC_PRL[19:0] = (fRTC_CLK / fSC_CLK ) - 1u. */
RTCx->PRLL = div; /* Setup the lower 16-bit value of prescaler. */
RTCx->CRL &= ~RTC_CRL_CNF_MASK; /* Disable the configuration mode. */
}
/* Configure the value at which the counter starts counting. */
void RTC_PutCounterValue(RTC_Type * RTCx, uint32_t cnt)
{
RTCx->CRL |= RTC_CRL_CNF_MASK; /* Enable the configuration mode. */
RTCx->CNTH = cnt >> 16u; /* Setup the upper 16-bit value of counter. */
RTCx->CNTL = cnt; /* Setup the lower 16-bit value of counter. */
RTCx->CRL &= ~RTC_CRL_CNF_MASK; /* Disable the configuration mode. */
}
/* Configure alarm clock response time. */
void RTC_PutAlarmValue(RTC_Type * RTCx, uint32_t alarm)
{
RTCx->CRL |= RTC_CRL_CNF_MASK; /* Enable the configuration mode. */
RTCx->ALRH = alarm >> 16u; /* Setup the upper 16-bit value of alarm counter. */
RTCx->ALRL = alarm; /* Setup the lower 16-bit value of alarm counter. */
RTCx->CRL &= ~RTC_CRL_CNF_MASK; /* Disable the configuration mode. */
}
/* Get the current value from counter of RTC module. */
uint32_t RTC_GetCounterValue(RTC_Type * RTCx)
{
return ( (RTCx->CNTH << 16u) | RTCx->CNTL );
}
/* Get the alarm clock response time */
uint32_t RTC_GetAlarmValue(RTC_Type * RTCx)
{
return ( (RTCx->ALRH << 16u) | RTCx->ALRL);
}
/* Enable RTC interrupt of RTC module. */
void RTC_EnableInterrupts(RTC_Type * RTCx, uint32_t interrupts, bool enable)
{
if (enable)
{
RTCx->CRH |= interrupts;
}
else
{
RTCx->CRH &= ~interrupts;
}
}
/* Get the interrupts status flags of the RTC module. */
uint32_t RTC_GetInterruptStatus(RTC_Type * RTCx)
{
return (RTCx->CRL & RTCx->CRH);
}
/* Clear the status of RTC interrupt. */
void RTC_ClearInterruptStatus(RTC_Type * RTCx, uint32_t interrupts)
{
RTCx->CRL &= ~interrupts;
}
/* Judging whether the current year is a leap year, an ordinary leap year or a century leap year. */
bool RTC_JudgeLeapYear(uint16_t years)
{
if (years % 4u == 0u)
{
if (years % 100u == 0u)
{
if (years % 400u == 0u)
{
return true; /* Century leap year. */
}
else
{
return false;
}
}
else
{
return true; /* Ordinary leap year. */
}
}
else
{
return false;
}
}
/* Month correction table, used for calculation of month. */
const uint8_t month_table[12u] = {31u, 28u, 31u, 30u, 31u, 30u, 31u, 31u, 30u, 31u, 30u, 31u};
/* Setup initialization time, calculate the year, month, day, hour, minute and second as the total number of seconds. */
void RTC_SetTime(RTC_Type * RTCx, RTC_Time_Type * time)
{
/* Calculate the total number of seconds of the current configuration time. */
uint32_t seccnt = 0u;
/* Calculate the number of seconds from the lowest years to the current setup years. */
for (uint16_t years = time->Lyears; years < time->Years; years++)
{
if ( RTC_JudgeLeapYear(years) )
{
seccnt += 31622400u; /* The number of seconds in leap year is 31622400. */
}
else
{
seccnt += 31536000u; /* The number of seconds in normal year is 31622400. */
}
}
/* Add up the seconds of the previous month. */
time->Months -= 1u; /* The month count starts from 0 instead of 1, so current months - 1. */
for (uint16_t months = 0u; months < time->Months; months++)
{
seccnt += (uint32_t)month_table[months] * 86400u; /* Calculate the number of seconds of months, the total number of seconds in a day is 86400. */
if ( ( RTC_JudgeLeapYear(time->Years) ) && (months == 1u) ) /* The time is in a leap year and february, add the number of seconds in one day. */
{
seccnt += 86400u; /* The number of seconds in day is 86400. */
}
}
/* Add up the seconds of the previous date. */
seccnt += (uint32_t)(time->Days - 1u) * 86400u; /* The day set for initialization is less than 24 hours, which needs to be subtracted by one day. */
seccnt += (uint32_t)(time->Hours) * 3600u; /* There are 3600 seconds in a hour. */
seccnt += (uint32_t)(time->Mins) * 60u; /* There are 60 seconds in a minute. */
seccnt += (time->Secs);
/* Configrate counter value. */
RTC_PutCounterValue(RTCx, seccnt); /* Put data into counter. */
}
/* Calculate the total number of seconds as year, month, day, hour, minute and second.. */
void RTC_CalcTime(RTC_Type * RTCx, RTC_Time_Type * time)
{
uint32_t count = RTC_GetCounterValue(RTCx); /* Get current seconds count. */
/* Calculated in days. */
uint16_t years = time->Lyears;
uint32_t days = count / 86400u;
for (; days >= 365u; days -= 365u)
{
if ( RTC_JudgeLeapYear(years) ) /* Determine whether it is a leap year. */
{
if (days >= 366u)
{
days -= 1u;
}
else
{
break;
}
}
years++;
}
time->Years = years; /* Get current years. */
uint16_t months = 0u;
for (; days >= 28u; days -= 28u)
{
if ( ( true == RTC_JudgeLeapYear(time->Years) ) && (months == 1u) ) /* The time is February of leap year. */
{
if (days >= 29u)
{
days -= 1u;
}
else
{
break;
}
}
else
{
if (days >= month_table[months]) /* Reach the maximum number of days in the current month. */
{
days = days - month_table[months] + 28u;
}
else
{
break;
}
}
months++;
}
time->Months = months + 1u; /* Get current months. */
time->Days = days + 1u; /* Get current days. */
time->Hours = ( count % 86400u) / 3600u; /* Get current hours. */
time->Mins = ((count % 86400u) % 3600u) / 60u; /* Get current minutes. */
time->Secs = ((count % 86400u) % 3600u) % 60u; /* Get current seconds. */
}
/* Setup the alarm response time. */
void RTC_SetAlarm(RTC_Type * RTCx, RTC_Time_Type * time)
{
uint32_t value = RTC_GetCounterValue(RTCx); /* Get the current total number of seconds. */
RTC_PutAlarmValue(RTCx, value + time->AlarmTime); /* Set alarm respond time. */
}
/* EOF. */