summaryrefslogtreecommitdiff
path: root/peripherals/rtc/rtc.c
diff options
context:
space:
mode:
Diffstat (limited to 'peripherals/rtc/rtc.c')
-rw-r--r--peripherals/rtc/rtc.c405
1 files changed, 405 insertions, 0 deletions
diff --git a/peripherals/rtc/rtc.c b/peripherals/rtc/rtc.c
new file mode 100644
index 0000000..be23c96
--- /dev/null
+++ b/peripherals/rtc/rtc.c
@@ -0,0 +1,405 @@
+/* ----------------------------------------------------------------------------
+ * 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 <board.h>
+#include <utility/assert.h>
+#include <utility/trace.h>
+
+//------------------------------------------------------------------------------
+// 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);
+}
personal git repositories of Harald Welte. Your mileage may vary