1 /* ----------------------------------------------------------------------------
\r
2 * SAM Software Package License
\r
3 * ----------------------------------------------------------------------------
\r
4 * Copyright (c) 2011, Atmel Corporation
\r
6 * All rights reserved.
\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
11 * - Redistributions of source code must retain the above copyright notice,
\r
12 * this list of conditions and the disclaimer below.
\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
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
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
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
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
43 * To update date or time, the user has to follow these few steps :
\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
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
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
60 * For more accurate information, please look at the RTC section of the
\r
74 * Implementation of Real Time Clock (RTC) controller.
\r
78 /*----------------------------------------------------------------------------
\r
80 *----------------------------------------------------------------------------*/
\r
87 /*----------------------------------------------------------------------------
\r
88 * Exported functions
\r
89 *----------------------------------------------------------------------------*/
\r
92 * \brief Sets the RTC in either 12 or 24 hour mode.
\r
94 * \param mode Hour mode.
\r
96 extern void RTC_SetHourMode( Rtc* pRtc, uint32_t dwMode )
\r
98 assert((dwMode & 0xFFFFFFFE) == 0);
\r
100 pRtc->RTC_MR = dwMode ;
\r
104 * \brief Gets the RTC mode.
\r
106 * \return Hour mode.
\r
108 extern uint32_t RTC_GetHourMode( Rtc* pRtc )
\r
112 TRACE_DEBUG( "RTC_SetHourMode()\n\r" ) ;
\r
114 dwMode = pRtc->RTC_MR;
\r
115 dwMode &= 0xFFFFFFFE;
\r
121 * \brief Enables the selected interrupt sources of the RTC.
\r
123 * \param sources Interrupt sources to enable.
\r
125 extern void RTC_EnableIt( Rtc* pRtc, uint32_t dwSources )
\r
127 assert((dwSources & (uint32_t)(~0x1F)) == 0);
\r
129 TRACE_DEBUG( "RTC_EnableIt()\n\r" ) ;
\r
131 pRtc->RTC_IER = dwSources ;
\r
135 * \brief Disables the selected interrupt sources of the RTC.
\r
137 * \param sources Interrupt sources to disable.
\r
139 extern void RTC_DisableIt( Rtc* pRtc, uint32_t dwSources )
\r
141 assert((dwSources & (uint32_t)(~0x1F)) == 0);
\r
143 TRACE_DEBUG( "RTC_DisableIt()\n\r" ) ;
\r
145 pRtc->RTC_IDR = dwSources ;
\r
149 * \brief Sets the current time in the RTC.
\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
155 * \param ucHour Current hour in 12 or 24 hour mode.
\r
156 * \param ucMinute Current minute.
\r
157 * \param ucSecond Current second.
\r
159 * \return 0 sucess, 1 fail to set
\r
161 extern int RTC_SetTime( Rtc* pRtc, uint8_t ucHour, uint8_t ucMinute, uint8_t ucSecond )
\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
168 TRACE_DEBUG( "RTC_SetTime(%02d:%02d:%02d)\n\r", ucHour, ucMinute, ucSecond ) ;
\r
170 /* if 12-hour mode, set AMPM bit */
\r
171 if ( (pRtc->RTC_MR & RTC_MR_HRMOD) == RTC_MR_HRMOD )
\r
176 dwTime |= RTC_TIMR_AMPM ;
\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
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
191 dwTime = ucSec_bcd | (ucMin_bcd << 8) | (ucHour_bcd<<16) ;
\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
200 return (int)(pRtc->RTC_VER & RTC_VER_NVTIM) ;
\r
204 * \brief Retrieves the current time as stored in the RTC in several variables.
\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
210 extern void RTC_GetTime( Rtc* pRtc, uint8_t *pucHour, uint8_t *pucMinute, uint8_t *pucSecond )
\r
214 TRACE_DEBUG( "RTC_GetTime()\n\r" ) ;
\r
216 /* Get current RTC time */
\r
217 dwTime = pRtc->RTC_TIMR ;
\r
218 while ( dwTime != pRtc->RTC_TIMR )
\r
220 dwTime = pRtc->RTC_TIMR ;
\r
226 *pucHour = ((dwTime & 0x00300000) >> 20) * 10
\r
227 + ((dwTime & 0x000F0000) >> 16);
\r
229 if ( (dwTime & RTC_TIMR_AMPM) == RTC_TIMR_AMPM )
\r
238 *pucMinute = ((dwTime & 0x00007000) >> 12) * 10
\r
239 + ((dwTime & 0x00000F00) >> 8);
\r
245 *pucSecond = ((dwTime & 0x00000070) >> 4) * 10
\r
246 + (dwTime & 0x0000000F);
\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
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
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
262 * \return 0 success, 1 fail to set
\r
264 extern int RTC_SetTimeAlarm( Rtc* pRtc, uint8_t *pucHour, uint8_t *pucMinute, uint8_t *pucSecond )
\r
266 uint32_t dwAlarm=0 ;
\r
268 TRACE_DEBUG( "RTC_SetTimeAlarm()\n\r" ) ;
\r
273 dwAlarm |= RTC_TIMALR_HOUREN | ((*pucHour / 10) << 20) | ((*pucHour % 10) << 16);
\r
279 dwAlarm |= RTC_TIMALR_MINEN | ((*pucMinute / 10) << 12) | ((*pucMinute % 10) << 8);
\r
285 dwAlarm |= RTC_TIMALR_SECEN | ((*pucSecond / 10) << 4) | (*pucSecond % 10);
\r
288 pRtc->RTC_TIMALR = dwAlarm ;
\r
290 return (int)(pRtc->RTC_VER & RTC_VER_NVTIMALR) ;
\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
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
302 extern void RTC_GetDate( Rtc* pRtc, uint16_t *pwYear, uint8_t *pucMonth, uint8_t *pucDay, uint8_t *pucWeek )
\r
306 /* Get current date (multiple reads are necessary to insure a stable value) */
\r
309 dwDate = pRtc->RTC_CALR ;
\r
311 while ( dwDate != pRtc->RTC_CALR ) ;
\r
313 /* Retrieve year */
\r
316 *pwYear = (((dwDate >> 4) & 0x7) * 1000)
\r
317 + ((dwDate & 0xF) * 100)
\r
318 + (((dwDate >> 12) & 0xF) * 10)
\r
319 + ((dwDate >> 8) & 0xF);
\r
322 /* Retrieve month */
\r
325 *pucMonth = (((dwDate >> 20) & 1) * 10) + ((dwDate >> 16) & 0xF);
\r
331 *pucDay = (((dwDate >> 28) & 0x3) * 10) + ((dwDate >> 24) & 0xF);
\r
334 /* Retrieve week */
\r
337 *pucWeek = ((dwDate >> 21) & 0x7);
\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
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
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
354 * \return 0 success, 1 fail to set
\r
356 extern int RTC_SetDate( Rtc* pRtc, uint16_t wYear, uint8_t ucMonth, uint8_t ucDay, uint8_t ucWeek )
\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
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
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
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
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
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
399 return (int)(pRtc->RTC_VER & RTC_VER_NVCAL) ;
\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
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
410 * \return 0 success, 1 fail to set
\r
412 extern int RTC_SetDateAlarm( Rtc* pRtc, uint8_t *pucMonth, uint8_t *pucDay )
\r
416 dwAlarm = ((pucMonth) || (pucDay)) ? (0) : (0x01010000);
\r
418 TRACE_DEBUG( "RTC_SetDateAlarm()\n\r" ) ;
\r
420 /* Compute alarm field value */
\r
423 dwAlarm |= RTC_CALALR_MTHEN | ((*pucMonth / 10) << 20) | ((*pucMonth % 10) << 16);
\r
428 dwAlarm |= RTC_CALALR_DATEEN | ((*pucDay / 10) << 28) | ((*pucDay % 10) << 24);
\r
432 pRtc->RTC_CALALR = dwAlarm ;
\r
434 return (int)(pRtc->RTC_VER & RTC_VER_NVCALALR) ;
\r
438 * \brief Clear flag bits of status clear command register in the RTC.
\r
440 * \param mask Bits mask of cleared events
\r
442 extern void RTC_ClearSCCR( Rtc* pRtc, uint32_t dwMask )
\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
447 pRtc->RTC_SCCR = dwMask ;
\r
451 * \brief Get flag bits of status register in the RTC.
\r
453 * \param mask Bits mask of Status Register
\r
455 * \return Status register & mask
\r
457 extern uint32_t RTC_GetSR( Rtc* pRtc, uint32_t dwMask )
\r
461 dwEvent = pRtc->RTC_SR ;
\r
463 return (dwEvent & dwMask) ;
\r
466 #if defined(sam3s8) || defined(sam3sd8)
\r
468 * \brief Select a output source in the RTC.
\r
470 * \param dwWaveMode is the RTC output source selection value.
\r
472 extern void RTC_SetWaveForm( Rtc* pRtc, uint32_t dwWaveMode )
\r
474 uint32_t dwRtcMode;
\r
476 dwRtcMode = pRtc->RTC_MR & (~RTC_MR_OUT1_Msk);
\r
477 pRtc->RTC_MR = dwRtcMode | dwWaveMode;
\r