SAMV71 Xplained Ultra Software Package 1.4

rtc.c

Go to the documentation of this file.
00001 /* ----------------------------------------------------------------------------
00002  *         SAM Software Package License
00003  * ----------------------------------------------------------------------------
00004  * Copyright (c) 2011, Atmel Corporation
00005  *
00006  * All rights reserved.
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted provided that the following conditions are met:
00010  *
00011  * - Redistributions of source code must retain the above copyright notice,
00012  * this list of conditions and the disclaimer below.
00013  *
00014  * Atmel's name may not be used to endorse or promote products derived from
00015  * this software without specific prior written permission.
00016  *
00017  * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
00018  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
00019  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
00020  * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
00021  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
00022  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
00023  * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00024  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00025  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
00026  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00027  * ----------------------------------------------------------------------------
00028  */
00029 
00030 /** \addtogroup rtc_module Working with RTC
00031  *  \ingroup peripherals_module
00032  * The RTC driver provides the interface to configure and use the RTC
00033  * peripheral.
00034  *
00035  * It manages date, time, and alarms.\n
00036  * This timer is clocked by the 32kHz system clock, and is not impacted by
00037  * power management settings (PMC). To be accurate, it is better to use an
00038  * external 32kHz crystal instead of the internal 32kHz RC.\n
00039  *
00040  * It uses BCD format, and time can be set in AM/PM or 24h mode through a
00041  * configuration bit in the mode register.\n
00042  *
00043  * To update date or time, the user has to follow these few steps :
00044  * <ul>
00045  * <li>Set UPDTIM and/or UPDCAL bit(s) in RTC_CR,</li>
00046  * <li>Polling or IRQ on the ACKUPD bit of RTC_CR,</li>
00047  * <li>Clear ACKUPD bit in RTC_SCCR,</li>
00048  * <li>Update Time and/or Calendar values in RTC_TIMR/RTC_CALR (BCD format),</li>
00049  * <li>Clear UPDTIM and/or UPDCAL bit in RTC_CR.</li>
00050  * </ul>
00051  * An alarm can be set to happen on month, date, hours, minutes or seconds,
00052  * by setting the proper "Enable" bit of each of these fields in the Time and
00053  * Calendar registers.
00054  * This allows a large number of configurations to be available for the user.
00055  * Alarm occurrence can be detected even by polling or interrupt.
00056  *
00057  * A check of the validity of the date and time format and values written by 
00058  * the user is automatically done.
00059  * Errors are reported through the Valid Entry Register.
00060  *
00061  * For more accurate information, please look at the RTC section of the
00062  * Datasheet.
00063  *
00064  * Related files :\n
00065  * \ref rtc.c\n
00066  * \ref rtc.h.\n
00067  */
00068 /*@{*/
00069 /*@}*/
00070 
00071 
00072 /**
00073  * \file
00074  *
00075  * Implementation of Real Time Clock (RTC) controller.
00076  *
00077  */
00078 
00079 /*----------------------------------------------------------------------------
00080  *        Headers
00081  *----------------------------------------------------------------------------*/
00082 
00083 #include "chip.h"
00084 
00085 #include <stdint.h>
00086 #include <assert.h>
00087 
00088 /*----------------------------------------------------------------------------
00089  *        Exported functions
00090  *----------------------------------------------------------------------------*/
00091 
00092 /**
00093  * \brief Sets the RTC in either 12 or 24 hour mode.
00094  *
00095  * \param mode  Hour mode.
00096  */
00097 extern void RTC_SetHourMode( Rtc* pRtc, uint32_t dwMode )
00098 {
00099     assert((dwMode & 0xFFFFFFFE) == 0);
00100 
00101     pRtc->RTC_MR = dwMode ;
00102 }
00103 
00104 /**
00105  * \brief Gets the RTC mode.
00106  *
00107  * \return Hour mode.
00108  */
00109 extern uint32_t RTC_GetHourMode( Rtc* pRtc )
00110 {
00111     uint32_t dwMode ;
00112 
00113     TRACE_DEBUG( "RTC_SetHourMode()\n\r" ) ;
00114 
00115     dwMode = pRtc->RTC_MR;
00116     dwMode &= 0xFFFFFFFE;
00117 
00118     return dwMode ;
00119 }
00120 
00121 /**
00122  * \brief Enables the selected interrupt sources of the RTC.
00123  *
00124  * \param sources  Interrupt sources to enable.
00125  */
00126 extern void RTC_EnableIt( Rtc* pRtc, uint32_t dwSources )
00127 {
00128     assert((dwSources & (uint32_t)(~0x1F)) == 0);
00129 
00130     TRACE_DEBUG( "RTC_EnableIt()\n\r" ) ;
00131 
00132     pRtc->RTC_IER = dwSources ;
00133 }
00134 
00135 /**
00136  * \brief Disables the selected interrupt sources of the RTC.
00137  *
00138  * \param sources  Interrupt sources to disable.
00139  */
00140 extern void RTC_DisableIt( Rtc* pRtc, uint32_t dwSources )
00141 {
00142     assert((dwSources & (uint32_t)(~0x1F)) == 0);
00143 
00144     TRACE_DEBUG( "RTC_DisableIt()\n\r" ) ;
00145 
00146     pRtc->RTC_IDR = dwSources ;
00147 }
00148 
00149 /**
00150  * \brief Sets the current time in the RTC.
00151  *
00152  * \note In successive update operations, the user must wait at least one second
00153  * after resetting the UPDTIM/UPDCAL bit in the RTC_CR before setting these
00154  * bits again. Please look at the RTC section of the datasheet for detail.
00155  *
00156  * \param ucHour    Current hour in 12 or 24 hour mode.
00157  * \param ucMinute  Current minute.
00158  * \param ucSecond  Current second.
00159  *
00160  * \return 0 success, 1 fail to set
00161  */
00162 extern int RTC_SetTime( Rtc* pRtc, uint8_t ucHour, uint8_t ucMinute, uint8_t ucSecond )
00163 {
00164     uint32_t dwTime=0 ;
00165     uint8_t ucHour_bcd ;
00166     uint8_t ucMin_bcd ;
00167     uint8_t ucSec_bcd ;
00168 
00169     TRACE_DEBUG( "RTC_SetTime(%02d:%02d:%02d)\n\r", ucHour, ucMinute, ucSecond ) ;
00170 
00171     /* if 12-hour mode, set AMPM bit */
00172     if ( (pRtc->RTC_MR & RTC_MR_HRMOD) == RTC_MR_HRMOD ) {
00173         if ( ucHour > 12 ) {
00174             ucHour -= 12 ;
00175             dwTime |= RTC_TIMR_AMPM ;
00176         }
00177     }
00178     ucHour_bcd = (ucHour%10)   | ((ucHour/10)<<4) ;
00179     ucMin_bcd  = (ucMinute%10) | ((ucMinute/10)<<4) ;
00180     ucSec_bcd  = (ucSecond%10) | ((ucSecond/10)<<4) ;
00181 
00182     /* value overflow */
00183     if ( (ucHour_bcd & (uint8_t)(~RTC_HOUR_BIT_LEN_MASK)) |
00184             (ucMin_bcd & (uint8_t)(~RTC_MIN_BIT_LEN_MASK)) |
00185             (ucSec_bcd & (uint8_t)(~RTC_SEC_BIT_LEN_MASK))) {
00186         return 1 ;
00187     }
00188 
00189     dwTime = ucSec_bcd | (ucMin_bcd << 8) | (ucHour_bcd<<16) ;
00190 
00191     pRtc->RTC_CR |= RTC_CR_UPDTIM ;
00192     while ((pRtc->RTC_SR & RTC_SR_ACKUPD) != RTC_SR_ACKUPD) ;
00193     pRtc->RTC_SCCR = RTC_SCCR_ACKCLR ;
00194     pRtc->RTC_TIMR = dwTime ;
00195     pRtc->RTC_CR &= (uint32_t)(~RTC_CR_UPDTIM) ;
00196     pRtc->RTC_SCCR |= RTC_SCCR_SECCLR ;
00197 
00198     return (int)(pRtc->RTC_VER & RTC_VER_NVTIM) ;
00199 }
00200 
00201 /**
00202  * \brief Retrieves the current time as stored in the RTC in several variables.
00203  *
00204  * \param pucHour    If not null, current hour is stored in this variable.
00205  * \param pucMinute  If not null, current minute is stored in this variable.
00206  * \param pucSecond  If not null, current second is stored in this variable.
00207  */
00208 extern void RTC_GetTime( Rtc* pRtc, uint8_t *pucHour, 
00209                 uint8_t *pucMinute, uint8_t *pucSecond )
00210 {
00211     uint32_t dwTime ;
00212 
00213     TRACE_DEBUG( "RTC_GetTime()\n\r" ) ;
00214 
00215     /* Get current RTC time */
00216     dwTime = pRtc->RTC_TIMR ;
00217     while ( dwTime != pRtc->RTC_TIMR ) {
00218         dwTime = pRtc->RTC_TIMR ;
00219     }
00220 
00221     /* Hour */
00222     if ( pucHour ) {
00223         *pucHour = ((dwTime & 0x00300000) >> 20) * 10
00224             + ((dwTime & 0x000F0000) >> 16);
00225 
00226         if ( (dwTime & RTC_TIMR_AMPM) == RTC_TIMR_AMPM ) {
00227             *pucHour += 12 ;
00228         }
00229     }
00230 
00231     /* Minute */
00232     if ( pucMinute ) {
00233         *pucMinute = ((dwTime & 0x00007000) >> 12) * 10
00234             + ((dwTime & 0x00000F00) >> 8);
00235     }
00236 
00237     /* Second */
00238     if ( pucSecond ) {
00239         *pucSecond = ((dwTime & 0x00000070) >> 4) * 10
00240             + (dwTime & 0x0000000F);
00241     }
00242 }
00243 
00244 /**
00245  * \brief Sets a time alarm on the RTC.
00246  * The match is performed only on the provided variables;
00247  * Setting all pointers to 0 disables the time alarm.
00248  *
00249  * \note In AM/PM mode, the hour value must have bit #7 set for PM, cleared for
00250  * AM (as expected in the time registers).
00251  *
00252  * \param pucHour    If not null, the time alarm will hour-match this value.
00253  * \param pucMinute  If not null, the time alarm will minute-match this value.
00254  * \param pucSecond  If not null, the time alarm will second-match this value.
00255  *
00256  * \return 0 success, 1 fail to set
00257  */
00258 extern int RTC_SetTimeAlarm( Rtc* pRtc, uint8_t *pucHour, 
00259                 uint8_t *pucMinute, uint8_t *pucSecond )
00260 {
00261     uint32_t dwAlarm=0 ;
00262 
00263     TRACE_DEBUG( "RTC_SetTimeAlarm()\n\r" ) ;
00264 
00265     /* Hour */
00266     if ( pucHour ) {
00267         dwAlarm |= RTC_TIMALR_HOUREN | ((*pucHour / 10) << 20) | ((*pucHour % 10) << 16);
00268     }
00269 
00270     /* Minute */
00271     if ( pucMinute ) {
00272         dwAlarm |= RTC_TIMALR_MINEN | ((*pucMinute / 10) << 12) 
00273                 | ((*pucMinute % 10) << 8);
00274     }
00275 
00276     /* Second */
00277     if ( pucSecond ) {
00278         dwAlarm |= RTC_TIMALR_SECEN | ((*pucSecond / 10) << 4) | (*pucSecond % 10);
00279     }
00280 
00281     pRtc->RTC_TIMALR = dwAlarm ;
00282 
00283     return (int)(pRtc->RTC_VER & RTC_VER_NVTIMALR) ;
00284 }
00285 
00286 /**
00287  * \brief Retrieves the current year, month and day from the RTC.
00288  * Month, day and week values are numbered starting at 1.
00289  *
00290  * \param pYwear  Current year (optional).
00291  * \param pucMonth  Current month (optional).
00292  * \param pucDay  Current day (optional).
00293  * \param pucWeek  Current day in current week (optional).
00294  */
00295 extern void RTC_GetDate( Rtc* pRtc, uint16_t *pwYear, uint8_t *pucMonth,
00296                 uint8_t *pucDay, uint8_t *pucWeek )
00297 {
00298     uint32_t dwDate ;
00299 
00300     /* Get current date (multiple reads are necessary to insure a stable value) */
00301     do {
00302         dwDate = pRtc->RTC_CALR ;
00303     }
00304     while ( dwDate != pRtc->RTC_CALR ) ;
00305 
00306     /* Retrieve year */
00307     if ( pwYear ) {
00308         *pwYear = (((dwDate  >> 4) & 0x7) * 1000)
00309             + ((dwDate & 0xF) * 100)
00310             + (((dwDate >> 12) & 0xF) * 10)
00311             + ((dwDate >> 8) & 0xF);
00312     }
00313 
00314     /* Retrieve month */
00315     if ( pucMonth ) {
00316         *pucMonth = (((dwDate >> 20) & 1) * 10) + ((dwDate >> 16) & 0xF);
00317     }
00318 
00319     /* Retrieve day */
00320     if ( pucDay ) {
00321         *pucDay = (((dwDate >> 28) & 0x3) * 10) + ((dwDate >> 24) & 0xF);
00322     }
00323 
00324     /* Retrieve week */
00325     if ( pucWeek ) {
00326         *pucWeek = ((dwDate >> 21) & 0x7);
00327     }
00328 }
00329 
00330 /**
00331  * \brief Sets the current year, month and day in the RTC.
00332  * Month, day and week values must be numbered starting from 1.
00333  *
00334  * \note In successive update operations, the user must wait at least one second
00335  * after resetting the UPDTIM/UPDCAL bit in the RTC_CR before setting these
00336  * bits again. Please look at the RTC section of the datasheet for detail.
00337  *
00338  * \param wYear  Current year.
00339  * \param ucMonth Current month.
00340  * \param ucDay   Current day.
00341  * \param ucWeek  Day number in current week.
00342  *
00343  * \return 0 success, 1 fail to set
00344  */
00345 extern int RTC_SetDate( Rtc* pRtc, uint16_t wYear, uint8_t ucMonth, 
00346                         uint8_t ucDay, uint8_t ucWeek )
00347 {
00348     uint32_t wDate ;
00349     uint8_t ucCent_bcd ;
00350     uint8_t ucYear_bcd ;
00351     uint8_t ucMonth_bcd ;
00352     uint8_t ucDay_bcd ;
00353     uint8_t ucWeek_bcd ;
00354 
00355     ucCent_bcd  = ((wYear/100)%10) | ((wYear/1000)<<4);
00356     ucYear_bcd  = (wYear%10) | (((wYear/10)%10)<<4);
00357     ucMonth_bcd = ((ucMonth%10) | (ucMonth/10)<<4);
00358     ucDay_bcd   = ((ucDay%10) | (ucDay/10)<<4);
00359     ucWeek_bcd  = ((ucWeek%10) | (ucWeek/10)<<4);
00360 
00361     /* value over flow */
00362     if ( (ucCent_bcd & (uint8_t)(~RTC_CENT_BIT_LEN_MASK)) |
00363             (ucYear_bcd & (uint8_t)(~RTC_YEAR_BIT_LEN_MASK)) |
00364             (ucMonth_bcd & (uint8_t)(~RTC_MONTH_BIT_LEN_MASK)) |
00365             (ucWeek_bcd & (uint8_t)(~RTC_WEEK_BIT_LEN_MASK)) |
00366             (ucDay_bcd & (uint8_t)(~RTC_DATE_BIT_LEN_MASK))
00367        ) {
00368         return 1 ;
00369     }
00370 
00371 
00372     /* Convert values to date register value */
00373     wDate = ucCent_bcd |
00374         (ucYear_bcd << 8) |
00375         (ucMonth_bcd << 16) |
00376         (ucWeek_bcd << 21) |
00377         (ucDay_bcd << 24);
00378 
00379     /* Update calendar register  */
00380     pRtc->RTC_CR |= RTC_CR_UPDCAL ;
00381     while ((pRtc->RTC_SR & RTC_SR_ACKUPD) != RTC_SR_ACKUPD) ;
00382 
00383     pRtc->RTC_SCCR = RTC_SCCR_ACKCLR;
00384     pRtc->RTC_CALR = wDate ;
00385     pRtc->RTC_CR &= (uint32_t)(~RTC_CR_UPDCAL) ;
00386     pRtc->RTC_SCCR |= RTC_SCCR_SECCLR; /* clear SECENV in SCCR */
00387 
00388     return (int)(pRtc->RTC_VER & RTC_VER_NVCAL) ;
00389 }
00390 
00391 /**
00392  * \brief Sets a date alarm in the RTC.
00393  * The alarm will match only the provided values;
00394  * Passing a null-pointer disables the corresponding field match.
00395  *
00396  * \param pucMonth If not null, the RTC alarm will month-match this value.
00397  * \param pucDay   If not null, the RTC alarm will day-match this value.
00398  *
00399  * \return 0 success, 1 fail to set
00400  */
00401 extern int RTC_SetDateAlarm( Rtc* pRtc, uint8_t *pucMonth, uint8_t *pucDay )
00402 {
00403     uint32_t dwAlarm ;
00404 
00405     dwAlarm = ((pucMonth) || (pucDay)) ? (0) : (0x01010000);
00406 
00407     TRACE_DEBUG( "RTC_SetDateAlarm()\n\r" ) ;
00408 
00409     /* Compute alarm field value */
00410     if ( pucMonth ) {
00411         dwAlarm |= RTC_CALALR_MTHEN | ((*pucMonth / 10) << 20) 
00412                     | ((*pucMonth % 10) << 16);
00413     }
00414 
00415     if ( pucDay ) {
00416         dwAlarm |= RTC_CALALR_DATEEN | ((*pucDay / 10) << 28) 
00417                     | ((*pucDay % 10) << 24);
00418     }
00419 
00420     /* Set alarm */
00421     pRtc->RTC_CALALR = dwAlarm ;
00422 
00423     return (int)(pRtc->RTC_VER & RTC_VER_NVCALALR) ;
00424 }
00425 
00426 /**
00427  * \brief Clear flag bits of status clear command register in the RTC.
00428  *
00429  * \param mask Bits mask of cleared events
00430  */
00431 extern void RTC_ClearSCCR( Rtc* pRtc, uint32_t dwMask )
00432 {
00433     /* Clear all flag bits in status clear command register */
00434     dwMask &= RTC_SCCR_ACKCLR | RTC_SCCR_ALRCLR | RTC_SCCR_SECCLR 
00435                 | RTC_SCCR_TIMCLR | RTC_SCCR_CALCLR ;
00436 
00437     pRtc->RTC_SCCR = dwMask ;
00438 }
00439 
00440 /**
00441  * \brief Get flag bits of status register in the RTC.
00442  *
00443  * \param mask Bits mask of Status Register
00444  *
00445  * \return Status register & mask
00446  */
00447 extern uint32_t RTC_GetSR( Rtc* pRtc, uint32_t dwMask )
00448 {
00449     uint32_t dwEvent ;
00450 
00451     dwEvent = pRtc->RTC_SR ;
00452 
00453     return (dwEvent & dwMask) ;
00454 }
00455 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines