mbed library sources. Supersedes mbed-src.
Dependents: Nucleo_Hello_Encoder BLE_iBeaconScan AM1805_DEMO DISCO-F429ZI_ExportTemplate1 ... more
Diff: targets/TARGET_Maxim/TARGET_MAX32630/rtc_api.c
- Revision:
- 186:707f6e361f3e
- Parent:
- 174:b96e65c34a4d
--- a/targets/TARGET_Maxim/TARGET_MAX32630/rtc_api.c Thu Apr 19 17:12:19 2018 +0100 +++ b/targets/TARGET_Maxim/TARGET_MAX32630/rtc_api.c Fri Jun 22 16:45:37 2018 +0100 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (C) 2016 Maxim Integrated Products, Inc., All Rights Reserved. + * Copyright (C) 2016,2018 Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -31,38 +31,31 @@ ******************************************************************************* */ +#include <string.h> #include "rtc_api.h" #include "lp_ticker_api.h" #include "rtc.h" #include "lp.h" - -#define PRESCALE_VAL RTC_PRESCALE_DIV_2_0 // Set the divider for the 4kHz clock -#define SHIFT_AMT (RTC_PRESCALE_DIV_2_12 - PRESCALE_VAL) +#include <string.h> -#define WINDOW 1000 +// LOG2 for 32-bit powers of 2 +#define LOG2_1(n) (((n) >= (1 << 1)) ? 1 : 0) +#define LOG2_2(n) (((n) >= (1 << 2)) ? ( 2 + (LOG2_1((n) >> 2))) : LOG2_1(n)) +#define LOG2_4(n) (((n) >= (1 << 4)) ? ( 4 + (LOG2_2((n) >> 4))) : LOG2_2(n)) +#define LOG2_8(n) (((n) >= (1 << 8)) ? ( 8 + (LOG2_4((n) >> 8))) : LOG2_4(n)) +#define LOG2(n) (((n) >= (1 << 16)) ? (16 + (LOG2_8((n) >> 16))) : LOG2_8(n)) -static int rtc_inited = 0; -static volatile uint32_t overflow_cnt = 0; +#define LP_TIMER_FREQ_HZ 4096 +#define LP_TIMER_PRESCALE RTC_PRESCALE_DIV_2_0 +#define LP_TIMER_RATE_HZ (LP_TIMER_FREQ_HZ >> LP_TIMER_PRESCALE) +#define LP_TIMER_WIDTH 32 -static uint64_t rtc_read64(void); +static volatile int rtc_inited = 0; +static volatile int lp_ticker_inited = 0; //****************************************************************************** -static void overflow_handler(void) +static void init_rtc(void) { - overflow_cnt++; - RTC_ClearFlags(MXC_F_RTC_FLAGS_ASYNC_CLR_FLAGS); -} - -//****************************************************************************** -void rtc_init(void) -{ - if (rtc_inited) { - return; - } - rtc_inited = 1; - - overflow_cnt = 0; - /* Enable power for RTC for all LPx states */ MXC_PWRSEQ->reg0 |= (MXC_F_PWRSEQ_REG0_PWR_RTCEN_RUN | MXC_F_PWRSEQ_REG0_PWR_RTCEN_SLP); @@ -70,21 +63,13 @@ /* Enable clock to synchronizers */ CLKMAN_SetClkScale(CLKMAN_CLK_SYNC, CLKMAN_SCALE_DIV_1); - // Prepare interrupt handlers - NVIC_SetVector(RTC0_IRQn, (uint32_t)lp_ticker_irq_handler); - NVIC_EnableIRQ(RTC0_IRQn); - NVIC_SetVector(RTC3_IRQn, (uint32_t)overflow_handler); - NVIC_EnableIRQ(RTC3_IRQn); - - // Enable wakeup on RTC rollover - LP_ConfigRTCWakeUp(0, 0, 0, 1); - /* RTC registers are only reset on a power cycle. Do not reconfigure the RTC * if it is already running. */ if (!RTC_IsActive()) { - rtc_cfg_t cfg = {0}; - cfg.prescaler = PRESCALE_VAL; + rtc_cfg_t cfg; + memset(&cfg, 0, sizeof(rtc_cfg_t)); + cfg.prescaler = LP_TIMER_PRESCALE; cfg.snoozeMode = RTC_SNOOZE_DISABLE; int retval = RTC_Init(&cfg); @@ -96,163 +81,116 @@ } //****************************************************************************** -void lp_ticker_init(void) +static void overflow_handler(void) { - rtc_init(); + MXC_RTCTMR->comp[1] += ((UINT32_MAX >> LOG2(LP_TIMER_RATE_HZ)) + 1); + RTC_ClearFlags(MXC_F_RTC_FLAGS_OVERFLOW); +} + +//****************************************************************************** +void rtc_init(void) +{ + NVIC_SetVector(RTC3_IRQn, (uint32_t)overflow_handler); + NVIC_EnableIRQ(RTC3_IRQn); + + // Enable as LP wakeup source + MXC_PWRSEQ->msk_flags |= MXC_F_PWRSEQ_FLAGS_RTC_ROLLOVER; + + init_rtc(); } //****************************************************************************** void rtc_free(void) { - if (RTC_IsActive()) { - // Clear and disable RTC - MXC_RTCTMR->ctrl |= MXC_F_RTC_CTRL_CLEAR; - RTC_Stop(); - } + while (MXC_RTCTMR->ctrl & MXC_F_RTC_CTRL_PENDING); } //****************************************************************************** int rtc_isenabled(void) { - return RTC_IsActive(); + return !!RTC_IsActive(); +} + +//****************************************************************************** +void rtc_write(time_t t) +{ + MXC_RTCTMR->comp[1] = t - (MXC_RTCTMR->timer >> LOG2(LP_TIMER_RATE_HZ)); + while (MXC_RTCTMR->ctrl & MXC_F_RTC_CTRL_PENDING); } //****************************************************************************** time_t rtc_read(void) { - uint32_t ovf_cnt_1, ovf_cnt_2, timer_cnt; - uint32_t ovf1, ovf2; - - // Make sure RTC is setup before trying to read - if (!rtc_inited) { - rtc_init(); - } + return (MXC_RTCTMR->timer >> LOG2(LP_TIMER_RATE_HZ)) + MXC_RTCTMR->comp[1]; +} - // Ensure coherency between overflow_cnt and timer - do { - ovf_cnt_1 = overflow_cnt; - ovf1 = RTC_GetFlags() & MXC_F_RTC_FLAGS_OVERFLOW; - timer_cnt = RTC_GetCount(); - ovf2 = RTC_GetFlags() & MXC_F_RTC_FLAGS_OVERFLOW; - ovf_cnt_2 = overflow_cnt; - } while ((ovf_cnt_1 != ovf_cnt_2) || (ovf1 != ovf2)); - - // Account for an unserviced interrupt - if (ovf1) { - ovf_cnt_1++; - } - - return (timer_cnt >> SHIFT_AMT) + (ovf_cnt_1 << (32 - SHIFT_AMT)); +//****************************************************************************** +void lp_ticker_init(void) +{ + RTC_DisableINT(MXC_F_RTC_INTEN_COMP0); + NVIC_SetVector(RTC0_IRQn, (uint32_t)lp_ticker_irq_handler); + NVIC_EnableIRQ(RTC0_IRQn); + init_rtc(); } //****************************************************************************** -static uint64_t rtc_read64(void) +void lp_ticker_free(void) { - uint32_t ovf_cnt_1, ovf_cnt_2, timer_cnt; - uint32_t ovf1, ovf2; - uint64_t current_us; - - // Make sure RTC is setup before trying to read - if (!rtc_inited) { - rtc_init(); - } + // Disable interrupt associated with LPTICKER API + RTC_DisableINT(MXC_F_RTC_INTEN_COMP0); - // Ensure coherency between overflow_cnt and timer - do { - ovf_cnt_1 = overflow_cnt; - ovf1 = RTC_GetFlags() & MXC_F_RTC_FLAGS_OVERFLOW; - timer_cnt = RTC_GetCount(); - ovf2 = RTC_GetFlags() & MXC_F_RTC_FLAGS_OVERFLOW; - ovf_cnt_2 = overflow_cnt; - } while ((ovf_cnt_1 != ovf_cnt_2) || (ovf1 != ovf2)); - - // Account for an unserviced interrupt - if (ovf1) { - ovf_cnt_1++; + // RTC hardware is shared by LPTICKER and RTC APIs. + // Prior initialization of the RTC API gates disabling the RTC hardware. + if (!(MXC_RTCTMR->inten & MXC_F_RTC_INTEN_OVERFLOW)) { + RTC_Stop(); } - - current_us = (((uint64_t)timer_cnt * 1000000) >> SHIFT_AMT) + (((uint64_t)ovf_cnt_1 * 1000000) << (32 - SHIFT_AMT)); - - return current_us; } //****************************************************************************** -void rtc_write(time_t t) +uint32_t lp_ticker_read(void) { - // Make sure RTC is setup before accessing - if (!rtc_inited) { - rtc_init(); - } - - RTC_Stop(); - RTC_SetCount(t << SHIFT_AMT); - overflow_cnt = t >> (32 - SHIFT_AMT); - RTC_Start(); + return MXC_RTCTMR->timer; } //****************************************************************************** void lp_ticker_set_interrupt(timestamp_t timestamp) { - uint32_t comp_value; - uint64_t curr_ts64; - uint64_t ts64; - - // Note: interrupts are disabled before this function is called. - - // Disable the alarm while it is prepared - RTC_DisableINT(MXC_F_RTC_INTEN_COMP0); - - curr_ts64 = rtc_read64(); - ts64 = (uint64_t)timestamp | (curr_ts64 & 0xFFFFFFFF00000000ULL); - - // If this event is older than a recent window, it must be in the future - if ((ts64 < (curr_ts64 - WINDOW)) && ((curr_ts64 - WINDOW) < curr_ts64)) { - ts64 += 0x100000000ULL; - } - - uint32_t timer = RTC_GetCount(); - if (ts64 <= curr_ts64) { - // This event has already occurred. Set the alarm to expire immediately. - comp_value = timer + 1; - } else { - comp_value = (ts64 << SHIFT_AMT) / 1000000; - } - - // Ensure that the compare value is far enough in the future to guarantee the interrupt occurs. - if ((comp_value < (timer + 2)) && (comp_value > (timer - 10))) { - comp_value = timer + 2; - } - - MXC_RTCTMR->comp[0] = comp_value; - MXC_RTCTMR->flags = MXC_F_RTC_FLAGS_ASYNC_CLR_FLAGS; + MXC_RTCTMR->comp[0] = timestamp; + MXC_RTCTMR->flags = MXC_F_RTC_FLAGS_COMP0; RTC_EnableINT(MXC_F_RTC_INTEN_COMP0); - // Enable wakeup from RTC - LP_ConfigRTCWakeUp(1, 0, 0, 1); + // Enable as LP wakeup source + MXC_PWRSEQ->msk_flags |= MXC_F_PWRSEQ_FLAGS_RTC_CMPR0; - // Wait for pending transactions + // Postponed write pending wait for comp0 and flags while (MXC_RTCTMR->ctrl & MXC_F_RTC_CTRL_PENDING); } +//****************************************************************************** +void lp_ticker_disable_interrupt(void) +{ + RTC_DisableINT(MXC_F_RTC_INTEN_COMP0); +} + +//****************************************************************************** +void lp_ticker_clear_interrupt(void) +{ + RTC_ClearFlags(MXC_F_RTC_FLAGS_COMP0); +} + +//****************************************************************************** void lp_ticker_fire_interrupt(void) { NVIC_SetPendingIRQ(RTC0_IRQn); } //****************************************************************************** -inline void lp_ticker_disable_interrupt(void) -{ - RTC_DisableINT(MXC_F_RTC_INTEN_COMP0); -} - -//****************************************************************************** -inline void lp_ticker_clear_interrupt(void) +const ticker_info_t *lp_ticker_get_info(void) { - RTC_ClearFlags(MXC_F_RTC_FLAGS_ASYNC_CLR_FLAGS); -} + static const ticker_info_t info = { + LP_TIMER_RATE_HZ, + LP_TIMER_WIDTH + }; -//****************************************************************************** -inline uint32_t lp_ticker_read(void) -{ - return rtc_read64(); + return &info; }