/* ---------------------------------------------------------------------------- * ATMEL Microcontroller Software Support * ---------------------------------------------------------------------------- * Copyright (c) 2008, Atmel Corporation * * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the disclaimer below. * * Atmel's name may not be used to endorse or promote products derived from * this software without specific prior written permission. * * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ---------------------------------------------------------------------------- */ //------------------------------------------------------------------------------ // Headers //------------------------------------------------------------------------------ #include "rtc.h" #include #include #include //------------------------------------------------------------------------------ // Exported functions //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ /// Sets the RTC in either 12- or 24-hour mode. /// \param mode Hour mode. //------------------------------------------------------------------------------ void RTC_SetHourMode(unsigned int mode) { SANITY_CHECK((mode & 0xFFFFFFFE) == 0); TRACE_DEBUG("RTC_SetHourMode()\n\r"); AT91C_BASE_RTC->RTC_MR = mode; } //------------------------------------------------------------------------------ /// Gets the RTC mode. /// \return Hour mode. //------------------------------------------------------------------------------ unsigned int RTC_GetHourMode() { unsigned int hmode; TRACE_DEBUG("RTC_SetHourMode()\n\r"); hmode = AT91C_BASE_RTC->RTC_MR; hmode &= 0xFFFFFFFE; return hmode; } //------------------------------------------------------------------------------ /// Enables the selected interrupt sources of the RTC. /// \param sources Interrupt sources to enable. //------------------------------------------------------------------------------ void RTC_EnableIt(unsigned int sources) { SANITY_CHECK((sources & ~0x1F) == 0); TRACE_DEBUG("RTC_EnableIt()\n\r"); AT91C_BASE_RTC->RTC_IER = sources; } //------------------------------------------------------------------------------ /// Disables the selected interrupt sources of the RTC. /// \param sources Interrupt sources to disable. //------------------------------------------------------------------------------ void RTC_DisableIt(unsigned int sources) { SANITY_CHECK((sources & ~0x1F) == 0); TRACE_DEBUG("RTC_DisableIt()\n\r"); AT91C_BASE_RTC->RTC_IDR = sources; } //------------------------------------------------------------------------------ /// Sets the current time in the RTC. /// \param hour Current hour in 24 hour mode. /// \param minute Current minute. /// \param second Current second. /// \return 0 sucess, 1 fail to set //------------------------------------------------------------------------------ int RTC_SetTime(unsigned char hour, unsigned char minute, unsigned char second) { unsigned int time=0; unsigned char hour_bcd; unsigned char min_bcd; unsigned char sec_bcd; TRACE_DEBUG("RTC_SetTime(%02d:%02d:%02d)\n\r", hour, minute, second); // if 12-hour mode, set AMPM bit if ((AT91C_BASE_RTC->RTC_MR & AT91C_RTC_HRMOD) == AT91C_RTC_HRMOD) { if (hour > 12) { hour -= 12; time |= AT91C_RTC_AMPM; } } hour_bcd = (hour%10) | ((hour/10)<<4); min_bcd = (minute%10) | ((minute/10)<<4); sec_bcd = (second%10) | ((second/10)<<4); //value overflow if((hour_bcd & (unsigned char)(~RTC_HOUR_BIT_LEN_MASK)) | (min_bcd & (unsigned char)(~RTC_MIN_BIT_LEN_MASK)) | (sec_bcd & (unsigned char)(~RTC_SEC_BIT_LEN_MASK))) return 1; time = sec_bcd | (min_bcd << 8) | (hour_bcd<<16); // time |= ((hour % 10) << 16) | ((hour / 10) << 20); // Set time //if((AT91C_BASE_RTC->RTC_SR & AT91C_RTC_SECEV) != AT91C_RTC_SECEV) return 1; while ((AT91C_BASE_RTC->RTC_SR & AT91C_RTC_SECEV) != AT91C_RTC_SECEV);//wait from previous set AT91C_BASE_RTC->RTC_CR |= AT91C_RTC_UPDTIM; while ((AT91C_BASE_RTC->RTC_SR & AT91C_RTC_ACKUPD) != AT91C_RTC_ACKUPD); AT91C_BASE_RTC->RTC_SCCR = AT91C_RTC_ACKUPD; AT91C_BASE_RTC->RTC_TIMR = time; AT91C_BASE_RTC->RTC_CR &= ~AT91C_RTC_UPDTIM; AT91C_BASE_RTC->RTC_SCCR |= AT91C_RTC_SECEV;//clear SECENV in SCCR return (int)(AT91C_BASE_RTC->RTC_VER & AT91C_RTC_NVTIM); } //------------------------------------------------------------------------------ /// Retrieves the current time as stored in the RTC in several variables. /// \param pHour If not null, current hour is stored in this variable. /// \param pMinute If not null, current minute is stored in this variable. /// \param pSecond If not null, current second is stored in this variable. //------------------------------------------------------------------------------ void RTC_GetTime( unsigned char *pHour, unsigned char *pMinute, unsigned char *pSecond) { unsigned int time; TRACE_DEBUG("RTC_GetTime()\n\r"); // Get current RTC time time = AT91C_BASE_RTC->RTC_TIMR; while (time != AT91C_BASE_RTC->RTC_TIMR) { time = AT91C_BASE_RTC->RTC_TIMR; } // Hour if (pHour) { *pHour = ((time & 0x00300000) >> 20) * 10 + ((time & 0x000F0000) >> 16); if ((time & AT91C_RTC_AMPM) == AT91C_RTC_AMPM) { *pHour += 12; } } // Minute if (pMinute) { *pMinute = ((time & 0x00007000) >> 12) * 10 + ((time & 0x00000F00) >> 8); } // Second if (pSecond) { *pSecond = ((time & 0x00000070) >> 4) * 10 + (time & 0x0000000F); } } //------------------------------------------------------------------------------ /// Sets a time alarm on the RTC. The match is performed only on the provided /// variables; setting all pointers to 0 disables the time alarm. /// Note: in AM/PM mode, the hour value must have bit #7 set for PM, cleared for /// AM (as expected in the time registers). /// \param pHour If not null, the time alarm will hour-match this value. /// \param pMinute If not null, the time alarm will minute-match this value. /// \param pSecond If not null, the time alarm will second-match this value. /// \return 0 success, 1 fail to set //------------------------------------------------------------------------------ int RTC_SetTimeAlarm( unsigned char *pHour, unsigned char *pMinute, unsigned char *pSecond) { unsigned int alarm = 0; TRACE_DEBUG("RTC_SetTimeAlarm()\n\r"); // Hour if (pHour) { alarm |= AT91C_RTC_HOUREN | ((*pHour / 10) << 20) | ((*pHour % 10) << 16); } // Minute if (pMinute) { alarm |= AT91C_RTC_MINEN | ((*pMinute / 10) << 12) | ((*pMinute % 10) << 8); } // Second if (pSecond) { alarm |= AT91C_RTC_SECEN | ((*pSecond / 10) << 4) | (*pSecond % 10); } AT91C_BASE_RTC->RTC_TIMALR = alarm; return (int)(AT91C_BASE_RTC->RTC_VER & AT91C_RTC_NVTIMALR); } //------------------------------------------------------------------------------ /// Retrieves the current year, month and day from the RTC. Month, day and week /// values are numbered starting at 1. /// \param pYear Current year (optional). /// \param pMonth Current month (optional). /// \param pDay Current day (optional). /// \param pWeek Current day in current week (optional). //------------------------------------------------------------------------------ void RTC_GetDate( unsigned short *pYear, unsigned char *pMonth, unsigned char *pDay, unsigned char *pWeek) { unsigned int date; // Get current date (multiple reads are necessary to insure a stable value) do { date = AT91C_BASE_RTC->RTC_CALR; } while (date != AT91C_BASE_RTC->RTC_CALR); // Retrieve year if (pYear) { *pYear = (((date >> 4) & 0x7) * 1000) + ((date & 0xF) * 100) + (((date >> 12) & 0xF) * 10) + ((date >> 8) & 0xF); } // Retrieve month if (pMonth) { *pMonth = (((date >> 20) & 1) * 10) + ((date >> 16) & 0xF); } // Retrieve day if (pDay) { *pDay = (((date >> 28) & 0x3) * 10) + ((date >> 24) & 0xF); } // Retrieve week if (pWeek) { *pWeek = ((date >> 21) & 0x7); } } //------------------------------------------------------------------------------ /// Sets the current year, month and day in the RTC. Month, day and week values /// must be numbered starting from 1. /// \param year Current year. /// \param month Current month. /// \param day Current day. /// \param week Day number in current week. /// \return 0 success, 1 fail to set //------------------------------------------------------------------------------ int RTC_SetDate( unsigned short year, unsigned char month, unsigned char day, unsigned char week) { unsigned int date; unsigned char cent_bcd; unsigned char year_bcd; unsigned char month_bcd; unsigned char day_bcd; unsigned char week_bcd; cent_bcd = ((year/100)%10) | ((year/1000)<<4); year_bcd = (year%10) | (((year/10)%10)<<4); month_bcd = ((month%10) | (month/10)<<4); day_bcd = ((day%10) | (day/10)<<4); week_bcd = ((week%10) | (week/10)<<4); //value over flow if((cent_bcd & (unsigned char)(~RTC_CENT_BIT_LEN_MASK)) | (year_bcd & (unsigned char)(~RTC_YEAR_BIT_LEN_MASK)) | (month_bcd & (unsigned char)(~RTC_MONTH_BIT_LEN_MASK)) | (week_bcd & (unsigned char)(~RTC_WEEK_BIT_LEN_MASK)) | (day_bcd & (unsigned char)(~RTC_DATE_BIT_LEN_MASK))) return 1; // Convert values to date register value date = cent_bcd | (year_bcd << 8) | (month_bcd << 16) | (week_bcd << 21) | (day_bcd << 24); // Update calendar register //if((AT91C_BASE_RTC->RTC_SR & AT91C_RTC_SECEV) != AT91C_RTC_SECEV) return 1; while ((AT91C_BASE_RTC->RTC_SR & AT91C_RTC_SECEV) != AT91C_RTC_SECEV);//wait from previous set AT91C_BASE_RTC->RTC_CR |= AT91C_RTC_UPDCAL; while ((AT91C_BASE_RTC->RTC_SR & AT91C_RTC_ACKUPD) != AT91C_RTC_ACKUPD); AT91C_BASE_RTC->RTC_SCCR = AT91C_RTC_ACKUPD; AT91C_BASE_RTC->RTC_CALR = date; AT91C_BASE_RTC->RTC_CR &= ~AT91C_RTC_UPDCAL; AT91C_BASE_RTC->RTC_SCCR |= AT91C_RTC_SECEV;//clear SECENV in SCCR return (int)(AT91C_BASE_RTC->RTC_VER & AT91C_RTC_NVCAL); } //------------------------------------------------------------------------------ /// Sets a date alarm in the RTC. The alarm will match only the provided values; /// passing a null-pointer disables the corresponding field match. /// \param pMonth If not null, the RTC alarm will month-match this value. /// \param pDay If not null, the RTC alarm will day-match this value. /// \return 0 success, 1 fail to set //------------------------------------------------------------------------------ int RTC_SetDateAlarm(unsigned char *pMonth, unsigned char *pDay) { unsigned int alarm; alarm = ((pMonth) || (pDay)) ? (0) : (0x01010000); TRACE_DEBUG("RTC_SetDateAlarm()\n\r"); // Compute alarm field value if (pMonth) { alarm |= AT91C_RTC_MONTHEN | ((*pMonth / 10) << 20) | ((*pMonth % 10) << 16); } if (pDay) { alarm |= AT91C_RTC_DATEEN | ((*pDay / 10) << 28) | ((*pDay % 10) << 24); } // Set alarm AT91C_BASE_RTC->RTC_CALALR = alarm; return (int)(AT91C_BASE_RTC->RTC_VER & AT91C_RTC_NVCALALR); } //------------------------------------------------------------------------------ /// Clear flag bits of status clear command register in the RTC. /// \param mask Bits mask of cleared events //------------------------------------------------------------------------------ void RTC_ClearSCCR(unsigned int mask) { // Clear all flag bits in status clear command register mask &= AT91C_RTC_ACKUPD | AT91C_RTC_ALARM | AT91C_RTC_SECEV | \ AT91C_RTC_TIMEV | AT91C_RTC_CALEV; AT91C_BASE_RTC->RTC_SCCR = mask; } //------------------------------------------------------------------------------ /// Get flag bits of status register in the RTC. /// \param mask Bits mask of Status Register /// \return Status register & mask //------------------------------------------------------------------------------ unsigned int RTC_GetSR(unsigned int mask) { unsigned int event; event = AT91C_BASE_RTC->RTC_SR; return (event & mask); }