SAM3S8/SD8 Software Package: libraries/libchip_sam3s/source/rtc.c Source File

SAM3S8/SD8 Software Package 1.2

# rtc.c

Go to the documentation of this file.

    00001 /* ----------------------------------------------------------------------------
    00002  *         ATMEL Microcontroller Software Support
    00003  * ----------------------------------------------------------------------------
    00004  * Copyright (c) 2009, 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 occurence 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 the user is automatically done.
    00058  * Errors are reported through the Valid Entry Register.
    00059  *
    00060  * For more accurate information, please look at the RTC section of the
    00061  * Datasheet.
    00062  *
    00063  * Related files :\n
    00064  * \ref rtc.c\n
    00065  * \ref rtc.h.\n
    00066 */
    00067 /*@{*/
    00068 /*@}*/
    00069
    00070
    00071 /**
    00072  * \file
    00073  *
    00074  * Implementation of Real Time Clock (RTC) controller.
    00075  *
    00076  */
    00077
    00078 /*----------------------------------------------------------------------------
    00079  *        Headers
    00080  *----------------------------------------------------------------------------*/
    00081
    00082 #include "chip.h"
    00083
    00084 #include <stdint.h>
    00085 #include <assert.h>
    00086
    00087 /*----------------------------------------------------------------------------
    00088  *        Exported functions
    00089  *----------------------------------------------------------------------------*/
    00090
    00091 /**
    00092  * \brief Sets the RTC in either 12 or 24 hour mode.
    00093  *
    00094  * \param mode  Hour mode.
    00095  */
    00096 extern void RTC_SetHourMode( Rtc* pRtc, uint32_t dwMode )
    00097 {
    00098     assert((dwMode & 0xFFFFFFFE) == 0);
    00099
    00100     pRtc->RTC_MR = dwMode ;
    00101 }
    00102
    00103 /**
    00104  * \brief Gets the RTC mode.
    00105  *
    00106  * \return Hour mode.
    00107  */
    00108 extern uint32_t RTC_GetHourMode( Rtc* pRtc )
    00109 {
    00110     uint32_t dwMode ;
    00111
    00112     TRACE_DEBUG( "RTC_SetHourMode()\n\r" ) ;
    00113
    00114     dwMode = pRtc->RTC_MR;
    00115     dwMode &= 0xFFFFFFFE;
    00116
    00117     return dwMode ;
    00118 }
    00119
    00120 /**
    00121  * \brief Enables the selected interrupt sources of the RTC.
    00122  *
    00123  * \param sources  Interrupt sources to enable.
    00124  */
    00125 extern void RTC_EnableIt( Rtc* pRtc, uint32_t dwSources )
    00126 {
    00127     assert((dwSources & (uint32_t)(~0x1F)) == 0);
    00128
    00129     TRACE_DEBUG( "RTC_EnableIt()\n\r" ) ;
    00130
    00131     pRtc->RTC_IER = dwSources ;
    00132 }
    00133
    00134 /**
    00135 * \brief Disables the selected interrupt sources of the RTC.
    00136 *
    00137 * \param sources  Interrupt sources to disable.
    00138 */
    00139 extern void RTC_DisableIt( Rtc* pRtc, uint32_t dwSources )
    00140 {
    00141     assert((dwSources & (uint32_t)(~0x1F)) == 0);
    00142
    00143     TRACE_DEBUG( "RTC_DisableIt()\n\r" ) ;
    00144
    00145     pRtc->RTC_IDR = dwSources ;
    00146 }
    00147
    00148 /**
    00149  * \brief Sets the current time in the RTC.
    00150  *
    00151  * \note In successive update operations, the user must wait at least one second
    00152  * after resetting the UPDTIM/UPDCAL bit in the RTC_CR before setting these
    00153  * bits again. Please look at the RTC section of the datasheet for detail.
    00154  *
    00155  * \param ucHour    Current hour in 12 or 24 hour mode.
    00156  * \param ucMinute  Current minute.
    00157  * \param ucSecond  Current second.
    00158  *
    00159  * \return 0 sucess, 1 fail to set
    00160  */
    00161 extern int RTC_SetTime( Rtc* pRtc, uint8_t ucHour, uint8_t ucMinute, uint8_t ucSecond )
    00162 {
    00163     uint32_t dwTime=0 ;
    00164     uint8_t ucHour_bcd ;
    00165     uint8_t ucMin_bcd ;
    00166     uint8_t ucSec_bcd ;
    00167
    00168     TRACE_DEBUG( "RTC_SetTime(%02d:%02d:%02d)\n\r", ucHour, ucMinute, ucSecond ) ;
    00169
    00170     /* if 12-hour mode, set AMPM bit */
    00171     if ( (pRtc->RTC_MR & RTC_MR_HRMOD) == RTC_MR_HRMOD )
    00172     {
    00173         if ( ucHour > 12 )
    00174         {
    00175             ucHour -= 12 ;
    00176             dwTime |= RTC_TIMR_AMPM ;
    00177         }
    00178     }
    00179     ucHour_bcd = (ucHour%10)   | ((ucHour/10)<<4) ;
    00180     ucMin_bcd  = (ucMinute%10) | ((ucMinute/10)<<4) ;
    00181     ucSec_bcd  = (ucSecond%10) | ((ucSecond/10)<<4) ;
    00182
    00183     /* value overflow */
    00184     if ( (ucHour_bcd & (uint8_t)(~RTC_HOUR_BIT_LEN_MASK)) |
    00185          (ucMin_bcd & (uint8_t)(~RTC_MIN_BIT_LEN_MASK)) |
    00186          (ucSec_bcd & (uint8_t)(~RTC_SEC_BIT_LEN_MASK)))
    00187     {
    00188         return 1 ;
    00189     }
    00190
    00191     dwTime = ucSec_bcd | (ucMin_bcd << 8) | (ucHour_bcd<<16) ;
    00192
    00193     pRtc->RTC_CR |= RTC_CR_UPDTIM ;
    00194     while ((pRtc->RTC_SR & RTC_SR_ACKUPD) != RTC_SR_ACKUPD) ;
    00195     pRtc->RTC_SCCR = RTC_SCCR_ACKCLR ;
    00196     pRtc->RTC_TIMR = dwTime ;
    00197     pRtc->RTC_CR &= (uint32_t)(~RTC_CR_UPDTIM) ;
    00198     pRtc->RTC_SCCR |= RTC_SCCR_SECCLR ;
    00199
    00200     return (int)(pRtc->RTC_VER & RTC_VER_NVTIM) ;
    00201 }
    00202
    00203 /**
    00204  * \brief Retrieves the current time as stored in the RTC in several variables.
    00205  *
    00206  * \param pucHour    If not null, current hour is stored in this variable.
    00207  * \param pucMinute  If not null, current minute is stored in this variable.
    00208  * \param pucSecond  If not null, current second is stored in this variable.
    00209  */
    00210 extern void RTC_GetTime( Rtc* pRtc, uint8_t *pucHour, uint8_t *pucMinute, uint8_t *pucSecond )
    00211 {
    00212     uint32_t dwTime ;
    00213
    00214     TRACE_DEBUG( "RTC_GetTime()\n\r" ) ;
    00215
    00216     /* Get current RTC time */
    00217     dwTime = pRtc->RTC_TIMR ;
    00218     while ( dwTime != pRtc->RTC_TIMR )
    00219     {
    00220         dwTime = pRtc->RTC_TIMR ;
    00221     }
    00222
    00223     /* Hour */
    00224     if ( pucHour )
    00225     {
    00226         *pucHour = ((dwTime & 0x00300000) >> 20) * 10
    00227                  + ((dwTime & 0x000F0000) >> 16);
    00228
    00229         if ( (dwTime & RTC_TIMR_AMPM) == RTC_TIMR_AMPM )
    00230         {
    00231             *pucHour += 12 ;
    00232         }
    00233     }
    00234
    00235     /* Minute */
    00236     if ( pucMinute )
    00237     {
    00238         *pucMinute = ((dwTime & 0x00007000) >> 12) * 10
    00239                    + ((dwTime & 0x00000F00) >> 8);
    00240     }
    00241
    00242     /* Second */
    00243     if ( pucSecond )
    00244     {
    00245         *pucSecond = ((dwTime & 0x00000070) >> 4) * 10
    00246                    + (dwTime & 0x0000000F);
    00247     }
    00248 }
    00249
    00250 /**
    00251  * \brief Sets a time alarm on the RTC.
    00252  * The match is performed only on the provided variables;
    00253  * Setting all pointers to 0 disables the time alarm.
    00254  *
    00255  * \note In AM/PM mode, the hour value must have bit #7 set for PM, cleared for
    00256  * AM (as expected in the time registers).
    00257  *
    00258  * \param pucHour    If not null, the time alarm will hour-match this value.
    00259  * \param pucMinute  If not null, the time alarm will minute-match this value.
    00260  * \param pucSecond  If not null, the time alarm will second-match this value.
    00261  *
    00262  * \return 0 success, 1 fail to set
    00263  */
    00264 extern int RTC_SetTimeAlarm( Rtc* pRtc, uint8_t *pucHour, uint8_t *pucMinute, uint8_t *pucSecond )
    00265 {
    00266     uint32_t dwAlarm=0 ;
    00267
    00268     TRACE_DEBUG( "RTC_SetTimeAlarm()\n\r" ) ;
    00269
    00270     /* Hour */
    00271     if ( pucHour )
    00272     {
    00273         dwAlarm |= RTC_TIMALR_HOUREN | ((*pucHour / 10) << 20) | ((*pucHour % 10) << 16);
    00274     }
    00275
    00276     /* Minute */
    00277     if ( pucMinute )
    00278     {
    00279         dwAlarm |= RTC_TIMALR_MINEN | ((*pucMinute / 10) << 12) | ((*pucMinute % 10) << 8);
    00280     }
    00281
    00282     /* Second */
    00283     if ( pucSecond )
    00284     {
    00285         dwAlarm |= RTC_TIMALR_SECEN | ((*pucSecond / 10) << 4) | (*pucSecond % 10);
    00286     }
    00287
    00288     pRtc->RTC_TIMALR = dwAlarm ;
    00289
    00290     return (int)(pRtc->RTC_VER & RTC_VER_NVTIMALR) ;
    00291 }
    00292
    00293 /**
    00294  * \brief Retrieves the current year, month and day from the RTC.
    00295  * Month, day and week values are numbered starting at 1.
    00296  *
    00297  * \param pYwear  Current year (optional).
    00298  * \param pucMonth  Current month (optional).
    00299  * \param pucDay  Current day (optional).
    00300  * \param pucWeek  Current day in current week (optional).
    00301  */
    00302 extern void RTC_GetDate( Rtc* pRtc, uint16_t *pwYear, uint8_t *pucMonth, uint8_t *pucDay, uint8_t *pucWeek )
    00303 {
    00304     uint32_t dwDate ;
    00305
    00306     /* Get current date (multiple reads are necessary to insure a stable value) */
    00307     do
    00308     {
    00309         dwDate = pRtc->RTC_CALR ;
    00310     }
    00311     while ( dwDate != pRtc->RTC_CALR ) ;
    00312
    00313     /* Retrieve year */
    00314     if ( pwYear )
    00315     {
    00316         *pwYear = (((dwDate  >> 4) & 0x7) * 1000)
    00317                  + ((dwDate & 0xF) * 100)
    00318                  + (((dwDate >> 12) & 0xF) * 10)
    00319                  + ((dwDate >> 8) & 0xF);
    00320     }
    00321
    00322     /* Retrieve month */
    00323     if ( pucMonth )
    00324     {
    00325         *pucMonth = (((dwDate >> 20) & 1) * 10) + ((dwDate >> 16) & 0xF);
    00326     }
    00327
    00328     /* Retrieve day */
    00329     if ( pucDay )
    00330     {
    00331         *pucDay = (((dwDate >> 28) & 0x3) * 10) + ((dwDate >> 24) & 0xF);
    00332     }
    00333
    00334     /* Retrieve week */
    00335     if ( pucWeek )
    00336     {
    00337         *pucWeek = ((dwDate >> 21) & 0x7);
    00338     }
    00339 }
    00340
    00341 /**
    00342  * \brief Sets the current year, month and day in the RTC.
    00343  * Month, day and week values must be numbered starting from 1.
    00344  *
    00345  * \note In successive update operations, the user must wait at least one second
    00346  * after resetting the UPDTIM/UPDCAL bit in the RTC_CR before setting these
    00347  * bits again. Please look at the RTC section of the datasheet for detail.
    00348  *
    00349  * \param wYear  Current year.
    00350  * \param ucMonth Current month.
    00351  * \param ucDay   Current day.
    00352  * \param ucWeek  Day number in current week.
    00353  *
    00354  * \return 0 success, 1 fail to set
    00355  */
    00356 extern int RTC_SetDate( Rtc* pRtc, uint16_t wYear, uint8_t ucMonth, uint8_t ucDay, uint8_t ucWeek )
    00357 {
    00358     uint32_t wDate ;
    00359     uint8_t ucCent_bcd ;
    00360     uint8_t ucYear_bcd ;
    00361     uint8_t ucMonth_bcd ;
    00362     uint8_t ucDay_bcd ;
    00363     uint8_t ucWeek_bcd ;
    00364
    00365     ucCent_bcd  = ((wYear/100)%10) | ((wYear/1000)<<4);
    00366     ucYear_bcd  = (wYear%10) | (((wYear/10)%10)<<4);
    00367     ucMonth_bcd = ((ucMonth%10) | (ucMonth/10)<<4);
    00368     ucDay_bcd   = ((ucDay%10) | (ucDay/10)<<4);
    00369     ucWeek_bcd  = ((ucWeek%10) | (ucWeek/10)<<4);
    00370
    00371     /* value over flow */
    00372     if ( (ucCent_bcd & (uint8_t)(~RTC_CENT_BIT_LEN_MASK)) |
    00373          (ucYear_bcd & (uint8_t)(~RTC_YEAR_BIT_LEN_MASK)) |
    00374          (ucMonth_bcd & (uint8_t)(~RTC_MONTH_BIT_LEN_MASK)) |
    00375          (ucWeek_bcd & (uint8_t)(~RTC_WEEK_BIT_LEN_MASK)) |
    00376          (ucDay_bcd & (uint8_t)(~RTC_DATE_BIT_LEN_MASK))
    00377        )
    00378     {
    00379         return 1 ;
    00380     }
    00381
    00382
    00383     /* Convert values to date register value */
    00384     wDate = ucCent_bcd |
    00385             (ucYear_bcd << 8) |
    00386             (ucMonth_bcd << 16) |
    00387             (ucWeek_bcd << 21) |
    00388             (ucDay_bcd << 24);
    00389
    00390     /* Update calendar register  */
    00391     pRtc->RTC_CR |= RTC_CR_UPDCAL ;
    00392     while ((pRtc->RTC_SR & RTC_SR_ACKUPD) != RTC_SR_ACKUPD) ;
    00393
    00394     pRtc->RTC_SCCR = RTC_SCCR_ACKCLR;
    00395     pRtc->RTC_CALR = wDate ;
    00396     pRtc->RTC_CR &= (uint32_t)(~RTC_CR_UPDCAL) ;
    00397     pRtc->RTC_SCCR |= RTC_SCCR_SECCLR; /* clear SECENV in SCCR */
    00398
    00399     return (int)(pRtc->RTC_VER & RTC_VER_NVCAL) ;
    00400 }
    00401
    00402 /**
    00403  * \brief Sets a date alarm in the RTC.
    00404  * The alarm will match only the provided values;
    00405  * Passing a null-pointer disables the corresponding field match.
    00406  *
    00407  * \param pucMonth If not null, the RTC alarm will month-match this value.
    00408  * \param pucDay   If not null, the RTC alarm will day-match this value.
    00409  *
    00410  * \return 0 success, 1 fail to set
    00411  */
    00412 extern int RTC_SetDateAlarm( Rtc* pRtc, uint8_t *pucMonth, uint8_t *pucDay )
    00413 {
    00414     uint32_t dwAlarm ;
    00415
    00416     dwAlarm = ((pucMonth) || (pucDay)) ? (0) : (0x01010000);
    00417
    00418     TRACE_DEBUG( "RTC_SetDateAlarm()\n\r" ) ;
    00419
    00420     /* Compute alarm field value */
    00421     if ( pucMonth )
    00422     {
    00423         dwAlarm |= RTC_CALALR_MTHEN | ((*pucMonth / 10) << 20) | ((*pucMonth % 10) << 16);
    00424     }
    00425
    00426     if ( pucDay )
    00427     {
    00428         dwAlarm |= RTC_CALALR_DATEEN | ((*pucDay / 10) << 28) | ((*pucDay % 10) << 24);
    00429     }
    00430
    00431     /* Set alarm */
    00432     pRtc->RTC_CALALR = dwAlarm ;
    00433
    00434     return (int)(pRtc->RTC_VER & RTC_VER_NVCALALR) ;
    00435 }
    00436
    00437 /**
    00438  * \brief Clear flag bits of status clear command register in the RTC.
    00439  *
    00440  * \param mask Bits mask of cleared events
    00441  */
    00442 extern void RTC_ClearSCCR( Rtc* pRtc, uint32_t dwMask )
    00443 {
    00444     /* Clear all flag bits in status clear command register */
    00445     dwMask &= RTC_SCCR_ACKCLR | RTC_SCCR_ALRCLR | RTC_SCCR_SECCLR | RTC_SCCR_TIMCLR | RTC_SCCR_CALCLR ;
    00446
    00447     pRtc->RTC_SCCR = dwMask ;
    00448 }
    00449
    00450 /**
    00451  * \brief Get flag bits of status register in the RTC.
    00452  *
    00453  * \param mask Bits mask of Status Register
    00454  *
    00455  * \return Status register & mask
    00456  */
    00457 extern uint32_t RTC_GetSR( Rtc* pRtc, uint32_t dwMask )
    00458 {
    00459     uint32_t dwEvent ;
    00460
    00461     dwEvent = pRtc->RTC_SR ;
    00462
    00463     return (dwEvent & dwMask) ;
    00464 }
    00465
    00466 #if defined(sam3s8) || defined(sam3sd8)
    00467 /**
    00468  * \brief Select a output source in the RTC.
    00469  *
    00470  * \param dwWaveMode is the RTC output source selection value.
    00471  */
    00472 extern void RTC_SetWaveForm( Rtc* pRtc, uint32_t dwWaveMode )
    00473 {
    00474     uint32_t dwRtcMode;
    00475
    00476     dwRtcMode = pRtc->RTC_MR & (~RTC_MR_OUT1_Msk);
    00477     pRtc->RTC_MR = dwRtcMode | dwWaveMode;
    00478 }
    00479 #endif
    00480

All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines