1 /*************************************************************************************
2 * Copyright (C) 2019, Huada Semiconductor Co.,Ltd All rights reserved.
3 *
4 * This software is owned and published by:
5 * Huada Semiconductor Co.,Ltd ("HDSC").
6 *
7 * BY DOWNLOADING, INSTALLING OR USING THIS SOFTWARE, YOU AGREE TO BE BOUND
8 * BY ALL THE TERMS AND CONDITIONS OF THIS AGREEMENT.
9 *
10 * This software contains source code for use with HDSC
11 * components. This software is licensed by HDSC to be adapted only
12 * for use in systems utilizing HDSC components. HDSC shall not be
13 * responsible for misuse or illegal use of this software for devices not
14 * supported herein. HDSC is providing this software "AS IS" and will
15 * not be responsible for issues arising from incorrect user implementation
16 * of the software.
17 *
18 * Disclaimer:
19 * HDSC MAKES NO WARRANTY, EXPRESS OR IMPLIED, ARISING BY LAW OR OTHERWISE,
20 * REGARDING THE SOFTWARE (INCLUDING ANY ACOOMPANYING WRITTEN MATERIALS),
21 * ITS PERFORMANCE OR SUITABILITY FOR YOUR INTENDED USE, INCLUDING,
22 * WITHOUT LIMITATION, THE IMPLIED WARRANTY OF MERCHANTABILITY, THE IMPLIED
23 * WARRANTY OF FITNESS FOR A PARTICULAR PURPOSE OR USE, AND THE IMPLIED
24 * WARRANTY OF NONINFRINGEMENT.
25 * HDSC SHALL HAVE NO LIABILITY (WHETHER IN CONTRACT, WARRANTY, TORT,
26 * NEGLIGENCE OR OTHERWISE) FOR ANY DAMAGES WHATSOEVER (INCLUDING, WITHOUT
27 * LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS, BUSINESS INTERRUPTION,
28 * LOSS OF BUSINESS INFORMATION, OR OTHER PECUNIARY LOSS) ARISING FROM USE OR
29 * INABILITY TO USE THE SOFTWARE, INCLUDING, WITHOUT LIMITATION, ANY DIRECT,
30 * INDIRECT, INCIDENTAL, SPECIAL OR CONSEQUENTIAL DAMAGES OR LOSS OF DATA,
31 * SAVINGS OR PROFITS,
32 * EVEN IF Disclaimer HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
33 * YOU ASSUME ALL RESPONSIBILITIES FOR SELECTION OF THE SOFTWARE TO ACHIEVE YOUR
34 * INTENDED RESULTS, AND FOR THE INSTALLATION OF, USE OF, AND RESULTS OBTAINED
35 * FROM, THE SOFTWARE.
36 *
37 * This software may be replicated in part or whole for the licensed use,
38 * with the restriction that this Disclaimer and Copyright notice must be
39 * included with each copy of this software, whether used in part or whole,
40 * at all times.
41 */
42 /******************************************************************************/
43 /** \file rtc.c
44  **
45  ** RTC function driver API.
46  ** @link SampleGroup Some description @endlink
47  **
48  **   - 2019-04-10    First version
49  **
50  ******************************************************************************/
51 
52 /******************************************************************************/
53 /* Include files                                                              */
54 /******************************************************************************/
55 #include "hc32l196_rtc.h"
56 /**
57  ******************************************************************************
58  ** \addtogroup RtcGroup
59  ******************************************************************************/
60 //@{
61 
62 /******************************************************************************/
63 /* Local pre-processor symbols/macros ('#define')                             */
64 /******************************************************************************/
65 
66 /******************************************************************************/
67 /* Local function prototypes ('const')                                       */
68 /******************************************************************************/
69 const uint8_t Leap_Month_Base[]     =    {3,6,0,3,5,1,3,6,2,4,0,2};
70 const uint8_t NonLeap_Month_Base[]  =    {4,0,0,3,5,1,3,6,2,4,0,2};
71 const uint8_t Cnst_Month_Tbl[12]={0x31,0x28,0x31,0x30,0x31,0x30,0x31,0x31,0x30,0x31,0x30,0x31};
72 /******************************************************************************/
73 /* Local function prototypes ('static')                                       */
74 /******************************************************************************/
75 
76 /******************************************************************************/
77 /* Local variable prototypes ('static')                                       */
78 /******************************************************************************/
79 
80 /*****************************************************************************
81  * Function implementation - global ('extern') and local ('static')
82  *****************************************************************************/
83 
84 /**
85 ******************************************************************************
86     ** \brief  RTC计数器的使能或停止
87     **
88     ** @param  NewState : TRUE 或 FALSE
89     ** \retval 无
90     **
91 ******************************************************************************/
Rtc_Cmd(boolean_t NewState)92 void Rtc_Cmd(boolean_t NewState)
93 {
94     SetBit((uint32_t)(&(M0P_RTC->CR0)), 7, NewState);
95 }
96 
97 /**
98 ******************************************************************************
99     ** \brief  RTC计数器启动等待函数,如启动RTC计数器后立即进入低功耗模式,
100     **         进入低功耗模式之前需执行此函数,以确保RTC已启动完成
101     **
102     ** @param  NewState : TRUE 或 FALSE
103     ** \retval 无
104     **
105 ******************************************************************************/
Rtc_StartWait(void)106 void Rtc_StartWait(void)
107 {
108     M0P_RTC->CR1_f.WAIT = 1;
109     while (M0P_RTC->CR1_f.WAITF != 1)  //等待直到WAITF=1
110     {
111         ;
112     }
113     M0P_RTC->CR1_f.WAIT = 0;
114     while (M0P_RTC->CR1_f.WAITF != 0)  //等待直到WAITF=0
115     {
116         ;
117     }
118 }
119 
120 /**
121 ******************************************************************************
122     ** \brief  RTC的1Hz输出的使能或停止
123     ** @param  pricision : RtcHz1selGeneralPricision 或 RtcHz1selHighPricision
124     ** @param  NewState : Hz1o_Disable 或 HZ1o_Enable
125     ** \retval 无
126     **
127 ******************************************************************************/
Rtc_Hz1Cmd(en_rtc_hz1sel_t pricision,boolean_t NewState)128 void Rtc_Hz1Cmd(en_rtc_hz1sel_t pricision, boolean_t NewState)
129 {
130     SetBit((uint32_t)(&(M0P_RTC->CR0)), 6, pricision);  //设置普通精度或者高精度1Hz输出
131     SetBit((uint32_t)(&(M0P_RTC->CR0)), 5, NewState);   //设置1Hz输出使能或禁止
132 }
133 
134 /**
135 ******************************************************************************
136     ** \brief  设置周期中断的类型(PRDSEL)及其所选类型的时间(PRDS或PRDX)
137     **
138   ** @param   pstCyc: 根据结构体的定义设置PRDSEL、PRDS与PRDX
139     ** \retval  Ok、Error 或 ErrorInvalidParameter
140     **
141 ******************************************************************************/
Rtc_SetCyc(stc_rtc_cyccfg_t * pstCyc)142 en_result_t Rtc_SetCyc(stc_rtc_cyccfg_t* pstCyc)
143 {
144     en_result_t enRet = Error;
145     M0P_RTC->CR0_f.PRDSEL = pstCyc->rtcPrdsel;
146     if(pstCyc->rtcPrdsel == RtcPrds)
147     {
148         M0P_RTC->CR0_f.PRDS = pstCyc->rtcPrds;
149     }
150     else if(pstCyc->rtcPrdsel == RtcPrdx)
151     {
152         if(pstCyc->rtcPrdx>=64)
153         {
154             enRet = ErrorInvalidParameter;
155             return enRet;
156         }
157         M0P_RTC->CR0_f.PRDX = pstCyc->rtcPrdx;
158     }
159     else
160     {
161         ;
162     }
163     enRet = Ok;
164     return enRet;
165 }
166 
167 /**
168 ******************************************************************************
169     ** \brief  RTC闹钟中断的使能或停止
170     **
171     ** @param  NewState : TRUE 或 FALSE
172     ** \retval 无
173     **
174 ******************************************************************************/
Rtc_AlmIeCmd(boolean_t NewState)175 void Rtc_AlmIeCmd(boolean_t NewState)
176 {
177     SetBit((uint32_t)(&(M0P_RTC->CR1)), 3, 0);        //清除周期中断标志位
178     SetBit((uint32_t)(&(M0P_RTC->CR1)), 4, 0);        //清除周期中断标志位
179     SetBit((uint32_t)(&(M0P_RTC->CR1)), 6, NewState);
180 }
181 
182 /**
183 ******************************************************************************
184     ** \brief  RTC闹钟的使能或停止
185     **
186     ** @param  NewState : Almen_Disable 或 Almen_Enable
187     ** \retval 无
188     **
189 ******************************************************************************/
Rtc_AlmEnCmd(boolean_t NewState)190 void Rtc_AlmEnCmd(boolean_t NewState)
191 {
192     SetBit((uint32_t)(&(M0P_RTC->CR1)), 7, NewState);
193 }
194 
195 /**
196 ******************************************************************************
197     ** \brief  获取RTC闹钟中断状态位
198     **
199     ** @param  无
200     ** \retval TRUE 或 FALSE
201     **
202 ******************************************************************************/
Rtc_GetAlmfItStatus(void)203 boolean_t Rtc_GetAlmfItStatus(void)
204 {
205     return GetBit((uint32_t)(&(M0P_RTC->CR1)), 4);
206 }
207 
208 /**
209 ******************************************************************************
210     ** \brief  清除RTC闹钟中断状态位
211     **
212     ** @param  无
213     ** \retval 无
214     **
215 ******************************************************************************/
Rtc_ClearAlmfItStatus(void)216 void Rtc_ClearAlmfItStatus(void)
217 {
218     SetBit((uint32_t)(&(M0P_RTC->CR1)), 4, 0);
219 }
220 
221 /**
222 ******************************************************************************
223     ** \brief  清除RTC周期中断状态位
224     **
225     ** @param  无
226     ** \retval 无
227     **
228 ******************************************************************************/
Rtc_ClearPrdfItStatus(void)229 void Rtc_ClearPrdfItStatus(void)
230 {
231     SetBit((uint32_t)(&(M0P_RTC->CR1)), 3, 0);
232 }
233 
234 /**
235 ******************************************************************************
236     ** \brief  获取RTC周期中断状态位
237     **
238     ** @param  无
239     ** \retval TRUE 或 FALSE
240     **
241 ******************************************************************************/
Rtc_GetPridItStatus(void)242 boolean_t Rtc_GetPridItStatus(void)
243 {
244     return GetBit((uint32_t)(&(M0P_RTC->CR1)), 3);
245 }
246 
247 /**
248 ******************************************************************************
249     ** \brief  配置RTC的误差补偿寄存器
250     **
251     ** @param  CompValue:数值的范围为:32-256
252     ** @param  NewStatus: RtcCompenDisable 或 RtcAmCompenEnable
253     ** \retval Ok  ErrorInvalidParameter
254     **
255 ******************************************************************************/
Rtc_CompCfg(uint16_t CompVlue,en_rtc_compen_t NewStatus)256 en_result_t Rtc_CompCfg(uint16_t CompVlue, en_rtc_compen_t NewStatus)
257 {
258     en_result_t enRet = Error;
259     if(CompVlue<=256)
260     {
261         M0P_RTC->COMPEN_f.EN = NewStatus;
262         M0P_RTC->COMPEN_f.CR = CompVlue;
263     }
264     else
265     {
266         enRet = ErrorInvalidParameter;
267     }
268     return enRet;
269 }
270 
271 /**
272  ******************************************************************************
273  ** \brief  RTC根据日期计算周数
274  **
275  ** \param pu8buf时间数据
276  ** \param u8limit_min最小值
277  ** \param u8limit_max最大值
278  **
279  ** \retval Error 错误,Ok校验正确
280  **
281  ******************************************************************************/
Check_BCD_Format(uint8_t u8data,uint8_t u8limit_min,uint8_t u8limit_max)282 en_result_t Check_BCD_Format(uint8_t u8data,uint8_t u8limit_min, uint8_t u8limit_max)
283 {
284 
285     if (((u8data & 0x0F) > 0x09) || ((u8data & 0xF0) > 0x90)
286     ||(u8data > u8limit_max) || (u8data < u8limit_min))
287     {
288         return Error;
289     }
290     return Ok;
291 }
292 
293 /**
294  ******************************************************************************
295  ** \brief  RTC 平、闰年检测
296  **
297 ** \param  u8year:年十进制低两位:0-99
298  **
299  ** \retval  1:闰年  0:平年
300  **
301  ******************************************************************************/
Rtc_CheckLeapYear(uint8_t u8year)302 uint8_t Rtc_CheckLeapYear(uint8_t u8year)
303 {
304         uint16_t tmp;
305         tmp=2000+u8year;
306         if((((tmp % 4)==0) && ((tmp % 100) !=0))|| ((tmp % 400) ==0))
307     {
308         return 1;
309     }
310     else
311     {
312         return 0;
313     }
314 }
315 
316 /**
317  ******************************************************************************
318  ** \brief  RTC根据年获取二月的天数
319  **
320  ** \param [in] u8month月份,u8year年份
321  **
322 ** \retval u8day天数:28或29
323  **
324  ******************************************************************************/
Get_Month2_Day(uint8_t u8year)325 uint8_t Get_Month2_Day( uint8_t u8year)
326 {
327     uint8_t u8day = 0;
328 
329     u8day = 28;
330     if(Rtc_CheckLeapYear(u8year) == 1)
331     {
332         u8day++;
333     }
334     return u8day;
335 }
336 
337 /**
338  ******************************************************************************
339  ** \brief  RTC获取时间函数
340  **
341  ** \param time: 用于存放读取自时间寄存器的时间数据,格式为BCD码格式
342  **
343  ** \retval Ok  获取正常
344  ** \retval ErrorTimeout 时间溢出错误
345  ******************************************************************************/
Rtc_ReadDateTime(stc_rtc_time_t * time)346 en_result_t Rtc_ReadDateTime(stc_rtc_time_t* time)
347 {
348     uint32_t u32TimeOut;
349     ASSERT(NULL != pstcTimeDate);
350     u32TimeOut = 1000;
351     if(1 == M0P_RTC->CR0_f.START)
352     {
353         M0P_RTC->CR1_f.WAIT = 1;
354         while(u32TimeOut--)
355         {
356             if(M0P_RTC->CR1_f.WAITF)
357             {
358             break;
359             }
360         }
361         if(u32TimeOut==0)
362         {
363             return ErrorTimeout;
364         }
365     }
366     time->u8Second  = M0P_RTC->SEC;
367     time->u8Minute  = M0P_RTC->MIN;
368     if(1 == M0P_RTC->CR0_f.AMPM)
369     {
370         time->u8Hour   = M0P_RTC->HOUR;
371     }
372     else
373     {
374         time->u8Hour   = M0P_RTC->HOUR&0x1f;
375     }
376     time->u8Day       = M0P_RTC->DAY;
377     time->u8DayOfWeek = M0P_RTC->WEEK;
378     time->u8Month     = M0P_RTC->MON;
379     time->u8Year      = M0P_RTC->YEAR;
380 
381     M0P_RTC->CR1_f.WAIT = 0;
382     if(1 == M0P_RTC->CR0_f.START)
383     {
384             while(M0P_RTC->CR1_f.WAITF)
385             {}
386     }
387 
388     return Ok;
389 }
390 
391 /**
392  ******************************************************************************
393  ** \brief  向RTC时间寄存器写入时间
394  **
395  ** \param time: 存放时间的结构体,各个时间均为BCD码格式
396  **
397  ** \retval ErrorTimeout 或 Ok
398  **
399  ******************************************************************************/
Rtc_SetTime(stc_rtc_time_t * time)400 en_result_t Rtc_SetTime(stc_rtc_time_t* time)
401 {
402     en_result_t enRet = Ok;
403     uint16_t u16TimeOut;
404     u16TimeOut = 1000;
405     if(M0P_RTC->CR0_f.START == 1)
406     {
407         M0P_RTC->CR1_f.WAIT = 1;
408         while(--u16TimeOut)
409         {
410             if(M0P_RTC->CR1_f.WAITF)
411             {
412                     break;
413             }
414         }
415         if(u16TimeOut==0)
416         {
417             return ErrorTimeout;
418         }
419     }
420     M0P_RTC->SEC   = time->u8Second;
421     M0P_RTC->MIN   = time->u8Minute;
422     M0P_RTC->HOUR  = time->u8Hour;
423     M0P_RTC->DAY   = time->u8Day;
424     M0P_RTC->MON   = time->u8Month;
425     M0P_RTC->YEAR  = time->u8Year;
426     M0P_RTC->WEEK  = time->u8DayOfWeek;
427 
428     M0P_RTC->CR1_f.WAIT = 0;
429     if(M0P_RTC->CR0_f.START == 1)
430     {
431         while(M0P_RTC->CR1_f.WAITF)
432         {}
433     }
434     enRet = Ok;
435     return enRet;
436 }
437 
438 /**
439  ******************************************************************************
440  ** \brief  RTC闹钟中断时间获取
441  **
442  ** \param pstcAlarmTime:存放闹钟时间寄存器数据:秒 分 时 周
443  **
444  ** \retval 无
445  **
446  ******************************************************************************/
Rtc_GetAlarmTime(stc_rtc_alarmtime_t * pstcAlarmTime)447 void Rtc_GetAlarmTime(stc_rtc_alarmtime_t* pstcAlarmTime)
448 {
449     pstcAlarmTime->RtcAlarmSec    = M0P_RTC->ALMSEC;
450     pstcAlarmTime->RtcAlarmMinute = M0P_RTC->ALMMIN;
451     pstcAlarmTime->RtcAlarmHour     = M0P_RTC->ALMHOUR;
452     pstcAlarmTime->RtcAlarmWeek     = M0P_RTC->ALMWEEK;
453 }
454 
455 /**
456  ******************************************************************************
457  ** \brief  RTC闹钟设置
458  **
459  ** \param [in] pstcAlarmTime闹钟时间:秒 分 时 周
460  **
461  ** \retval Ok  设置正常
462  **
463  ******************************************************************************/
Rtc_SetAlarmTime(stc_rtc_alarmtime_t * pstcAlarmTime)464 en_result_t Rtc_SetAlarmTime(stc_rtc_alarmtime_t* pstcAlarmTime)
465 {
466     en_result_t enRet = Ok;
467 //    ASSERT(NULL != pstcAlarmTime);
468     Rtc_AlmEnCmd(FALSE);      //闹钟禁止以后再设置闹钟时间
469     enRet = Check_BCD_Format(pstcAlarmTime->RtcAlarmSec,0x00,0x59);
470     if(M0P_RTC->CR0_f.AMPM == RtcAm)
471     {
472         enRet = Check_BCD_Format(pstcAlarmTime->RtcAlarmHour,0x00,0x12);
473     }
474     else
475     {
476         enRet = Check_BCD_Format(pstcAlarmTime->RtcAlarmHour,0x00,0x24);
477     }
478     if(enRet != Ok)
479     {
480         return enRet;
481     }
482     enRet = Check_BCD_Format(pstcAlarmTime->RtcAlarmMinute,0x00,0x59);
483     if(enRet != Ok)
484     {
485         return enRet;
486     }
487 
488     if(enRet != Ok)
489     {
490             return enRet;
491     }
492     M0P_RTC->ALMSEC  = pstcAlarmTime->RtcAlarmSec & 0x7f;
493     M0P_RTC->ALMMIN  = pstcAlarmTime->RtcAlarmMinute & 0x7f;
494     M0P_RTC->ALMHOUR = pstcAlarmTime->RtcAlarmHour & 0x3f;
495     M0P_RTC->ALMWEEK = pstcAlarmTime->RtcAlarmWeek;
496     Rtc_AlmEnCmd(TRUE);      //闹钟许可
497     enRet = Ok;
498     return enRet;
499 }
500 
501 /**
502 ******************************************************************************
503     ** \brief  初始化RTC
504     **
505     ** @param  Rtc_InitStruct 存放stc_rtc_initstruct_t类型的结构体
506     ** \retval 无
507     **
508 ******************************************************************************/
Rtc_Init(stc_rtc_initstruct_t * Rtc_InitStruct)509 void Rtc_Init(stc_rtc_initstruct_t* Rtc_InitStruct)
510 {
511     Rtc_Cmd(FALSE);
512     M0P_RTC->CR0_f.AMPM = Rtc_InitStruct->rtcAmpm;        //实时时钟小时的时制
513     Rtc_SetCyc(&Rtc_InitStruct->rtcPrdsel);                //设置周期中断的类型(PRDSEL)及其所选类型的时间(PRDS或PRDX)
514     M0P_RTC->CR1_f.CKSEL = Rtc_InitStruct->rtcClksrc;      //实时时钟RTC的时钟源
515     Rtc_CompCfg(Rtc_InitStruct->rtcCompValue, Rtc_InitStruct->rtcCompen); //配置时钟误差补偿寄存器
516     Rtc_SetTime(&Rtc_InitStruct->rtcTime);                 //设置初始时钟
517 }
518 
519 
520 
521