1 /*
2  * Copyright 2021 MindMotion Microelectronics Co., Ltd.
3  * All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  */
7 
8 #include "hal_rtc.h"
9 
10 /* Initialize RTC. */
RTC_Init(void)11 void RTC_Init(void)
12 {
13     /* Open access rights. */
14     RCC->BDCR |= RCC_BDCR_DBP_MASK;
15 
16     /* Reset BKP. */
17     RCC->BDCR |= RCC_BDCR_BDRST_MASK;
18     RCC->BDCR &= ~RCC_BDCR_BDRST_MASK;
19 
20     /* Enable clock source. */
21     RCC->BDCR |= RCC_BDCR_RTCSEL(1u);
22     RCC->BDCR &= ~RCC_BDCR_LSEON_MASK;
23     RCC->BDCR |= RCC_BDCR_LSEON_MASK;
24 
25     /* Clear register synchronization status. */
26     RTC->CRL &= ~RTC_CRL_RSF_MASK;
27 }
28 
29 /* Enable or disable access to RTC and backing registers. */
RTC_EnableAccess(bool enable)30 void RTC_EnableAccess(bool enable)
31 {
32     if (enable)
33     {
34         RCC->BDCR |= RCC_BDCR_DBP_MASK;
35     }
36     else
37     {
38         RCC->BDCR &= ~RCC_BDCR_DBP_MASK;
39     }
40 }
41 
42 /* Enable backup domain software reset, the register of BKP is reset by the backup domain, not reset during power reset and system reset. */
RTC_EnableReset(bool enable)43 void RTC_EnableReset(bool enable)
44 {
45     if (enable)
46     {
47         RCC->BDCR |= RCC_BDCR_BDRST_MASK;
48     }
49     else
50     {
51         RCC->BDCR &= ~RCC_BDCR_BDRST_MASK;
52     }
53 }
54 
55 /* Get the current status flags of the RTC module. */
RTC_GetStatus(void)56 uint32_t RTC_GetStatus(void)
57 {
58     return RTC->CRL;
59 }
60 
61 /* Clear the status flag of the RTC module. */
RTC_ClearStatus(uint32_t status)62 void RTC_ClearStatus(uint32_t status)
63 {
64     RTC->CRL &= ~status;
65 }
66 
67 /* Get RTC clock source status. */
RTC_GetClockStatus(void)68 uint32_t RTC_GetClockStatus(void)
69 {
70     return RCC->BDCR;
71 }
72 
73 /* Enable RTC clock. */
RTC_Enable(bool enable)74 void RTC_Enable(bool enable)
75 {
76     if (enable)
77     {
78         RCC->BDCR |= RCC_BDCR_RTCEN_MASK;
79     }
80     else
81     {
82         RCC->BDCR &= ~RCC_BDCR_RTCEN_MASK;
83     }
84 }
85 
86 /* Enable or disable the configuration mode, enable to enter configuration mode, this is a precondition for registers to write data. */
RTC_EnableConf(bool enable)87 void RTC_EnableConf(bool enable)
88 {
89     if (enable)
90     {
91         RTC->CRL |= RTC_CRL_CNF_MASK;
92     }
93     else
94     {
95         RTC->CRL &= ~RTC_CRL_CNF_MASK;
96     }
97 }
98 
99 /* Setup prescaler register, open configration module before put data into RTC register. */
RTC_PutPrescalerData(uint32_t div)100 void RTC_PutPrescalerData(uint32_t div)
101 {
102     RTC->CRL |= RTC_CRL_CNF_MASK;  /* Enable the configuration mode. */
103     RTC->PRLH = div >> 16u;        /* Setup the upper 16-bit value of prescaler. */
104     RTC->PRLL = div;               /* Setup the lower 16-bit value of prescaler. */
105     RTC->CRL &= ~RTC_CRL_CNF_MASK; /* Disable the configuration mode. */
106 }
107 
108 /* Setup counter register, open configration module before put data into RTC register. */
RTC_PutCounterData(uint32_t cnt)109 void RTC_PutCounterData(uint32_t cnt)
110 {
111     RTC->CRL |= RTC_CRL_CNF_MASK;  /* Enable the configuration mode. */
112     RTC->CNTH = cnt >> 16u;        /* Setup the upper 16-bit value of counter. */
113     RTC->CNTL = cnt;               /* Setup the lower 16-bit value of counter. */
114     RTC->CRL &= ~RTC_CRL_CNF_MASK; /* Disable the configuration mode. */
115 }
116 
117 /* Setup alarm register, open configration module before put data into RTC register. */
RTC_PutAlarmData(uint32_t alarm)118 void RTC_PutAlarmData(uint32_t alarm)
119 {
120     RTC->CRL |= RTC_CRL_CNF_MASK;  /* Enable the configuration mode. */
121     RTC->ALRH = alarm >> 16u;      /* Setup the upper 16-bit value of alarm counter. */
122     RTC->ALRL = alarm;             /* Setup the lower 16-bit value of alarm counter. */
123     RTC->CRL &= ~RTC_CRL_CNF_MASK; /* Disable the configuration mode. */
124 }
125 
126 /* Get the data from counter of I2C module. */
RTC_GetCounterData(void)127 uint32_t RTC_GetCounterData(void)
128 {
129     return ( (RTC->CNTH << 16u) | RTC->CNTL );
130 }
131 
132 /* Get alarm count value which is used to alarm interrupt. */
RTC_GetAlarmData(void)133 uint32_t RTC_GetAlarmData(void)
134 {
135     return ( (RTC->ALRH << 16u) | RTC->ALRL);
136 }
137 
138 /* Enable RTC interrupt of RTC module. */
RTC_EnableInterrupts(uint32_t interrupts,bool enable)139 void RTC_EnableInterrupts(uint32_t interrupts, bool enable)
140 {
141     if (enable)
142     {
143         RTC->CRH |= interrupts;
144     }
145     else
146     {
147         RTC->CRH &= ~interrupts;
148     }
149 }
150 
151 /* Get the interrupts status flags of the RTC module. */
RTC_GetInterruptStatus(void)152 uint32_t RTC_GetInterruptStatus(void)
153 {
154     return RTC->CRL;
155 }
156 
157 /* Clear the status of RTC interrupt. */
RTC_ClearInterruptStatus(uint32_t interrupts)158 void RTC_ClearInterruptStatus(uint32_t interrupts)
159 {
160     RTC->CRL &= ~interrupts;
161 }
162 
163 /* Get RTC interrupt enable status. */
RTC_GetEnabledInterrupts(void)164 uint32_t RTC_GetEnabledInterrupts(void)
165 {
166     return RTC->CRH;
167 }
168 
169 /* Judging whether the current year is a leap year, an ordinary leap year or a century leap year. */
RTC_JudgeLeapYear(uint16_t years)170 bool RTC_JudgeLeapYear(uint16_t years)
171 {
172     if (years % 4u == 0u)
173     {
174         if (years % 100u == 0u)
175         {
176             if (years % 400u == 0u)
177             {
178                 return true;  /* Century leap year. */
179             }
180             else
181             {
182                 return false;
183             }
184         }
185         else
186         {
187             return true; /* Ordinary leap year. */
188         }
189     }
190     else
191     {
192         return false;
193     }
194 }
195 
196 /* Month correction table, used for calculation of month. */
197 const uint8_t month_table[12u] = {31u, 28u, 31u, 30u, 31u, 30u, 31u, 31u, 30u, 31u, 30u, 31u};
198 
199 /* Setup initialization time. */
RTC_SetTimeBlocking(RTC_Init_Type * init,RTC_Time_Type * time)200 bool RTC_SetTimeBlocking(RTC_Init_Type * init, RTC_Time_Type * time)
201 {
202     RTC_PutPrescalerData(init->Div);  /* Setup prescaler. */
203     while ( (0u == (RTC_GetStatus() & RTC_STATUS_OPERATION) ) && (0u != (time->WaitTime--) ) )  /* Wait for write operation finish, only after the end of the previous write operation can new write be performed. */
204     {
205     }
206 
207     /* Calculate the total number of seconds of the current configuration time. */
208     uint32_t seccnt = 0u;
209     if ( (init->Years < init->LYears) || (init->Years > init->HYears) )   /* Exceeding the specified year. */
210     {
211         return false;
212     }
213     /* Calculate the number of seconds from the lowest years to the current setup years. */
214     for (uint16_t years = init->LYears; years < init->Years; years++)
215     {
216         if ( RTC_JudgeLeapYear(years) )
217         {
218             seccnt += 31622400u;  /* The number of seconds in leap year is 31622400. */
219         }
220         else
221         {
222             seccnt += 31536000u;  /* The number of seconds in normal year is 31622400. */
223         }
224     }
225 
226     /* Add up the seconds of the previous month. */
227     init->Months -= 1u;  /* The month count starts from 0 instead of 1, so current months - 1. */
228     for (uint16_t months = 0u; months < init->Months; months++)
229     {
230         seccnt += (uint32_t)month_table[months] * 86400u;  /* Calculate the number of seconds of months, the total number of seconds in a day is 86400. */
231         if ( ( RTC_JudgeLeapYear(init->Years) ) && (months == 1u) )  /* The time is in a leap year and february, add the number of seconds in one day. */
232         {
233             seccnt += 86400u;  /* The number of seconds in day is 86400. */
234         }
235     }
236     /* Add up the seconds of the previous date. */
237     seccnt += (uint32_t)(init->Days - 1u) * 86400u;  /* The day set for initialization is less than 24 hours, which needs to be subtracted by one day. */
238     seccnt += (uint32_t)(init->Hours) * 3600u;  /* There are 3600 seconds in a hour. */
239     seccnt += (uint32_t)(init->Mins) * 60u;   /* There are 60 seconds in a minute. */
240     seccnt += (init->Secs);
241 
242 
243     while ( (0u == (RTC_GetStatus() & RTC_STATUS_OPERATION)) && (0u != (time->WaitTime--) ) )  /* Wait for write operation finish, only after the end of the previous write operation can new write be performed. */
244     {
245     }
246 
247     /* Configrate counter value. */
248     RTC_PutCounterData(seccnt);  /* Put data into counter. */
249     while ( ( 0u == (RTC_GetStatus() & RTC_STATUS_OPERATION) ) && (0u != (time->WaitTime--) ) )  /* Wait for write operation finish. */
250     {
251     }
252     if (0u == time->WaitTime)   /* Timeout. */
253     {
254         return false;
255     }
256 
257     return true;
258 }
259 
260 /* Calculate and get current time. */
RTC_CalcTimeBlocking(RTC_Init_Type * init,RTC_Time_Type * time)261 void RTC_CalcTimeBlocking(RTC_Init_Type * init, RTC_Time_Type * time)
262 {
263     while ( 0u == (RTC_GetStatus() & RTC_STATUS_SYNC) && (0u != time->WaitTime) )  /* Wait for register synchronization, only register synchronization can read RTC register. */
264     {
265         time->WaitTime--;
266     }
267     uint32_t count = RTC_GetCounterData();  /* Get current seconds count. */
268 
269     /* Calculated in days. */
270     uint16_t years = init->LYears;
271     uint32_t days = count / 86400u;
272 
273     for (; days >= 365u; days -= 365u)
274     {
275         if ( RTC_JudgeLeapYear(years) )  /* Determine whether it is a leap year. */
276         {
277             if (days >= 366u)
278             {
279                 days -= 1u;
280             }
281             else
282             {
283                 break;
284             }
285         }
286         years++;
287     }
288     init->Years = years;  /* Get current years. */
289 
290     uint16_t months = 0u;
291     for (; days >= 28u; days -= 28u)
292     {
293         if ( ( true == RTC_JudgeLeapYear(init->Years) ) && (months == 1u) )  /* The time is February of leap year. */
294         {
295             if (days >= 29u)
296             {
297                 days -= 1u;
298             }
299             else
300             {
301                 break;
302             }
303         }
304         else
305         {
306             if (days >= month_table[months])  /* Reach the maximum number of days in the current month. */
307             {
308                 days = days - month_table[months] + 28u;
309             }
310             else
311             {
312                 break;
313             }
314         }
315         months++;
316     }
317     init->Months = months + 1u;  /* Get current months. */
318     init->Days   = days   + 1u;   /* Get current days. */
319     init->Hours  = ( count % 86400u) / 3600u;  /* Get current hours. */
320     init->Mins   = ((count % 86400u) % 3600u) / 60u;  /* Get current minutes. */
321     init->Secs   = ((count % 86400u) % 3600u) % 60u;  /* Get current seconds. */
322 }
323 
324 /* Setup the alarm response time. */
RTC_SetAlarmBlocking(RTC_Time_Type * time)325 bool RTC_SetAlarmBlocking(RTC_Time_Type * time)
326 {
327     RTC_EnableInterrupts(RTC_INT_ALARM, true);  /* Enable alarm interrupt. */
328     while ( 0u == (RTC_GetStatus() & RTC_STATUS_SYNC) && (0u != time->WaitTime) )  /* Wait for register synchronization, only register synchronization can read RTC register. */
329     {
330         time->WaitTime--;
331     }
332     uint32_t value = RTC_GetCounterData();  /* Get the current total number of seconds. */
333     RTC_PutAlarmData(value + time->AlarmTime);  /* Set alarm respond time. */
334     while ( 0u == (RTC_GetStatus() & RTC_STATUS_OPERATION) && (0u != time->WaitTime) )  /* Wait for write operation finish. */
335     {
336         time->WaitTime--;
337     }
338     if (0u == time->WaitTime)
339     {
340         return false;
341     }
342     return true;
343 }
344 
345 /* RTC interrupt request handler. */
RTC_TimeHandler(RTC_Init_Type * init,RTC_Time_Type * time,uint32_t interrupts)346 void RTC_TimeHandler(RTC_Init_Type * init, RTC_Time_Type * time, uint32_t interrupts)
347 {
348     /* Seconds interrupt. */
349     if ( ( 0u == (interrupts & RTC_INT_ALARM) ) && ( 1u == (interrupts & RTC_INT_SEC) ) )
350     {
351         RTC_CalcTimeBlocking(init, time);  /* Get current time. */
352         if (time->SecDoneCallback)
353         {
354             (*(time->SecDoneCallback))((void *)time);  /* Callback when seconds interrupt done. */
355         }
356     }
357 
358     /* Alarm interrupt. */
359     if (0u != (interrupts & RTC_INT_ALARM) ) /* When the alarm count value is the same as the current count value, the alarm clock interrupt is generated. */
360     {
361         RTC_CalcTimeBlocking(init, time);  /* Get current time. */
362         RTC_ClearInterruptStatus(RTC_INT_ALARM);  /* Clear alarm interrupt status flag. */
363         if (time->AlarmDoneCallback)
364         {
365             (*(time->AlarmDoneCallback))((void *)time);  /* Callback when alarm interrupt done. */
366         }
367     }
368     RTC_ClearInterruptStatus(RTC_INT_SEC | RTC_INT_OVERFLOW);  /* Clear seconds interrupt status flag and overflow status flag. */
369 }
370 
371 /* EOF. */
372 
373