/* * Copyright 2008-2010, Freie Universitaet Berlin (FUB). All rights reserved. * Copyright 2014 INRIA * * This file is subject to the terms and conditions of the GNU Lesser * General Public License v2.1. See the file LICENSE in the top level * directory for more details. */ /** * @ingroup cpu_lpc23xx * @ingroup drivers_periph_rtc * @{ * * @file * @brief Peripheral UART driver implementation * * @author Kaspar Schleiser * * @} */ #include #include #include /* cpu */ #include "periph/rtc.h" #include "VIC.h" #include "lpc23xx.h" #include "timex.h" #define ENABLE_DEBUG 0 #include "debug.h" /* Alarm callback */ static rtc_alarm_cb_t _cb; /* Argument to alarm callback */ static void *_cb_arg; void RTC_IRQHandler(void) __attribute__((interrupt("IRQ"))); void rtc_init(void) { PCONP |= BIT9; RTC_AMR = 0xff; /* disable alarm irq */ RTC_CIIR = 0; /* disable increase irq */ RTC_CISS = 0; /* disable subsecond irq */ INTWAKE |= BIT15; /* rtc irq wakes up mcu from power down */ RTC_CCR = CCR_CLKSRC; /* Clock from external 32 kHz Osc. */ /* Initialize clock to a a sane and predictable default * after cold boot or external reset. */ if ((RSIR == RSIR_POR) || (RSIR == (RSIR_POR | RSIR_EXTR))) { struct tm localt = { .tm_year = RIOT_EPOCH - 1900 }; rtc_set_time(&localt); } rtc_poweron(); DEBUG("%2lu.%2lu.%4lu %2lu:%2lu:%2lu\n", RTC_DOM, RTC_MONTH, RTC_YEAR, RTC_HOUR, RTC_MIN, RTC_SEC); } /** * @brief Sets the current time in broken down format directly from to RTC * @param[in] localt Pointer to structure with time to set */ int rtc_set_time(struct tm *localt) { if (localt == NULL) { return -1; } /* normalize input */ rtc_tm_normalize(localt); /* set clock */ RTC_SEC = localt->tm_sec; RTC_MIN = localt->tm_min; RTC_HOUR = localt->tm_hour; RTC_DOM = localt->tm_mday; RTC_DOW = localt->tm_wday; RTC_DOY = localt->tm_yday; RTC_MONTH = localt->tm_mon + 1; RTC_YEAR = localt->tm_year; return 0; } int rtc_get_time(struct tm *localt) { if (localt == NULL) { return -1; } localt->tm_sec = RTC_SEC; localt->tm_min = RTC_MIN; localt->tm_hour = RTC_HOUR; localt->tm_mday = RTC_DOM; localt->tm_wday = RTC_DOW; localt->tm_yday = RTC_DOY; localt->tm_mon = RTC_MONTH - 1; localt->tm_year = RTC_YEAR; localt->tm_isdst = -1; /* not available */ return 0; } int rtc_get_time_ms(struct tm *time, uint16_t *ms) { uint16_t ccr_before, ccr_after; /* loop in case of overflow */ do { ccr_before = RTC_CCR >> 1; rtc_get_time(time); ccr_after = RTC_CCR >> 1; } while (ccr_before > ccr_after); /* CCR is 15-bit counter, increments second with each overflow */ *ms = (ccr_after * MS_PER_SEC) >> 15; return 0; } int rtc_set_alarm(struct tm *localt, rtc_alarm_cb_t cb, void *arg) { if (localt != NULL) { /* normalize input */ rtc_tm_normalize(localt); RTC_ALSEC = localt->tm_sec; RTC_ALMIN = localt->tm_min; RTC_ALHOUR = localt->tm_hour; RTC_ALDOM = localt->tm_mday; RTC_ALDOW = localt->tm_wday; RTC_ALDOY = localt->tm_yday; RTC_ALMON = localt->tm_mon + 1; RTC_ALYEAR = localt->tm_year; RTC_AMR = 0; /* set which alarm fields to check */ DEBUG("alarm set %2lu.%2lu.%4lu %2lu:%2lu:%2lu\n", RTC_ALDOM, RTC_ALMON, RTC_ALYEAR, RTC_ALHOUR, RTC_ALMIN, RTC_ALSEC); } if (cb) { _cb = cb; _cb_arg = arg; } return 0; } int rtc_get_alarm(struct tm *localt) { if (localt == NULL) { return -1; } localt->tm_sec = RTC_ALSEC; localt->tm_min = RTC_ALMIN; localt->tm_hour = RTC_ALHOUR; localt->tm_mday = RTC_ALDOM; localt->tm_wday = RTC_ALDOW; localt->tm_yday = RTC_ALDOY; localt->tm_mon = RTC_ALMON - 1; localt->tm_year = RTC_ALYEAR; localt->tm_isdst = -1; /* not available */ return 0; } void rtc_clear_alarm(void) { RTC_AMR = 0xff; } void rtc_poweron(void) { PCONP |= BIT9; RTC_ILR = (ILR_RTSSF | ILR_RTCCIF | ILR_RTCALF); /* clear interrupt flags */ RTC_CCR |= CCR_CLKEN; /* enable clock */ install_irq(RTC_INT, &RTC_IRQHandler, IRQP_RTC); /* install interrupt handler */ } void rtc_poweroff(void) { RTC_CCR &= ~CCR_CLKEN; /* disable clock */ install_irq(RTC_INT, NULL, 0); PCONP &= ~BIT9; } void RTC_IRQHandler(void) { if (RTC_ILR & ILR_RTCALF) { RTC_ILR = ILR_RTCALF; RTC_AMR = 0xff; /* disable alarm irq */ if (_cb) { _cb(_cb_arg); } DEBUG("Ring\n"); } VICVectAddr = 0; /* Acknowledge Interrupt */ }