SAMV71 Xplained Ultra Software Package 1.5

rtc.c

Go to the documentation of this file.
00001 /* ---------------------------------------------------------------------------- */
00002 /*                  Atmel Microcontroller Software Support                      */
00003 /*                       SAM Software Package License                           */
00004 /* ---------------------------------------------------------------------------- */
00005 /* Copyright (c) 2015, Atmel Corporation                                        */
00006 /*                                                                              */
00007 /* All rights reserved.                                                         */
00008 /*                                                                              */
00009 /* Redistribution and use in source and binary forms, with or without           */
00010 /* modification, are permitted provided that the following condition is met:    */
00011 /*                                                                              */
00012 /* - Redistributions of source code must retain the above copyright notice,     */
00013 /* this list of conditions and the disclaimer below.                            */
00014 /*                                                                              */
00015 /* Atmel's name may not be used to endorse or promote products derived from     */
00016 /* this software without specific prior written permission.                     */
00017 /*                                                                              */
00018 /* DISCLAIMER:  THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR   */
00019 /* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF */
00020 /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE   */
00021 /* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,      */
00022 /* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */
00023 /* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,  */
00024 /* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF    */
00025 /* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING         */
00026 /* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, */
00027 /* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.                           */
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,
00163                         uint8_t ucSecond)
00164 {
00165     uint32_t dwTime = 0;
00166     uint8_t ucHour_bcd;
00167     uint8_t ucMin_bcd;
00168     uint8_t ucSec_bcd;
00169 
00170     TRACE_DEBUG("RTC_SetTime(%02d:%02d:%02d)\n\r", ucHour, ucMinute, ucSecond);
00171 
00172     /* if 12-hour mode, set AMPM bit */
00173     if ((pRtc->RTC_MR & RTC_MR_HRMOD) == RTC_MR_HRMOD) {
00174         if (ucHour > 12) {
00175             ucHour -= 12;
00176             dwTime |= RTC_TIMR_AMPM;
00177         }
00178     }
00179 
00180     ucHour_bcd = (ucHour % 10)   | ((ucHour / 10) << 4);
00181     ucMin_bcd  = (ucMinute % 10) | ((ucMinute / 10) << 4);
00182     ucSec_bcd  = (ucSecond % 10) | ((ucSecond / 10) << 4);
00183 
00184     /* value overflow */
00185     if ((ucHour_bcd & (uint8_t)(~RTC_HOUR_BIT_LEN_MASK)) |
00186          (ucMin_bcd & (uint8_t)(~RTC_MIN_BIT_LEN_MASK)) |
00187          (ucSec_bcd & (uint8_t)(~RTC_SEC_BIT_LEN_MASK)))
00188         return 1;
00189 
00190     dwTime = ucSec_bcd | (ucMin_bcd << 8) | (ucHour_bcd << 16);
00191 
00192     pRtc->RTC_CR |= RTC_CR_UPDTIM;
00193 
00194     while ((pRtc->RTC_SR & RTC_SR_ACKUPD) != RTC_SR_ACKUPD);
00195 
00196     pRtc->RTC_SCCR = RTC_SCCR_ACKCLR;
00197     pRtc->RTC_TIMR = dwTime;
00198     pRtc->RTC_CR &= (uint32_t)(~RTC_CR_UPDTIM);
00199     pRtc->RTC_SCCR |= RTC_SCCR_SECCLR;
00200 
00201     return (int)(pRtc->RTC_VER & RTC_VER_NVTIM);
00202 }
00203 
00204 /**
00205  * \brief Retrieves the current time as stored in the RTC in several variables.
00206  *
00207  * \param pucHour    If not null, current hour is stored in this variable.
00208  * \param pucMinute  If not null, current minute is stored in this variable.
00209  * \param pucSecond  If not null, current second is stored in this variable.
00210  */
00211 extern void RTC_GetTime(Rtc *pRtc, uint8_t *pucHour,
00212                          uint8_t *pucMinute, uint8_t *pucSecond)
00213 {
00214     uint32_t dwTime;
00215 
00216     TRACE_DEBUG("RTC_GetTime()\n\r");
00217 
00218     /* Get current RTC time */
00219     dwTime = pRtc->RTC_TIMR;
00220 
00221     while (dwTime != pRtc->RTC_TIMR)
00222         dwTime = pRtc->RTC_TIMR;
00223 
00224     /* Hour */
00225     if (pucHour) {
00226         *pucHour = ((dwTime & 0x00300000) >> 20) * 10
00227                    + ((dwTime & 0x000F0000) >> 16);
00228 
00229         if ((dwTime & RTC_TIMR_AMPM) == RTC_TIMR_AMPM)
00230             *pucHour += 12;
00231     }
00232 
00233     /* Minute */
00234     if (pucMinute) {
00235         *pucMinute = ((dwTime & 0x00007000) >> 12) * 10
00236                      + ((dwTime & 0x00000F00) >> 8);
00237     }
00238 
00239     /* Second */
00240     if (pucSecond) {
00241         *pucSecond = ((dwTime & 0x00000070) >> 4) * 10
00242                      + (dwTime & 0x0000000F);
00243     }
00244 }
00245 
00246 /**
00247  * \brief Sets a time alarm on the RTC.
00248  * The match is performed only on the provided variables;
00249  * Setting all pointers to 0 disables the time alarm.
00250  *
00251  * \note In AM/PM mode, the hour value must have bit #7 set for PM, cleared for
00252  * AM (as expected in the time registers).
00253  *
00254  * \param pucHour    If not null, the time alarm will hour-match this value.
00255  * \param pucMinute  If not null, the time alarm will minute-match this value.
00256  * \param pucSecond  If not null, the time alarm will second-match this value.
00257  *
00258  * \return 0 success, 1 fail to set
00259  */
00260 extern int RTC_SetTimeAlarm(Rtc *pRtc, uint8_t *pucHour,
00261                              uint8_t *pucMinute, uint8_t *pucSecond)
00262 {
00263     uint32_t dwAlarm = 0;
00264 
00265     TRACE_DEBUG("RTC_SetTimeAlarm()\n\r");
00266 
00267     /* Hour */
00268     if (pucHour)
00269         dwAlarm |= RTC_TIMALR_HOUREN | ((*pucHour / 10) << 20) | ((
00270                        *pucHour % 10) << 16);
00271 
00272     /* Minute */
00273     if (pucMinute) {
00274         dwAlarm |= RTC_TIMALR_MINEN | ((*pucMinute / 10) << 12)
00275                    | ((*pucMinute % 10) << 8);
00276     }
00277 
00278     /* Second */
00279     if (pucSecond)
00280         dwAlarm |= RTC_TIMALR_SECEN | ((*pucSecond / 10) << 4) | (*pucSecond % 10);
00281 
00282     pRtc->RTC_TIMALR = dwAlarm;
00283 
00284     return (int)(pRtc->RTC_VER & RTC_VER_NVTIMALR);
00285 }
00286 
00287 /**
00288  * \brief Retrieves the current year, month and day from the RTC.
00289  * Month, day and week values are numbered starting at 1.
00290  *
00291  * \param pYwear  Current year (optional).
00292  * \param pucMonth  Current month (optional).
00293  * \param pucDay  Current day (optional).
00294  * \param pucWeek  Current day in current week (optional).
00295  */
00296 extern void RTC_GetDate(Rtc *pRtc, uint16_t *pwYear, uint8_t *pucMonth,
00297                          uint8_t *pucDay, uint8_t *pucWeek)
00298 {
00299     uint32_t dwDate;
00300 
00301     /* Get current date (multiple reads are necessary to insure a stable value) */
00302     do {
00303         dwDate = pRtc->RTC_CALR;
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     /* Retrieve day */
00319     if (pucDay)
00320         *pucDay = (((dwDate >> 28) & 0x3) * 10) + ((dwDate >> 24) & 0xF);
00321 
00322     /* Retrieve week */
00323     if (pucWeek)
00324         *pucWeek = ((dwDate >> 21) & 0x7);
00325 }
00326 
00327 /**
00328  * \brief Sets the current year, month and day in the RTC.
00329  * Month, day and week values must be numbered starting from 1.
00330  *
00331  * \note In successive update operations, the user must wait at least one second
00332  * after resetting the UPDTIM/UPDCAL bit in the RTC_CR before setting these
00333  * bits again. Please look at the RTC section of the datasheet for detail.
00334  *
00335  * \param wYear  Current year.
00336  * \param ucMonth Current month.
00337  * \param ucDay   Current day.
00338  * \param ucWeek  Day number in current week.
00339  *
00340  * \return 0 success, 1 fail to set
00341  */
00342 extern int RTC_SetDate(Rtc *pRtc, uint16_t wYear, uint8_t ucMonth,
00343                         uint8_t ucDay, uint8_t ucWeek)
00344 {
00345     uint32_t wDate;
00346     uint8_t ucCent_bcd;
00347     uint8_t ucYear_bcd;
00348     uint8_t ucMonth_bcd;
00349     uint8_t ucDay_bcd;
00350     uint8_t ucWeek_bcd;
00351 
00352     ucCent_bcd  = ((wYear / 100) % 10) | ((wYear / 1000) << 4);
00353     ucYear_bcd  = (wYear % 10) | (((wYear / 10) % 10) << 4);
00354     ucMonth_bcd = ((ucMonth % 10) | (ucMonth / 10) << 4);
00355     ucDay_bcd   = ((ucDay % 10) | (ucDay / 10) << 4);
00356     ucWeek_bcd  = ((ucWeek % 10) | (ucWeek / 10) << 4);
00357 
00358     /* value over flow */
00359     if ((ucCent_bcd & (uint8_t)(~RTC_CENT_BIT_LEN_MASK)) |
00360          (ucYear_bcd & (uint8_t)(~RTC_YEAR_BIT_LEN_MASK)) |
00361          (ucMonth_bcd & (uint8_t)(~RTC_MONTH_BIT_LEN_MASK)) |
00362          (ucWeek_bcd & (uint8_t)(~RTC_WEEK_BIT_LEN_MASK)) |
00363          (ucDay_bcd & (uint8_t)(~RTC_DATE_BIT_LEN_MASK))
00364     )
00365         return 1;
00366 
00367 
00368     /* Convert values to date register value */
00369     wDate = ucCent_bcd |
00370             (ucYear_bcd << 8) |
00371             (ucMonth_bcd << 16) |
00372             (ucWeek_bcd << 21) |
00373             (ucDay_bcd << 24);
00374 
00375     /* Update calendar register  */
00376     pRtc->RTC_CR |= RTC_CR_UPDCAL;
00377 
00378     while ((pRtc->RTC_SR & RTC_SR_ACKUPD) != RTC_SR_ACKUPD);
00379 
00380     pRtc->RTC_SCCR = RTC_SCCR_ACKCLR;
00381     pRtc->RTC_CALR = wDate;
00382     pRtc->RTC_CR &= (uint32_t)(~RTC_CR_UPDCAL);
00383     pRtc->RTC_SCCR |= RTC_SCCR_SECCLR; /* clear SECENV in SCCR */
00384 
00385     return (int)(pRtc->RTC_VER & RTC_VER_NVCAL);
00386 }
00387 
00388 /**
00389  * \brief Sets a date alarm in the RTC.
00390  * The alarm will match only the provided values;
00391  * Passing a null-pointer disables the corresponding field match.
00392  *
00393  * \param pucMonth If not null, the RTC alarm will month-match this value.
00394  * \param pucDay   If not null, the RTC alarm will day-match this value.
00395  *
00396  * \return 0 success, 1 fail to set
00397  */
00398 extern int RTC_SetDateAlarm(Rtc *pRtc, uint8_t *pucMonth, uint8_t *pucDay)
00399 {
00400     uint32_t dwAlarm;
00401 
00402     dwAlarm = ((pucMonth) || (pucDay)) ? (0) : (0x01010000);
00403 
00404     TRACE_DEBUG("RTC_SetDateAlarm()\n\r");
00405 
00406     /* Compute alarm field value */
00407     if (pucMonth) {
00408         dwAlarm |= RTC_CALALR_MTHEN | ((*pucMonth / 10) << 20)
00409                    | ((*pucMonth % 10) << 16);
00410     }
00411 
00412     if (pucDay) {
00413         dwAlarm |= RTC_CALALR_DATEEN | ((*pucDay / 10) << 28)
00414                    | ((*pucDay % 10) << 24);
00415     }
00416 
00417     /* Set alarm */
00418     pRtc->RTC_CALALR = dwAlarm;
00419 
00420     return (int)(pRtc->RTC_VER & RTC_VER_NVCALALR);
00421 }
00422 
00423 /**
00424  * \brief Clear flag bits of status clear command register in the RTC.
00425  *
00426  * \param mask Bits mask of cleared events
00427  */
00428 extern void RTC_ClearSCCR(Rtc *pRtc, uint32_t dwMask)
00429 {
00430     /* Clear all flag bits in status clear command register */
00431     dwMask &= RTC_SCCR_ACKCLR | RTC_SCCR_ALRCLR | RTC_SCCR_SECCLR
00432               | RTC_SCCR_TIMCLR | RTC_SCCR_CALCLR;
00433 
00434     pRtc->RTC_SCCR = dwMask;
00435 }
00436 
00437 /**
00438  * \brief Get flag bits of status register in the RTC.
00439  *
00440  * \param mask Bits mask of Status Register
00441  *
00442  * \return Status register & mask
00443  */
00444 extern uint32_t RTC_GetSR(Rtc *pRtc, uint32_t dwMask)
00445 {
00446     uint32_t dwEvent;
00447 
00448     dwEvent = pRtc->RTC_SR;
00449 
00450     return (dwEvent & dwMask);
00451 }
00452 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines