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