]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/CORTEX_M7_SAMV71_Xplained_IAR_Keil/libchip_samv7/source/rtc.c
Final V8.2.1 release ready for tagging:
[freertos] / FreeRTOS / Demo / CORTEX_M7_SAMV71_Xplained_IAR_Keil / libchip_samv7 / source / rtc.c
1 /* ----------------------------------------------------------------------------\r
2  *         SAM Software Package License\r
3  * ----------------------------------------------------------------------------\r
4  * Copyright (c) 2011, Atmel Corporation\r
5  *\r
6  * All rights reserved.\r
7  *\r
8  * Redistribution and use in source and binary forms, with or without\r
9  * modification, are permitted provided that the following conditions are met:\r
10  *\r
11  * - Redistributions of source code must retain the above copyright notice,\r
12  * this list of conditions and the disclaimer below.\r
13  *\r
14  * Atmel's name may not be used to endorse or promote products derived from\r
15  * this software without specific prior written permission.\r
16  *\r
17  * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR\r
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE\r
20  * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,\r
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\r
22  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,\r
23  * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\r
24  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\r
25  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\r
26  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
27  * ----------------------------------------------------------------------------\r
28  */\r
29 \r
30 /** \addtogroup rtc_module Working with RTC\r
31  *  \ingroup peripherals_module\r
32  * The RTC driver provides the interface to configure and use the RTC\r
33  * peripheral.\r
34  *\r
35  * It manages date, time, and alarms.\n\r
36  * This timer is clocked by the 32kHz system clock, and is not impacted by\r
37  * power management settings (PMC). To be accurate, it is better to use an\r
38  * external 32kHz crystal instead of the internal 32kHz RC.\n\r
39  *\r
40  * It uses BCD format, and time can be set in AM/PM or 24h mode through a\r
41  * configuration bit in the mode register.\n\r
42  *\r
43  * To update date or time, the user has to follow these few steps :\r
44  * <ul>\r
45  * <li>Set UPDTIM and/or UPDCAL bit(s) in RTC_CR,</li>\r
46  * <li>Polling or IRQ on the ACKUPD bit of RTC_CR,</li>\r
47  * <li>Clear ACKUPD bit in RTC_SCCR,</li>\r
48  * <li>Update Time and/or Calendar values in RTC_TIMR/RTC_CALR (BCD format),</li>\r
49  * <li>Clear UPDTIM and/or UPDCAL bit in RTC_CR.</li>\r
50  * </ul>\r
51  * An alarm can be set to happen on month, date, hours, minutes or seconds,\r
52  * by setting the proper "Enable" bit of each of these fields in the Time and\r
53  * Calendar registers.\r
54  * This allows a large number of configurations to be available for the user.\r
55  * Alarm occurence can be detected even by polling or interrupt.\r
56  *\r
57  * A check of the validity of the date and time format and values written by the user is automatically done.\r
58  * Errors are reported through the Valid Entry Register.\r
59  *\r
60  * For more accurate information, please look at the RTC section of the\r
61  * Datasheet.\r
62  *\r
63  * Related files :\n\r
64  * \ref rtc.c\n\r
65  * \ref rtc.h.\n\r
66 */\r
67 /*@{*/\r
68 /*@}*/\r
69 \r
70 \r
71 /**\r
72  * \file\r
73  *\r
74  * Implementation of Real Time Clock (RTC) controller.\r
75  *\r
76  */\r
77 \r
78 /*----------------------------------------------------------------------------\r
79  *        Headers\r
80  *----------------------------------------------------------------------------*/\r
81 \r
82 #include "chip.h"\r
83 \r
84 #include <stdint.h>\r
85 #include <assert.h>\r
86 \r
87 /*----------------------------------------------------------------------------\r
88  *        Exported functions\r
89  *----------------------------------------------------------------------------*/\r
90 \r
91 /**\r
92  * \brief Sets the RTC in either 12 or 24 hour mode.\r
93  *\r
94  * \param mode  Hour mode.\r
95  */\r
96 extern void RTC_SetHourMode( Rtc* pRtc, uint32_t dwMode )\r
97 {\r
98     assert((dwMode & 0xFFFFFFFE) == 0);\r
99 \r
100     pRtc->RTC_MR = dwMode ;\r
101 }\r
102 \r
103 /**\r
104  * \brief Gets the RTC mode.\r
105  *\r
106  * \return Hour mode.\r
107  */\r
108 extern uint32_t RTC_GetHourMode( Rtc* pRtc )\r
109 {\r
110     uint32_t dwMode ;\r
111 \r
112     TRACE_DEBUG( "RTC_SetHourMode()\n\r" ) ;\r
113 \r
114     dwMode = pRtc->RTC_MR;\r
115     dwMode &= 0xFFFFFFFE;\r
116 \r
117     return dwMode ;\r
118 }\r
119 \r
120 /**\r
121  * \brief Enables the selected interrupt sources of the RTC.\r
122  *\r
123  * \param sources  Interrupt sources to enable.\r
124  */\r
125 extern void RTC_EnableIt( Rtc* pRtc, uint32_t dwSources )\r
126 {\r
127     assert((dwSources & (uint32_t)(~0x1F)) == 0);\r
128 \r
129     TRACE_DEBUG( "RTC_EnableIt()\n\r" ) ;\r
130 \r
131     pRtc->RTC_IER = dwSources ;\r
132 }\r
133 \r
134 /**\r
135 * \brief Disables the selected interrupt sources of the RTC.\r
136 *\r
137 * \param sources  Interrupt sources to disable.\r
138 */\r
139 extern void RTC_DisableIt( Rtc* pRtc, uint32_t dwSources )\r
140 {\r
141     assert((dwSources & (uint32_t)(~0x1F)) == 0);\r
142 \r
143     TRACE_DEBUG( "RTC_DisableIt()\n\r" ) ;\r
144 \r
145     pRtc->RTC_IDR = dwSources ;\r
146 }\r
147 \r
148 /**\r
149  * \brief Sets the current time in the RTC.\r
150  *\r
151  * \note In successive update operations, the user must wait at least one second\r
152  * after resetting the UPDTIM/UPDCAL bit in the RTC_CR before setting these\r
153  * bits again. Please look at the RTC section of the datasheet for detail.\r
154  *\r
155  * \param ucHour    Current hour in 12 or 24 hour mode.\r
156  * \param ucMinute  Current minute.\r
157  * \param ucSecond  Current second.\r
158  *\r
159  * \return 0 sucess, 1 fail to set\r
160  */\r
161 extern int RTC_SetTime( Rtc* pRtc, uint8_t ucHour, uint8_t ucMinute, uint8_t ucSecond )\r
162 {\r
163     uint32_t dwTime=0 ;\r
164     uint8_t ucHour_bcd ;\r
165     uint8_t ucMin_bcd ;\r
166     uint8_t ucSec_bcd ;\r
167 \r
168     TRACE_DEBUG( "RTC_SetTime(%02d:%02d:%02d)\n\r", ucHour, ucMinute, ucSecond ) ;\r
169 \r
170     /* if 12-hour mode, set AMPM bit */\r
171     if ( (pRtc->RTC_MR & RTC_MR_HRMOD) == RTC_MR_HRMOD )\r
172     {\r
173         if ( ucHour > 12 )\r
174         {\r
175             ucHour -= 12 ;\r
176             dwTime |= RTC_TIMR_AMPM ;\r
177         }\r
178     }\r
179     ucHour_bcd = (ucHour%10)   | ((ucHour/10)<<4) ;\r
180     ucMin_bcd  = (ucMinute%10) | ((ucMinute/10)<<4) ;\r
181     ucSec_bcd  = (ucSecond%10) | ((ucSecond/10)<<4) ;\r
182 \r
183     /* value overflow */\r
184     if ( (ucHour_bcd & (uint8_t)(~RTC_HOUR_BIT_LEN_MASK)) |\r
185          (ucMin_bcd & (uint8_t)(~RTC_MIN_BIT_LEN_MASK)) |\r
186          (ucSec_bcd & (uint8_t)(~RTC_SEC_BIT_LEN_MASK)))\r
187     {\r
188         return 1 ;\r
189     }\r
190 \r
191     dwTime = ucSec_bcd | (ucMin_bcd << 8) | (ucHour_bcd<<16) ;\r
192 \r
193     pRtc->RTC_CR |= RTC_CR_UPDTIM ;\r
194     while ((pRtc->RTC_SR & RTC_SR_ACKUPD) != RTC_SR_ACKUPD) ;\r
195     pRtc->RTC_SCCR = RTC_SCCR_ACKCLR ;\r
196     pRtc->RTC_TIMR = dwTime ;\r
197     pRtc->RTC_CR &= (uint32_t)(~RTC_CR_UPDTIM) ;\r
198     pRtc->RTC_SCCR |= RTC_SCCR_SECCLR ;\r
199 \r
200     return (int)(pRtc->RTC_VER & RTC_VER_NVTIM) ;\r
201 }\r
202 \r
203 /**\r
204  * \brief Retrieves the current time as stored in the RTC in several variables.\r
205  *\r
206  * \param pucHour    If not null, current hour is stored in this variable.\r
207  * \param pucMinute  If not null, current minute is stored in this variable.\r
208  * \param pucSecond  If not null, current second is stored in this variable.\r
209  */\r
210 extern void RTC_GetTime( Rtc* pRtc, uint8_t *pucHour, uint8_t *pucMinute, uint8_t *pucSecond )\r
211 {\r
212     uint32_t dwTime ;\r
213 \r
214     TRACE_DEBUG( "RTC_GetTime()\n\r" ) ;\r
215 \r
216     /* Get current RTC time */\r
217     dwTime = pRtc->RTC_TIMR ;\r
218     while ( dwTime != pRtc->RTC_TIMR )\r
219     {\r
220         dwTime = pRtc->RTC_TIMR ;\r
221     }\r
222 \r
223     /* Hour */\r
224     if ( pucHour )\r
225     {\r
226         *pucHour = ((dwTime & 0x00300000) >> 20) * 10\r
227                  + ((dwTime & 0x000F0000) >> 16);\r
228 \r
229         if ( (dwTime & RTC_TIMR_AMPM) == RTC_TIMR_AMPM )\r
230         {\r
231             *pucHour += 12 ;\r
232         }\r
233     }\r
234 \r
235     /* Minute */\r
236     if ( pucMinute )\r
237     {\r
238         *pucMinute = ((dwTime & 0x00007000) >> 12) * 10\r
239                    + ((dwTime & 0x00000F00) >> 8);\r
240     }\r
241 \r
242     /* Second */\r
243     if ( pucSecond )\r
244     {\r
245         *pucSecond = ((dwTime & 0x00000070) >> 4) * 10\r
246                    + (dwTime & 0x0000000F);\r
247     }\r
248 }\r
249 \r
250 /**\r
251  * \brief Sets a time alarm on the RTC.\r
252  * The match is performed only on the provided variables;\r
253  * Setting all pointers to 0 disables the time alarm.\r
254  *\r
255  * \note In AM/PM mode, the hour value must have bit #7 set for PM, cleared for\r
256  * AM (as expected in the time registers).\r
257  *\r
258  * \param pucHour    If not null, the time alarm will hour-match this value.\r
259  * \param pucMinute  If not null, the time alarm will minute-match this value.\r
260  * \param pucSecond  If not null, the time alarm will second-match this value.\r
261  *\r
262  * \return 0 success, 1 fail to set\r
263  */\r
264 extern int RTC_SetTimeAlarm( Rtc* pRtc, uint8_t *pucHour, uint8_t *pucMinute, uint8_t *pucSecond )\r
265 {\r
266     uint32_t dwAlarm=0 ;\r
267 \r
268     TRACE_DEBUG( "RTC_SetTimeAlarm()\n\r" ) ;\r
269 \r
270     /* Hour */\r
271     if ( pucHour )\r
272     {\r
273         dwAlarm |= RTC_TIMALR_HOUREN | ((*pucHour / 10) << 20) | ((*pucHour % 10) << 16);\r
274     }\r
275 \r
276     /* Minute */\r
277     if ( pucMinute )\r
278     {\r
279         dwAlarm |= RTC_TIMALR_MINEN | ((*pucMinute / 10) << 12) | ((*pucMinute % 10) << 8);\r
280     }\r
281 \r
282     /* Second */\r
283     if ( pucSecond )\r
284     {\r
285         dwAlarm |= RTC_TIMALR_SECEN | ((*pucSecond / 10) << 4) | (*pucSecond % 10);\r
286     }\r
287 \r
288     pRtc->RTC_TIMALR = dwAlarm ;\r
289 \r
290     return (int)(pRtc->RTC_VER & RTC_VER_NVTIMALR) ;\r
291 }\r
292 \r
293 /**\r
294  * \brief Retrieves the current year, month and day from the RTC.\r
295  * Month, day and week values are numbered starting at 1.\r
296  *\r
297  * \param pYwear  Current year (optional).\r
298  * \param pucMonth  Current month (optional).\r
299  * \param pucDay  Current day (optional).\r
300  * \param pucWeek  Current day in current week (optional).\r
301  */\r
302 extern void RTC_GetDate( Rtc* pRtc, uint16_t *pwYear, uint8_t *pucMonth, uint8_t *pucDay, uint8_t *pucWeek )\r
303 {\r
304     uint32_t dwDate ;\r
305 \r
306     /* Get current date (multiple reads are necessary to insure a stable value) */\r
307     do\r
308     {\r
309         dwDate = pRtc->RTC_CALR ;\r
310     }\r
311     while ( dwDate != pRtc->RTC_CALR ) ;\r
312 \r
313     /* Retrieve year */\r
314     if ( pwYear )\r
315     {\r
316         *pwYear = (((dwDate  >> 4) & 0x7) * 1000)\r
317                  + ((dwDate & 0xF) * 100)\r
318                  + (((dwDate >> 12) & 0xF) * 10)\r
319                  + ((dwDate >> 8) & 0xF);\r
320     }\r
321 \r
322     /* Retrieve month */\r
323     if ( pucMonth )\r
324     {\r
325         *pucMonth = (((dwDate >> 20) & 1) * 10) + ((dwDate >> 16) & 0xF);\r
326     }\r
327 \r
328     /* Retrieve day */\r
329     if ( pucDay )\r
330     {\r
331         *pucDay = (((dwDate >> 28) & 0x3) * 10) + ((dwDate >> 24) & 0xF);\r
332     }\r
333 \r
334     /* Retrieve week */\r
335     if ( pucWeek )\r
336     {\r
337         *pucWeek = ((dwDate >> 21) & 0x7);\r
338     }\r
339 }\r
340 \r
341 /**\r
342  * \brief Sets the current year, month and day in the RTC.\r
343  * Month, day and week values must be numbered starting from 1.\r
344  *\r
345  * \note In successive update operations, the user must wait at least one second\r
346  * after resetting the UPDTIM/UPDCAL bit in the RTC_CR before setting these\r
347  * bits again. Please look at the RTC section of the datasheet for detail.\r
348  *\r
349  * \param wYear  Current year.\r
350  * \param ucMonth Current month.\r
351  * \param ucDay   Current day.\r
352  * \param ucWeek  Day number in current week.\r
353  *\r
354  * \return 0 success, 1 fail to set\r
355  */\r
356 extern int RTC_SetDate( Rtc* pRtc, uint16_t wYear, uint8_t ucMonth, uint8_t ucDay, uint8_t ucWeek )\r
357 {\r
358     uint32_t wDate ;\r
359     uint8_t ucCent_bcd ;\r
360     uint8_t ucYear_bcd ;\r
361     uint8_t ucMonth_bcd ;\r
362     uint8_t ucDay_bcd ;\r
363     uint8_t ucWeek_bcd ;\r
364 \r
365     ucCent_bcd  = ((wYear/100)%10) | ((wYear/1000)<<4);\r
366     ucYear_bcd  = (wYear%10) | (((wYear/10)%10)<<4);\r
367     ucMonth_bcd = ((ucMonth%10) | (ucMonth/10)<<4);\r
368     ucDay_bcd   = ((ucDay%10) | (ucDay/10)<<4);\r
369     ucWeek_bcd  = ((ucWeek%10) | (ucWeek/10)<<4);\r
370 \r
371     /* value over flow */\r
372     if ( (ucCent_bcd & (uint8_t)(~RTC_CENT_BIT_LEN_MASK)) |\r
373          (ucYear_bcd & (uint8_t)(~RTC_YEAR_BIT_LEN_MASK)) |\r
374          (ucMonth_bcd & (uint8_t)(~RTC_MONTH_BIT_LEN_MASK)) |\r
375          (ucWeek_bcd & (uint8_t)(~RTC_WEEK_BIT_LEN_MASK)) |\r
376          (ucDay_bcd & (uint8_t)(~RTC_DATE_BIT_LEN_MASK))\r
377        )\r
378     {\r
379         return 1 ;\r
380     }\r
381 \r
382 \r
383     /* Convert values to date register value */\r
384     wDate = ucCent_bcd |\r
385             (ucYear_bcd << 8) |\r
386             (ucMonth_bcd << 16) |\r
387             (ucWeek_bcd << 21) |\r
388             (ucDay_bcd << 24);\r
389 \r
390     /* Update calendar register  */\r
391     pRtc->RTC_CR |= RTC_CR_UPDCAL ;\r
392     while ((pRtc->RTC_SR & RTC_SR_ACKUPD) != RTC_SR_ACKUPD) ;\r
393 \r
394     pRtc->RTC_SCCR = RTC_SCCR_ACKCLR;\r
395     pRtc->RTC_CALR = wDate ;\r
396     pRtc->RTC_CR &= (uint32_t)(~RTC_CR_UPDCAL) ;\r
397     pRtc->RTC_SCCR |= RTC_SCCR_SECCLR; /* clear SECENV in SCCR */\r
398 \r
399     return (int)(pRtc->RTC_VER & RTC_VER_NVCAL) ;\r
400 }\r
401 \r
402 /**\r
403  * \brief Sets a date alarm in the RTC.\r
404  * The alarm will match only the provided values;\r
405  * Passing a null-pointer disables the corresponding field match.\r
406  *\r
407  * \param pucMonth If not null, the RTC alarm will month-match this value.\r
408  * \param pucDay   If not null, the RTC alarm will day-match this value.\r
409  *\r
410  * \return 0 success, 1 fail to set\r
411  */\r
412 extern int RTC_SetDateAlarm( Rtc* pRtc, uint8_t *pucMonth, uint8_t *pucDay )\r
413 {\r
414     uint32_t dwAlarm ;\r
415 \r
416     dwAlarm = ((pucMonth) || (pucDay)) ? (0) : (0x01010000);\r
417 \r
418     TRACE_DEBUG( "RTC_SetDateAlarm()\n\r" ) ;\r
419 \r
420     /* Compute alarm field value */\r
421     if ( pucMonth )\r
422     {\r
423         dwAlarm |= RTC_CALALR_MTHEN | ((*pucMonth / 10) << 20) | ((*pucMonth % 10) << 16);\r
424     }\r
425 \r
426     if ( pucDay )\r
427     {\r
428         dwAlarm |= RTC_CALALR_DATEEN | ((*pucDay / 10) << 28) | ((*pucDay % 10) << 24);\r
429     }\r
430 \r
431     /* Set alarm */\r
432     pRtc->RTC_CALALR = dwAlarm ;\r
433 \r
434     return (int)(pRtc->RTC_VER & RTC_VER_NVCALALR) ;\r
435 }\r
436 \r
437 /**\r
438  * \brief Clear flag bits of status clear command register in the RTC.\r
439  *\r
440  * \param mask Bits mask of cleared events\r
441  */\r
442 extern void RTC_ClearSCCR( Rtc* pRtc, uint32_t dwMask )\r
443 {\r
444     /* Clear all flag bits in status clear command register */\r
445     dwMask &= RTC_SCCR_ACKCLR | RTC_SCCR_ALRCLR | RTC_SCCR_SECCLR | RTC_SCCR_TIMCLR | RTC_SCCR_CALCLR ;\r
446 \r
447     pRtc->RTC_SCCR = dwMask ;\r
448 }\r
449 \r
450 /**\r
451  * \brief Get flag bits of status register in the RTC.\r
452  *\r
453  * \param mask Bits mask of Status Register\r
454  *\r
455  * \return Status register & mask\r
456  */\r
457 extern uint32_t RTC_GetSR( Rtc* pRtc, uint32_t dwMask )\r
458 {\r
459     uint32_t dwEvent ;\r
460 \r
461     dwEvent = pRtc->RTC_SR ;\r
462 \r
463     return (dwEvent & dwMask) ;\r
464 }\r
465 \r
466 #if defined(sam3s8) || defined(sam3sd8)\r
467 /**\r
468  * \brief Select a output source in the RTC.\r
469  *\r
470  * \param dwWaveMode is the RTC output source selection value.\r
471  */\r
472 extern void RTC_SetWaveForm( Rtc* pRtc, uint32_t dwWaveMode )\r
473 {\r
474     uint32_t dwRtcMode;\r
475 \r
476     dwRtcMode = pRtc->RTC_MR & (~RTC_MR_OUT1_Msk);\r
477     pRtc->RTC_MR = dwRtcMode | dwWaveMode;\r
478 }\r
479 #endif\r
480 \r