1 /*!
2     \file    gd32f3x0_rtc.c
3     \brief   RTC driver
4 
5     \version 2017-06-06, V1.0.0, firmware for GD32F3x0
6     \version 2019-06-01, V2.0.0, firmware for GD32F3x0
7     \version 2020-09-30, V2.1.0, firmware for GD32F3x0
8 */
9 
10 /*
11     Copyright (c) 2020, GigaDevice Semiconductor Inc.
12 
13     Redistribution and use in source and binary forms, with or without modification,
14 are permitted provided that the following conditions are met:
15 
16     1. Redistributions of source code must retain the above copyright notice, this
17        list of conditions and the following disclaimer.
18     2. Redistributions in binary form must reproduce the above copyright notice,
19        this list of conditions and the following disclaimer in the documentation
20        and/or other materials provided with the distribution.
21     3. Neither the name of the copyright holder nor the names of its contributors
22        may be used to endorse or promote products derived from this software without
23        specific prior written permission.
24 
25     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
26 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
27 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
28 IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
29 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
30 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
31 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
32 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
34 OF SUCH DAMAGE.
35 */
36 
37 #include "gd32f3x0_rtc.h"
38 
39 /*!
40     \brief      reset most of the RTC registers
41     \param[in]  none
42     \param[out] none
43     \retval     ErrStatus: ERROR or SUCCESS
44 */
rtc_deinit(void)45 ErrStatus rtc_deinit(void)
46 {
47     ErrStatus error_status = ERROR;
48 
49     /* RTC_TAMP register is not under write protection */
50     RTC_TAMP = RTC_REGISTER_RESET;
51 
52     /* disable the write protection */
53     RTC_WPK = RTC_UNLOCK_KEY1;
54     RTC_WPK = RTC_UNLOCK_KEY2;
55 
56     /* reset RTC_CTL register, this can be done without the init mode */
57     RTC_CTL &= RTC_REGISTER_RESET;
58 
59     /* enter init mode */
60     error_status = rtc_init_mode_enter();
61 
62     if(ERROR != error_status){
63         /* before reset RTC_TIME and RTC_DATE, BPSHAD bit in RTC_CTL should be reset as the condition.
64            in order to read calendar from shadow register, not the real registers being reset */
65         RTC_TIME = RTC_REGISTER_RESET;
66         RTC_DATE = RTC_DATE_RESET;
67 
68         RTC_PSC = RTC_PSC_RESET;
69 
70         /* reset RTC_STAT register, also exit init mode.
71            at the same time, RTC_STAT_SOPF bit is reset, as the condition to reset RTC_SHIFTCTL register later */
72         RTC_STAT = RTC_STAT_RESET;
73 
74         /* to write RTC_ALRM0SS register, ALRM0EN bit in RTC_CTL register should be reset as the condition */
75         RTC_ALRM0TD = RTC_REGISTER_RESET;
76         RTC_ALRM0SS = RTC_REGISTER_RESET;
77 
78         /* reset RTC_SHIFTCTL and RTC_HRFC register, this can be done without the init mode */
79         RTC_SHIFTCTL = RTC_REGISTER_RESET;
80         RTC_HRFC = RTC_REGISTER_RESET;
81 
82         error_status = rtc_register_sync_wait();
83     }
84 
85     /* enable the write protection */
86     RTC_WPK = RTC_LOCK_KEY;
87 
88     return error_status;
89 }
90 
91 /*!
92     \brief      initialize RTC registers
93     \param[in]  rtc_initpara_struct: pointer to a rtc_parameter_struct structure which contains
94                 parameters for initialization of the rtc peripheral
95                 members of the structure and the member values are shown as below:
96                   rtc_year: 0x0 - 0x99(BCD format)
97                   rtc_month: RTC_JAN, RTC_FEB, RTC_MAR, RTC_APR, RTC_MAY, RTC_JUN,
98                              RTC_JUL, RTC_AUG, RTC_SEP, RTC_OCT, RTC_NOV, RTC_DEC
99                   rtc_date: 0x1 - 0x31(BCD format)
100                   rtc_day_of_week: RTC_MONDAY, RTC_TUESDAY, RTC_WEDSDAY, RTC_THURSDAY
101                                    RTC_FRIDAY, RTC_SATURDAY, RTC_SUNDAY
102                   rtc_hour: 0x0 - 0x12(BCD format) or 0x0 - 0x23(BCD format) depending on the rtc_display_format chose
103                   rtc_minute: 0x0 - 0x59(BCD format)
104                   rtc_second: 0x0 - 0x59(BCD format)
105                   rtc_factor_asyn: 0x0 - 0x7F
106                   rtc_factor_syn: 0x0 - 0x7FFF
107                   rtc_am_pm: RTC_AM, RTC_PM
108                   rtc_display_format: RTC_24HOUR, RTC_12HOUR
109     \param[out] none
110     \retval     ErrStatus: ERROR or SUCCESS
111 */
rtc_init(rtc_parameter_struct * rtc_initpara_struct)112 ErrStatus rtc_init(rtc_parameter_struct* rtc_initpara_struct)
113 {
114     ErrStatus error_status = ERROR;
115     uint32_t reg_time = 0x00U, reg_date = 0x00U;
116 
117     reg_date = (DATE_YR(rtc_initpara_struct->rtc_year) | \
118                 DATE_DOW(rtc_initpara_struct->rtc_day_of_week) | \
119                 DATE_MON(rtc_initpara_struct->rtc_month) | \
120                 DATE_DAY(rtc_initpara_struct->rtc_date));
121 
122     reg_time = (rtc_initpara_struct->rtc_am_pm| \
123                 TIME_HR(rtc_initpara_struct->rtc_hour) | \
124                 TIME_MN(rtc_initpara_struct->rtc_minute) | \
125                 TIME_SC(rtc_initpara_struct->rtc_second));
126 
127     /* 1st: disable the write protection */
128     RTC_WPK = RTC_UNLOCK_KEY1;
129     RTC_WPK = RTC_UNLOCK_KEY2;
130 
131     /* 2nd: enter init mode */
132     error_status = rtc_init_mode_enter();
133 
134     if(ERROR != error_status){
135         RTC_PSC = (uint32_t)(PSC_FACTOR_A(rtc_initpara_struct->rtc_factor_asyn)| \
136                                   PSC_FACTOR_S(rtc_initpara_struct->rtc_factor_syn));
137 
138         RTC_TIME = (uint32_t)reg_time;
139         RTC_DATE = (uint32_t)reg_date;
140 
141         RTC_CTL &= (uint32_t)(~RTC_CTL_CS);
142         RTC_CTL |=  rtc_initpara_struct->rtc_display_format;
143 
144         /* 3rd: exit init mode */
145         rtc_init_mode_exit();
146 
147         /* 4th: wait the RSYNF flag to set */
148         error_status = rtc_register_sync_wait();
149     }
150 
151     /* 5th: enable the write protection */
152     RTC_WPK = RTC_LOCK_KEY;
153 
154     return error_status;
155 }
156 
157 /*!
158     \brief      enter RTC init mode
159     \param[in]  none
160     \param[out] none
161     \retval     ErrStatus: ERROR or SUCCESS
162 */
rtc_init_mode_enter(void)163 ErrStatus rtc_init_mode_enter(void)
164 {
165     uint32_t time_index = RTC_INITM_TIMEOUT;
166     uint32_t flag_status = RESET;
167     ErrStatus error_status = ERROR;
168 
169     /* check whether it has been in init mode */
170     if(RESET == (RTC_STAT & RTC_STAT_INITF)){
171         RTC_STAT |= RTC_STAT_INITM;
172 
173         /* wait until the INITF flag to be set */
174         do{
175            flag_status = RTC_STAT & RTC_STAT_INITF;
176         }while((--time_index > 0x00U) && (RESET == flag_status));
177 
178         if(RESET != flag_status){
179             error_status = SUCCESS;
180         }
181     }else{
182         error_status = SUCCESS;
183     }
184     return error_status;
185 }
186 
187 /*!
188     \brief      exit RTC init mode
189     \param[in]  none
190     \param[out] none
191     \retval     none
192 */
rtc_init_mode_exit(void)193 void rtc_init_mode_exit(void)
194 {
195     RTC_STAT &= (uint32_t)(~RTC_STAT_INITM);
196 }
197 
198 /*!
199     \brief      wait until RTC_TIME and RTC_DATE registers are synchronized with APB clock, and the shadow
200                 registers are updated
201     \param[in]  none
202     \param[out] none
203     \retval     ErrStatus: ERROR or SUCCESS
204 */
rtc_register_sync_wait(void)205 ErrStatus rtc_register_sync_wait(void)
206 {
207     volatile uint32_t time_index = RTC_RSYNF_TIMEOUT;
208     uint32_t flag_status = RESET;
209     ErrStatus error_status = ERROR;
210 
211     if(RESET == (RTC_CTL & RTC_CTL_BPSHAD)){
212         /* disable the write protection */
213         RTC_WPK = RTC_UNLOCK_KEY1;
214         RTC_WPK = RTC_UNLOCK_KEY2;
215 
216         /* firstly clear RSYNF flag */
217         RTC_STAT &= (uint32_t)(~RTC_STAT_RSYNF);
218 
219         /* wait until RSYNF flag to be set */
220         do{
221             flag_status = RTC_STAT & RTC_STAT_RSYNF;
222         }while((--time_index > 0x00U) && (RESET == flag_status));
223 
224         if(RESET != flag_status){
225             error_status = SUCCESS;
226         }
227 
228         /* enable the write protection */
229         RTC_WPK = RTC_LOCK_KEY;
230     }else{
231         error_status = SUCCESS;
232     }
233 
234     return error_status;
235 }
236 
237 /*!
238     \brief      get current time and date
239     \param[in]  none
240     \param[out] rtc_initpara_struct: pointer to a rtc_parameter_struct structure which contains
241                 parameters for initialization of the rtc peripheral
242                 members of the structure and the member values are shown as below:
243                   rtc_year: 0x0 - 0x99(BCD format)
244                   rtc_month: RTC_JAN, RTC_FEB, RTC_MAR, RTC_APR, RTC_MAY, RTC_JUN,
245                              RTC_JUL, RTC_AUG, RTC_SEP, RTC_OCT, RTC_NOV, RTC_DEC
246                   rtc_date: 0x1 - 0x31(BCD format)
247                   rtc_day_of_week: RTC_MONDAY, RTC_TUESDAY, RTC_WEDSDAY, RTC_THURSDAY
248                                    RTC_FRIDAY, RTC_SATURDAY, RTC_SUNDAY
249                   rtc_hour: 0x0 - 0x12(BCD format) or 0x0 - 0x23(BCD format) depending on the rtc_display_format chose
250                   rtc_minute: 0x0 - 0x59(BCD format)
251                   rtc_second: 0x0 - 0x59(BCD format)
252                   rtc_factor_asyn: 0x0 - 0x7F
253                   rtc_factor_syn: 0x0 - 0x7FFF
254                   rtc_am_pm: RTC_AM, RTC_PM
255                   rtc_display_format: RTC_24HOUR, RTC_12HOUR
256     \retval     none
257 */
rtc_current_time_get(rtc_parameter_struct * rtc_initpara_struct)258 void rtc_current_time_get(rtc_parameter_struct* rtc_initpara_struct)
259 {
260     uint32_t temp_tr = 0x00U, temp_dr = 0x00U, temp_pscr = 0x00U, temp_ctlr = 0x00U;
261 
262     temp_tr = (uint32_t)RTC_TIME;
263     temp_dr = (uint32_t)RTC_DATE;
264     temp_pscr = (uint32_t)RTC_PSC;
265     temp_ctlr = (uint32_t)RTC_CTL;
266 
267     /* get current time and construct rtc_parameter_struct structure */
268     rtc_initpara_struct->rtc_year = (uint8_t)GET_DATE_YR(temp_dr);
269     rtc_initpara_struct->rtc_month = (uint8_t)GET_DATE_MON(temp_dr);
270     rtc_initpara_struct->rtc_date = (uint8_t)GET_DATE_DAY(temp_dr);
271     rtc_initpara_struct->rtc_day_of_week = (uint8_t)GET_DATE_DOW(temp_dr);
272     rtc_initpara_struct->rtc_hour = (uint8_t)GET_TIME_HR(temp_tr);
273     rtc_initpara_struct->rtc_minute = (uint8_t)GET_TIME_MN(temp_tr);
274     rtc_initpara_struct->rtc_second = (uint8_t)GET_TIME_SC(temp_tr);
275     rtc_initpara_struct->rtc_factor_asyn = (uint16_t)GET_PSC_FACTOR_A(temp_pscr);
276     rtc_initpara_struct->rtc_factor_syn = (uint16_t)GET_PSC_FACTOR_S(temp_pscr);
277     rtc_initpara_struct->rtc_am_pm = (uint32_t)(temp_pscr & RTC_TIME_PM);
278     rtc_initpara_struct->rtc_display_format = (uint32_t)(temp_ctlr & RTC_CTL_CS);
279 }
280 
281 /*!
282     \brief      get current subsecond value
283     \param[in]  none
284     \param[out] none
285     \retval     current subsecond value
286 */
rtc_subsecond_get(void)287 uint32_t rtc_subsecond_get(void)
288 {
289     uint32_t reg = 0x00U;
290     /* if BPSHAD bit is reset, reading RTC_SS will lock RTC_TIME and RTC_DATE automatically */
291     reg = (uint32_t)RTC_SS;
292     /* read RTC_DATE to unlock the 3 shadow registers */
293     (void) (RTC_DATE);
294 
295     return reg;
296 }
297 
298 /*!
299     \brief      configure RTC alarm
300     \param[in]  rtc_alarm_time: pointer to a rtc_alarm_struct structure which contains
301                 parameters for RTC alarm configuration
302                 members of the structure and the member values are shown as below:
303                   rtc_alarm_mask: RTC_ALARM_NONE_MASK, RTC_ALARM_DATE_MASK, RTC_ALARM_HOUR_MASK
304                                   RTC_ALARM_MINUTE_MASK, RTC_ALARM_SECOND_MASK, RTC_ALARM_ALL_MASK
305                   rtc_weekday_or_date: RTC_ALARM_DATE_SELECTED, RTC_ALARM_WEEKDAY_SELECTED
306                   rtc_alarm_day: 1) 0x1 - 0x31(BCD format) if RTC_ALARM_DATE_SELECTED is set
307                                  2) RTC_MONDAY, RTC_TUESDAY, RTC_WEDSDAY, RTC_THURSDAY, RTC_FRIDAY,
308                                     RTC_SATURDAY, RTC_SUNDAY if RTC_ALARM_WEEKDAY_SELECTED is set
309                   rtc_alarm_hour: 0x0 - 0x12(BCD format) or 0x0 - 0x23(BCD format) depending on the rtc_display_format
310                   rtc_alarm_minute: 0x0 - 0x59(BCD format)
311                   rtc_alarm_second: 0x0 - 0x59(BCD format)
312                   rtc_am_pm: RTC_AM, RTC_PM
313     \param[out] none
314     \retval     none
315 */
rtc_alarm_config(rtc_alarm_struct * rtc_alarm_time)316 void rtc_alarm_config(rtc_alarm_struct* rtc_alarm_time)
317 {
318     uint32_t reg_alrm0td = 0x00U;
319 
320     reg_alrm0td = (rtc_alarm_time->rtc_alarm_mask | \
321                  rtc_alarm_time->rtc_weekday_or_date | \
322                  rtc_alarm_time->rtc_am_pm | \
323                  ALRM0TD_DAY(rtc_alarm_time->rtc_alarm_day) | \
324                  ALRM0TD_HR(rtc_alarm_time->rtc_alarm_hour) | \
325                  ALRM0TD_MN(rtc_alarm_time->rtc_alarm_minute) | \
326                  ALRM0TD_SC(rtc_alarm_time->rtc_alarm_second));
327 
328     /* disable the write protection */
329     RTC_WPK = RTC_UNLOCK_KEY1;
330     RTC_WPK = RTC_UNLOCK_KEY2;
331 
332     RTC_ALRM0TD = (uint32_t)reg_alrm0td;
333 
334     /* enable the write protection */
335     RTC_WPK = RTC_LOCK_KEY;
336 }
337 
338 /*!
339     \brief      configure subsecond of RTC alarm
340     \param[in]  mask_subsecond: alarm subsecond mask
341                 only one parameter can be selected which is shown as below:
342       \arg        RTC_MASKSSC_0_14: mask alarm subsecond configuration
343       \arg        RTC_MASKSSC_1_14: mask RTC_ALRM0SS_SSC[14:1], and RTC_ALRM0SS_SSC[0] is to be compared
344       \arg        RTC_MASKSSC_2_14: mask RTC_ALRM0SS_SSC[14:2], and RTC_ALRM0SS_SSC[1:0] is to be compared
345       \arg        RTC_MASKSSC_3_14: mask RTC_ALRM0SS_SSC[14:3], and RTC_ALRM0SS_SSC[2:0] is to be compared
346       \arg        RTC_MASKSSC_4_14: mask RTC_ALRM0SS_SSC[14:4], and RTC_ALRM0SS_SSC[3:0] is to be compared
347       \arg        RTC_MASKSSC_5_14: mask RTC_ALRM0SS_SSC[14:5], and RTC_ALRM0SS_SSC[4:0] is to be compared
348       \arg        RTC_MASKSSC_6_14: mask RTC_ALRM0SS_SSC[14:6], and RTC_ALRM0SS_SSC[5:0] is to be compared
349       \arg        RTC_MASKSSC_7_14: mask RTC_ALRM0SS_SSC[14:7], and RTC_ALRM0SS_SSC[6:0] is to be compared
350       \arg        RTC_MASKSSC_8_14: mask RTC_ALRM0SS_SSC[14:8], and RTC_ALRM0SS_SSC[7:0] is to be compared
351       \arg        RTC_MASKSSC_9_14: mask RTC_ALRM0SS_SSC[14:9], and RTC_ALRM0SS_SSC[8:0] is to be compared
352       \arg        RTC_MASKSSC_10_14: mask RTC_ALRM0SS_SSC[14:10], and RTC_ALRM0SS_SSC[9:0] is to be compared
353       \arg        RTC_MASKSSC_11_14: mask RTC_ALRM0SS_SSC[14:11], and RTC_ALRM0SS_SSC[10:0] is to be compared
354       \arg        RTC_MASKSSC_12_14: mask RTC_ALRM0SS_SSC[14:12], and RTC_ALRM0SS_SSC[11:0] is to be compared
355       \arg        RTC_MASKSSC_13_14: mask RTC_ALRM0SS_SSC[14:13], and RTC_ALRM0SS_SSC[12:0] is to be compared
356       \arg        RTC_MASKSSC_14: mask RTC_ALRM0SS_SSC[14], and RTC_ALRM0SS_SSC[13:0] is to be compared
357       \arg        RTC_MASKSSC_NONE: mask none, and RTC_ALRM0SS_SSC[14:0] is to be compared
358     \param[in]  subsecond: alarm subsecond value(0x000 - 0x7FFF)
359     \param[out] none
360     \retval     none
361 */
rtc_alarm_subsecond_config(uint32_t mask_subsecond,uint32_t subsecond)362 void rtc_alarm_subsecond_config(uint32_t mask_subsecond, uint32_t subsecond)
363 {
364     /* disable the write protection */
365     RTC_WPK = RTC_UNLOCK_KEY1;
366     RTC_WPK = RTC_UNLOCK_KEY2;
367 
368     RTC_ALRM0SS = mask_subsecond | subsecond;
369 
370     /* enable the write protection */
371     RTC_WPK = RTC_LOCK_KEY;
372 }
373 
374 /*!
375     \brief      get RTC alarm
376     \param[in]  none
377     \param[out] rtc_alarm_time: pointer to a rtc_alarm_struct structure which contains
378                 parameters for RTC alarm configuration
379                 members of the structure and the member values are shown as below:
380                   rtc_alarm_mask: RTC_ALARM_NONE_MASK, RTC_ALARM_DATE_MASK, RTC_ALARM_HOUR_MASK
381                                   RTC_ALARM_MINUTE_MASK, RTC_ALARM_SECOND_MASK, RTC_ALARM_ALL_MASK
382                   rtc_weekday_or_date: RTC_ALARM_DATE_SELECTED, RTC_ALARM_WEEKDAY_SELECTED
383                   rtc_alarm_day: 1) 0x1 - 0x31(BCD format) if RTC_ALARM_DATE_SELECTED is set
384                                  2) RTC_MONDAY, RTC_TUESDAY, RTC_WEDSDAY, RTC_THURSDAY, RTC_FRIDAY,
385                                     RTC_SATURDAY, RTC_SUNDAY if RTC_ALARM_WEEKDAY_SELECTED is set
386                   rtc_alarm_hour: 0x0 - 0x12(BCD format) or 0x0 - 0x23(BCD format) depending on the rtc_display_format
387                   rtc_alarm_minute: 0x0 - 0x59(BCD format)
388                   rtc_alarm_second: 0x0 - 0x59(BCD format)
389                   rtc_am_pm: RTC_AM, RTC_PM
390     \retval     none
391 */
rtc_alarm_get(rtc_alarm_struct * rtc_alarm_time)392 void rtc_alarm_get(rtc_alarm_struct* rtc_alarm_time)
393 {
394     uint32_t reg_alrm0td = 0x00U;
395 
396     /* get the value of RTC_ALRM0TD register */
397     reg_alrm0td = RTC_ALRM0TD;
398 
399     /* get alarm parameters and construct the rtc_alarm_struct structure */
400     rtc_alarm_time->rtc_alarm_mask = reg_alrm0td & RTC_ALARM_ALL_MASK;
401     rtc_alarm_time->rtc_am_pm = (uint32_t)(reg_alrm0td & RTC_ALRM0TD_PM);
402     rtc_alarm_time->rtc_weekday_or_date = (uint32_t)(reg_alrm0td & RTC_ALRM0TD_DOWS);
403     rtc_alarm_time->rtc_alarm_day = (uint8_t)GET_ALRM0TD_DAY(reg_alrm0td);
404     rtc_alarm_time->rtc_alarm_hour = (uint8_t)GET_ALRM0TD_HR(reg_alrm0td);
405     rtc_alarm_time->rtc_alarm_minute = (uint8_t)GET_ALRM0TD_MN(reg_alrm0td);
406     rtc_alarm_time->rtc_alarm_second = (uint8_t)GET_ALRM0TD_SC(reg_alrm0td);
407 }
408 
409 /*!
410     \brief      get RTC alarm subsecond
411     \param[in]  none
412     \param[out] none
413     \retval     RTC alarm subsecond value
414 */
rtc_alarm_subsecond_get(void)415 uint32_t rtc_alarm_subsecond_get(void)
416 {
417     return ((uint32_t)(RTC_ALRM0SS & RTC_ALRM0SS_SSC));
418 }
419 
420 /*!
421     \brief      enable RTC alarm
422     \param[in]  none
423     \param[out] none
424     \retval     none
425 */
rtc_alarm_enable(void)426 void rtc_alarm_enable(void)
427 {
428     /* disable the write protection */
429     RTC_WPK = RTC_UNLOCK_KEY1;
430     RTC_WPK = RTC_UNLOCK_KEY2;
431 
432     RTC_CTL |= RTC_CTL_ALRM0EN;
433 
434     /* enable the write protection */
435     RTC_WPK = RTC_LOCK_KEY;
436 }
437 
438 /*!
439     \brief      disable RTC alarm
440     \param[in]  none
441     \param[out] none
442     \retval     ErrStatus: ERROR or SUCCESS
443 */
rtc_alarm_disable(void)444 ErrStatus rtc_alarm_disable(void)
445 {
446     volatile uint32_t time_index = RTC_ALRM0WF_TIMEOUT;
447     ErrStatus error_status = ERROR;
448     uint32_t flag_status = RESET;
449 
450     /* disable the write protection */
451     RTC_WPK = RTC_UNLOCK_KEY1;
452     RTC_WPK = RTC_UNLOCK_KEY2;
453 
454     /* clear the state of alarm */
455     RTC_CTL &= (uint32_t)(~RTC_CTL_ALRM0EN);
456 
457     /* wait until ALRM0WF flag to be set after the alarm is disabled */
458     do{
459         flag_status = RTC_STAT & RTC_STAT_ALRM0WF;
460     }while((--time_index > 0x00U) && (RESET == flag_status));
461 
462     if(RESET != flag_status){
463         error_status = SUCCESS;
464     }
465 
466     /* enable the write protection */
467     RTC_WPK = RTC_LOCK_KEY;
468 
469     return error_status;
470 }
471 
472 /*!
473     \brief      enable RTC time-stamp
474     \param[in]  edge: specify which edge to detect of time-stamp
475                 only one parameter can be selected which is shown as below:
476       \arg        RTC_TIMESTAMP_RISING_EDGE: rising edge is valid event edge for timestamp event
477       \arg        RTC_TIMESTAMP_FALLING_EDGE: falling edge is valid event edge for timestamp event
478     \param[out] none
479     \retval     none
480 */
rtc_timestamp_enable(uint32_t edge)481 void rtc_timestamp_enable(uint32_t edge)
482 {
483     uint32_t reg_ctl = 0x00U;
484 
485     /* clear the bits to be configured in RTC_CTL */
486     reg_ctl = (uint32_t)(RTC_CTL & (uint32_t)(~(RTC_CTL_TSEG | RTC_CTL_TSEN)));
487 
488     /* new configuration */
489     reg_ctl |= (uint32_t)(edge | RTC_CTL_TSEN);
490 
491     /* disable the write protection */
492     RTC_WPK = RTC_UNLOCK_KEY1;
493     RTC_WPK = RTC_UNLOCK_KEY2;
494 
495     RTC_CTL = (uint32_t)reg_ctl;
496 
497     /* enable the write protection */
498     RTC_WPK = RTC_LOCK_KEY;
499 }
500 
501 /*!
502     \brief      disable RTC time-stamp
503     \param[in]  none
504     \param[out] none
505     \retval     none
506 */
rtc_timestamp_disable(void)507 void rtc_timestamp_disable(void)
508 {
509     /* disable the write protection */
510     RTC_WPK = RTC_UNLOCK_KEY1;
511     RTC_WPK = RTC_UNLOCK_KEY2;
512 
513     /* clear the TSEN bit */
514     RTC_CTL &= (uint32_t)(~ RTC_CTL_TSEN);
515 
516     /* enable the write protection */
517     RTC_WPK = RTC_LOCK_KEY;
518 }
519 
520 /*!
521     \brief      get RTC timestamp time and date
522     \param[in]  none
523     \param[out] rtc_timestamp: pointer to a rtc_timestamp_struct structure which contains
524                 parameters for RTC time-stamp configuration
525                 members of the structure and the member values are shown as below:
526                   rtc_timestamp_month: RTC_JAN, RTC_FEB, RTC_MAR, RTC_APR, RTC_MAY, RTC_JUN,
527                                        RTC_JUL, RTC_AUG, RTC_SEP, RTC_OCT, RTC_NOV, RTC_DEC
528                   rtc_timestamp_date: 0x1 - 0x31(BCD format)
529                   rtc_timestamp_day: RTC_MONDAY, RTC_TUESDAY, RTC_WEDSDAY, RTC_THURSDAY, RTC_FRIDAY,
530                                      RTC_SATURDAY, RTC_SUNDAY if RTC_ALARM_WEEKDAY_SELECTED is set
531                   rtc_timestamp_hour: 0x0 - 0x12(BCD format) or 0x0 - 0x23(BCD format) depending on the rtc_display_format
532                   rtc_timestamp_minute: 0x0 - 0x59(BCD format)
533                   rtc_timestamp_second: 0x0 - 0x59(BCD format)
534                   rtc_am_pm: RTC_AM, RTC_PM
535     \retval     none
536 */
rtc_timestamp_get(rtc_timestamp_struct * rtc_timestamp)537 void rtc_timestamp_get(rtc_timestamp_struct* rtc_timestamp)
538 {
539     uint32_t temp_tts = 0x00U, temp_dts = 0x00U;
540 
541     /* get the value of time_stamp registers */
542     temp_tts = (uint32_t)RTC_TTS;
543     temp_dts = (uint32_t)RTC_DTS;
544 
545     /* get timestamp time and construct the rtc_timestamp_struct structure */
546     rtc_timestamp->rtc_am_pm = (uint32_t)(temp_tts & RTC_TTS_PM);
547     rtc_timestamp->rtc_timestamp_month = (uint8_t)GET_DTS_MON(temp_dts);
548     rtc_timestamp->rtc_timestamp_date = (uint8_t)GET_DTS_DAY(temp_dts);
549     rtc_timestamp->rtc_timestamp_day = (uint8_t)GET_DTS_DOW(temp_dts);
550     rtc_timestamp->rtc_timestamp_hour = (uint8_t)GET_TTS_HR(temp_tts);
551     rtc_timestamp->rtc_timestamp_minute = (uint8_t)GET_TTS_MN(temp_tts);
552     rtc_timestamp->rtc_timestamp_second = (uint8_t)GET_TTS_SC(temp_tts);
553 }
554 
555 /*!
556     \brief      get RTC time-stamp subsecond
557     \param[in]  none
558     \param[out] none
559     \retval     RTC time-stamp subsecond value
560 */
rtc_timestamp_subsecond_get(void)561 uint32_t rtc_timestamp_subsecond_get(void)
562 {
563     return ((uint32_t)RTC_SSTS);
564 }
565 
566 /*!
567     \brief      enable RTC tamper
568     \param[in]  rtc_tamper: pointer to a rtc_tamper_struct structure which contains
569                 parameters for RTC tamper configuration
570                 members of the structure and the member values are shown as below:
571                   rtc_tamper_source: RTC_TAMPER0, RTC_TAMPER1
572                   rtc_tamper_trigger: RTC_TAMPER_TRIGGER_EDGE_RISING, RTC_TAMPER_TRIGGER_EDGE_FALLING
573                                       RTC_TAMPER_TRIGGER_LEVEL_LOW, RTC_TAMPER_TRIGGER_LEVEL_HIGH
574                   rtc_tamper_filter: RTC_FLT_EDGE, RTC_FLT_2S, RTC_FLT_4S, RTC_FLT_8S
575                   rtc_tamper_sample_frequency: RTC_FREQ_DIV32768, RTC_FREQ_DIV16384, RTC_FREQ_DIV8192,
576                                                RTC_FREQ_DIV4096, RTC_FREQ_DIV2048, RTC_FREQ_DIV1024,
577                                                RTC_FREQ_DIV512, RTC_FREQ_DIV256
578                   rtc_tamper_precharge_enable: DISABLE, ENABLE
579                   rtc_tamper_precharge_time: RTC_PRCH_1C, RTC_PRCH_2C, RTC_PRCH_4C, RTC_PRCH_8C
580                   rtc_tamper_with_timestamp: DISABLE, ENABLE
581     \param[out] none
582     \retval     none
583 */
rtc_tamper_enable(rtc_tamper_struct * rtc_tamper)584 void rtc_tamper_enable(rtc_tamper_struct* rtc_tamper)
585 {
586     /* disable tamper */
587     RTC_TAMP &= (uint32_t)~(rtc_tamper->rtc_tamper_source);
588 
589     /* tamper filter must be used when the tamper source is voltage level detection */
590     RTC_TAMP &= (uint32_t)~RTC_TAMP_FLT;
591 
592     /* the tamper source is voltage level detection */
593     if(rtc_tamper->rtc_tamper_filter != RTC_FLT_EDGE ){
594         RTC_TAMP &= (uint32_t)~(RTC_TAMP_DISPU | RTC_TAMP_PRCH | RTC_TAMP_FREQ | RTC_TAMP_FLT);
595 
596         /* check if the tamper pin need precharge, if need, then configure the precharge time */
597         if(DISABLE == rtc_tamper->rtc_tamper_precharge_enable){
598             RTC_TAMP |=  (uint32_t)RTC_TAMP_DISPU;
599         }else{
600             RTC_TAMP |= (uint32_t)(rtc_tamper->rtc_tamper_precharge_time);
601         }
602 
603         RTC_TAMP |= (uint32_t)(rtc_tamper->rtc_tamper_sample_frequency);
604         RTC_TAMP |= (uint32_t)(rtc_tamper->rtc_tamper_filter);
605     }
606 
607     RTC_TAMP &= (uint32_t)~RTC_TAMP_TPTS;
608 
609     if(DISABLE != rtc_tamper->rtc_tamper_with_timestamp){
610         /* the tamper event also cause a time-stamp event */
611         RTC_TAMP |= (uint32_t)RTC_TAMP_TPTS;
612     }
613 
614     /* configure the tamper trigger */
615     RTC_TAMP &= ((uint32_t)~((rtc_tamper->rtc_tamper_source) << RTC_TAMPER_TRIGGER_POS));
616     if(RTC_TAMPER_TRIGGER_EDGE_RISING != rtc_tamper->rtc_tamper_trigger){
617         RTC_TAMP |= (uint32_t)((rtc_tamper->rtc_tamper_source)<< RTC_TAMPER_TRIGGER_POS);
618     }
619     /* enable tamper */
620     RTC_TAMP |=  (uint32_t)(rtc_tamper->rtc_tamper_source);
621 }
622 
623 /*!
624     \brief      disable RTC tamper
625     \param[in]  source: specify which tamper source to be disabled
626                 only one parameter can be selected which is shown as below:
627       \arg        RTC_TAMPER0
628       \arg        RTC_TAMPER1
629     \param[out] none
630     \retval     none
631 */
rtc_tamper_disable(uint32_t source)632 void rtc_tamper_disable(uint32_t source)
633 {
634     /* disable tamper */
635     RTC_TAMP &= (uint32_t)~source;
636 
637 }
638 
639 /*!
640     \brief      enable specified RTC interrupt
641     \param[in]  interrupt: specify which interrupt source to be enabled
642                 only one parameter can be selected which is shown as below:
643       \arg        RTC_INT_TIMESTAMP: timestamp interrupt
644       \arg        RTC_INT_ALARM: alarm interrupt
645       \arg        RTC_INT_TAMP: tamp interrupt
646     \param[out] none
647     \retval     none
648 */
rtc_interrupt_enable(uint32_t interrupt)649 void rtc_interrupt_enable(uint32_t interrupt)
650 {
651     /* disable the write protection */
652     RTC_WPK = RTC_UNLOCK_KEY1;
653     RTC_WPK = RTC_UNLOCK_KEY2;
654 
655     /* enable the interrupts in RTC_CTL register */
656     RTC_CTL |= (uint32_t)(interrupt & (uint32_t)~RTC_TAMP_TPIE);
657     /* enable the interrupts in RTC_TAMP register */
658     RTC_TAMP |= (uint32_t)(interrupt & RTC_TAMP_TPIE);
659 
660     /* enable the write protection */
661     RTC_WPK = RTC_LOCK_KEY;
662 }
663 
664 /*!
665     \brief      disble specified RTC interrupt
666     \param[in]  interrupt: specify which interrupt source to be disabled
667                 only one parameter can be selected which is shown as below:
668       \arg        RTC_INT_TIMESTAMP: timestamp interrupt
669       \arg        RTC_INT_ALARM: alarm interrupt
670       \arg        RTC_INT_TAMP: tamp interrupt
671     \param[out] none
672     \retval     none
673 */
rtc_interrupt_disable(uint32_t interrupt)674 void rtc_interrupt_disable(uint32_t interrupt)
675 {
676     /* disable the write protection */
677     RTC_WPK = RTC_UNLOCK_KEY1;
678     RTC_WPK = RTC_UNLOCK_KEY2;
679 
680     /* disable the interrupts in RTC_CTL register */
681     RTC_CTL &= (uint32_t)~(interrupt & (uint32_t)~RTC_TAMP_TPIE);
682     /* disable the interrupts in RTC_TAMP register */
683     RTC_TAMP &= (uint32_t)~(interrupt & RTC_TAMP_TPIE);
684 
685     /* enable the write protection */
686     RTC_WPK = RTC_LOCK_KEY;
687 }
688 
689 /*!
690     \brief      check specified flag
691     \param[in]  flag: specify which flag to check
692                 only one parameter can be selected which is shown as below:
693       \arg        RTC_FLAG_RECALIBRATION: recalibration pending flag
694       \arg        RTC_FLAG_TAMP1: tamper 1 event flag
695       \arg        RTC_FLAG_TAMP0: tamper 0 event flag
696       \arg        RTC_FLAG_TIMESTAMP_OVERFLOW: time-stamp overflow event flag
697       \arg        RTC_FLAG_TIMESTAMP: time-stamp event flag
698       \arg        RTC_FLAG_ALARM0: alarm event flag
699       \arg        RTC_FLAG_INIT: init mode event flag
700       \arg        RTC_FLAG_RSYN: time and date registers synchronized event flag
701       \arg        RTC_FLAG_YCM: year parameter configured event flag
702       \arg        RTC_FLAG_SHIFT: shift operation pending flag
703       \arg        RTC_FLAG_ALARM0_WRITTEN: alarm writen available flag
704     \param[out] none
705     \retval     FlagStatus: SET or RESET
706 */
rtc_flag_get(uint32_t flag)707 FlagStatus rtc_flag_get(uint32_t flag)
708 {
709     FlagStatus flag_state = RESET;
710 
711     if(RESET != (RTC_STAT & flag)){
712         flag_state = SET;
713     }
714     return flag_state;
715 }
716 
717 /*!
718     \brief      clear specified flag
719     \param[in]  flag: specify which flag to clear
720       \arg        RTC_FLAG_TAMP1: tamper 1 event flag
721       \arg        RTC_FLAG_TAMP0: tamper 0 event flag
722       \arg        RTC_FLAG_TIMESTAMP_OVERFLOW: time-stamp overflow event flag
723       \arg        RTC_FLAG_TIMESTAMP: time-stamp event flag
724       \arg        RTC_FLAG_ALARM0: alarm event flag
725       \arg        RTC_FLAG_RSYN: time and date registers synchronized event flag
726     \param[out] none
727     \retval     none
728 */
rtc_flag_clear(uint32_t flag)729 void rtc_flag_clear(uint32_t flag)
730 {
731     RTC_STAT &= (uint32_t)(~flag);
732 }
733 
734 /*!
735     \brief      configure rtc alternate output source
736     \param[in]  source: specify signal to output
737                 only one parameter can be selected which is shown as below:
738       \arg        RTC_CALIBRATION_512HZ: when the LSE freqency is 32768Hz and the RTC_PSC
739                                          is the default value, output 512Hz signal
740       \arg        RTC_CALIBRATION_1HZ: when the LSE freqency is 32768Hz and the RTC_PSC
741                                        is the default value, output 1Hz signal
742       \arg        RTC_ALARM_HIGH: when the  alarm flag is set, the output pin is high
743       \arg        RTC_ALARM_LOW: when the  Alarm flag is set, the output pin is low
744     \param[in]  mode: specify the output pin (PC13) mode when output alarm signal
745                 only one parameter can be selected which is shown as below:
746       \arg        RTC_ALARM_OUTPUT_OD: open drain mode
747       \arg        RTC_ALARM_OUTPUT_PP: push pull mode
748     \param[out] none
749     \retval     none
750 */
rtc_alter_output_config(uint32_t source,uint32_t mode)751 void rtc_alter_output_config(uint32_t source, uint32_t mode)
752 {
753     /* disable the write protection */
754     RTC_WPK = RTC_UNLOCK_KEY1;
755     RTC_WPK = RTC_UNLOCK_KEY2;
756 
757     RTC_CTL &= (uint32_t)~(RTC_CTL_COEN | RTC_CTL_OS | RTC_CTL_OPOL | RTC_CTL_COS);
758 
759     RTC_CTL |= (uint32_t)(source);
760 
761     /* alarm output */
762     if(RESET != (source & RTC_OS_ENABLE)){
763         RTC_TAMP &= (uint32_t)~(RTC_TAMP_PC13VAL);
764         RTC_TAMP |= (uint32_t)(mode);
765     }
766 
767     /* enable the write protection */
768     RTC_WPK = RTC_LOCK_KEY;
769 }
770 
771 
772 /*!
773     \brief      configure RTC calibration register
774     \param[in]  window: select calibration window
775                 only one parameter can be selected which is shown as below:
776       \arg        RTC_CALIBRATION_WINDOW_32S: 2exp20 RTCCLK cycles, 32s if RTCCLK = 32768 Hz
777       \arg        RTC_CALIBRATION_WINDOW_16S: 2exp19 RTCCLK cycles, 16s if RTCCLK = 32768 Hz
778       \arg        RTC_CALIBRATION_WINDOW_8S: 2exp18 RTCCLK cycles, 8s if RTCCLK = 32768 Hz
779     \param[in]  plus: add RTC clock or not
780                 only one parameter can be selected which is shown as below:
781       \arg        RTC_CALIBRATION_PLUS_SET: add one RTC clock every 2048 rtc clock
782       \arg        RTC_CALIBRATION_PLUS_RESET: no effect
783     \param[in]  minus: the RTC clock to minus during the calibration window(0x0 - 0x1FF)
784     \param[out] none
785     \retval     ErrStatus: ERROR or SUCCESS
786 */
rtc_calibration_config(uint32_t window,uint32_t plus,uint32_t minus)787 ErrStatus rtc_calibration_config(uint32_t window, uint32_t plus, uint32_t minus)
788 {
789     uint32_t time_index = RTC_HRFC_TIMEOUT;
790     ErrStatus error_status = ERROR;
791     uint32_t flag_status = RESET;
792 
793     /* disable the write protection */
794     RTC_WPK = RTC_UNLOCK_KEY1;
795     RTC_WPK = RTC_UNLOCK_KEY2;
796 
797     /* check if a calibration operation is ongoing */
798     do{
799         flag_status = RTC_STAT & RTC_STAT_SCPF;
800     }while((--time_index > 0x00U) && (RESET != flag_status));
801 
802     if(RESET == flag_status){
803         RTC_HRFC = (uint32_t)(window | plus | HRFC_CMSK(minus));
804         error_status = SUCCESS;
805     }
806 
807     /* enable the write protection */
808     RTC_WPK = RTC_LOCK_KEY;
809 
810     return error_status;
811 }
812 
813 /*!
814     \brief      ajust the daylight saving time by adding or substracting one hour from the current time
815     \param[in]  operation: hour ajustment operation
816                 only one parameter can be selected which is shown as below:
817       \arg        RTC_CTL_A1H: add one hour
818       \arg        RTC_CTL_S1H: substract one hour
819     \param[out] none
820     \retval     none
821 */
rtc_hour_adjust(uint32_t operation)822 void rtc_hour_adjust(uint32_t operation)
823 {
824     /* disable the write protection */
825     RTC_WPK = RTC_UNLOCK_KEY1;
826     RTC_WPK = RTC_UNLOCK_KEY2;
827 
828     RTC_CTL |= (uint32_t)(operation);
829 
830     /* enable the write protection */
831     RTC_WPK = RTC_LOCK_KEY;
832 }
833 
834 /*!
835     \brief      ajust RTC second or subsecond value of current time
836     \param[in]  add: add 1s to current time or not
837                 only one parameter can be selected which is shown as below:
838       \arg        RTC_SHIFT_ADD1S_RESET: no effect
839       \arg        RTC_SHIFT_ADD1S_SET: add 1s to current time
840     \param[in]  minus: number of subsecond to minus from current time(0x0 - 0x7FFF)
841     \param[out] none
842     \retval     ErrStatus: ERROR or SUCCESS
843 */
rtc_second_adjust(uint32_t add,uint32_t minus)844 ErrStatus rtc_second_adjust(uint32_t add, uint32_t minus)
845 {
846     uint32_t time_index = RTC_SHIFTCTL_TIMEOUT;
847     ErrStatus error_status = ERROR;
848     uint32_t flag_status = RESET;
849     uint32_t temp=0U;
850 
851     /* disable the write protection */
852     RTC_WPK = RTC_UNLOCK_KEY1;
853     RTC_WPK = RTC_UNLOCK_KEY2;
854 
855     /* check if a shift operation is ongoing */
856     do{
857         flag_status = RTC_STAT & RTC_STAT_SOPF;
858     }while((--time_index > 0x00U) && (RESET != flag_status));
859 
860     temp = RTC_CTL & RTC_CTL_REFEN;
861     /* check if the function of reference clock detection is disabled */
862     if((RESET == flag_status) && (RESET == temp)){
863         RTC_SHIFTCTL = (uint32_t)(add | SHIFTCTL_SFS(minus));
864         error_status = rtc_register_sync_wait();
865     }
866 
867     /* enable the write protection */
868     RTC_WPK = RTC_LOCK_KEY;
869 
870     return error_status;
871 }
872 
873 /*!
874     \brief      enable RTC bypass shadow registers function
875     \param[in]  none
876     \param[out] none
877     \retval     none
878 */
rtc_bypass_shadow_enable(void)879 void rtc_bypass_shadow_enable(void)
880 {
881     /* disable the write protection */
882     RTC_WPK = RTC_UNLOCK_KEY1;
883     RTC_WPK = RTC_UNLOCK_KEY2;
884 
885     RTC_CTL |= (uint8_t)RTC_CTL_BPSHAD;
886 
887     /* enable the write protection */
888     RTC_WPK = RTC_LOCK_KEY;
889 }
890 
891 /*!
892     \brief      disable RTC bypass shadow registers function
893     \param[in]  none
894     \param[out] none
895     \retval     none
896 */
rtc_bypass_shadow_disable(void)897 void rtc_bypass_shadow_disable(void)
898 {
899     /* disable the write protection */
900     RTC_WPK = RTC_UNLOCK_KEY1;
901     RTC_WPK = RTC_UNLOCK_KEY2;
902 
903     RTC_CTL &= (uint8_t)~RTC_CTL_BPSHAD;
904 
905     /* enable the write protection */
906     RTC_WPK = RTC_LOCK_KEY;
907 }
908 
909 /*!
910     \brief      enable RTC reference clock detection function
911     \param[in]  none
912     \param[out] none
913     \retval     ErrStatus: ERROR or SUCCESS
914 */
rtc_refclock_detection_enable(void)915 ErrStatus rtc_refclock_detection_enable(void)
916 {
917     ErrStatus error_status = ERROR;
918 
919     /* disable the write protection */
920     RTC_WPK = RTC_UNLOCK_KEY1;
921     RTC_WPK = RTC_UNLOCK_KEY2;
922 
923     /* enter init mode */
924     error_status = rtc_init_mode_enter();
925 
926     if(ERROR != error_status){
927         RTC_CTL |= (uint32_t)RTC_CTL_REFEN;
928         /* exit init mode */
929         rtc_init_mode_exit();
930     }
931 
932     /* enable the write protection */
933     RTC_WPK = RTC_LOCK_KEY;
934 
935     return error_status;
936 }
937 
938 /*!
939     \brief      disable RTC reference clock detection function
940     \param[in]  none
941     \param[out] none
942     \retval     ErrStatus: ERROR or SUCCESS
943 */
rtc_refclock_detection_disable(void)944 ErrStatus rtc_refclock_detection_disable(void)
945 {
946     ErrStatus error_status = ERROR;
947 
948     /* disable the write protection */
949     RTC_WPK = RTC_UNLOCK_KEY1;
950     RTC_WPK = RTC_UNLOCK_KEY2;
951 
952     /* enter init mode */
953     error_status = rtc_init_mode_enter();
954 
955     if(ERROR != error_status){
956         RTC_CTL &= (uint32_t)~RTC_CTL_REFEN;
957         /* exit init mode */
958         rtc_init_mode_exit();
959     }
960 
961     /* enable the write protection */
962     RTC_WPK = RTC_LOCK_KEY;
963 
964     return error_status;
965 }
966 
967 
968