diff --git a/targets/TARGET_Maxim/TARGET_MAX32625/rtc_api.c b/targets/TARGET_Maxim/TARGET_MAX32625/rtc_api.c index 4abb1a5abe..ff39b3673e 100644 --- a/targets/TARGET_Maxim/TARGET_MAX32625/rtc_api.c +++ b/targets/TARGET_Maxim/TARGET_MAX32625/rtc_api.c @@ -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"), @@ -36,33 +36,24 @@ #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) +// 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)) -#define WINDOW 1000 +#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 int rtc_inited = 0; -static volatile uint32_t overflow_cnt = 0; - -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 +61,12 @@ void rtc_init(void) /* 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 = { 0 }; + cfg.prescaler = LP_TIMER_PRESCALE; cfg.snoozeMode = RTC_SNOOZE_DISABLE; int retval = RTC_Init(&cfg); @@ -96,163 +78,128 @@ void rtc_init(void) } //****************************************************************************** -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_ASYNC_CLR_FLAGS); +} + +//****************************************************************************** +void rtc_init(void) +{ + if (rtc_inited) { + return; + } + + NVIC_SetVector(RTC3_IRQn, (uint32_t)overflow_handler); + NVIC_EnableIRQ(RTC3_IRQn); + // Enable wakeup on RTC overflow + LP_ConfigRTCWakeUp(lp_ticker_inited, 0, 0, 1); + init_rtc(); + rtc_inited = 1; } //****************************************************************************** void rtc_free(void) { - if (RTC_IsActive()) { - // Clear and disable RTC - MXC_RTCTMR->ctrl |= MXC_F_RTC_CTRL_CLEAR; - RTC_Stop(); + if (rtc_inited) { + rtc_inited = 0; + if (lp_ticker_inited) { + RTC_DisableINT(MXC_F_RTC_FLAGS_OVERFLOW); + } else { + MXC_RTCTMR->ctrl |= MXC_F_RTC_CTRL_CLEAR; + RTC_Stop(); + } } } //****************************************************************************** int rtc_isenabled(void) { - return RTC_IsActive(); -} - -//****************************************************************************** -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(); - } - - // 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)); -} - -//****************************************************************************** -static uint64_t rtc_read64(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(); - } - - // 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++; - } - - current_us = (((uint64_t)timer_cnt * 1000000) >> SHIFT_AMT) + (((uint64_t)ovf_cnt_1 * 1000000) << (32 - SHIFT_AMT)); - - return current_us; + return rtc_inited; } //****************************************************************************** void rtc_write(time_t t) { - // 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(); -} - -//****************************************************************************** -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; - RTC_EnableINT(MXC_F_RTC_INTEN_COMP0); - - // Enable wakeup from RTC - LP_ConfigRTCWakeUp(1, 0, 0, 1); + MXC_RTCTMR->comp[1] = t - (MXC_RTCTMR->timer >> LOG2(LP_TIMER_RATE_HZ)); // Wait for pending transactions while (MXC_RTCTMR->ctrl & MXC_F_RTC_CTRL_PENDING); } +//****************************************************************************** +time_t rtc_read(void) +{ + if (!rtc_inited) { + rtc_init(); + } + + return (MXC_RTCTMR->timer >> LOG2(LP_TIMER_RATE_HZ)) + MXC_RTCTMR->comp[1]; +} + +//****************************************************************************** +void lp_ticker_init(void) +{ + if (lp_ticker_inited) { + return; + } + + NVIC_SetVector(RTC0_IRQn, (uint32_t)lp_ticker_irq_handler); + NVIC_EnableIRQ(RTC0_IRQn); + init_rtc(); + lp_ticker_inited = 1; +} + +//****************************************************************************** +uint32_t lp_ticker_read(void) +{ + return MXC_RTCTMR->timer; +} + +//****************************************************************************** +void lp_ticker_set_interrupt(timestamp_t timestamp) +{ + MXC_RTCTMR->comp[0] = timestamp; + MXC_RTCTMR->flags = MXC_F_RTC_FLAGS_ASYNC_CLR_FLAGS; + MXC_RTCTMR->inten |= MXC_F_RTC_INTEN_COMP0; + + // Enable wakeup from RTC compare 0 + LP_ConfigRTCWakeUp(1, 0, 0, rtc_inited); + + // Wait for pending transactions + 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_ASYNC_CLR_FLAGS); +} + +//****************************************************************************** void lp_ticker_fire_interrupt(void) { NVIC_SetPendingIRQ(RTC0_IRQn); } //****************************************************************************** -inline void lp_ticker_disable_interrupt(void) +const ticker_info_t *lp_ticker_get_info(void) { - RTC_DisableINT(MXC_F_RTC_INTEN_COMP0); -} + static const ticker_info_t info = { + LP_TIMER_RATE_HZ, + LP_TIMER_WIDTH + }; -//****************************************************************************** -inline void lp_ticker_clear_interrupt(void) -{ - RTC_ClearFlags(MXC_F_RTC_FLAGS_ASYNC_CLR_FLAGS); -} - -//****************************************************************************** -inline uint32_t lp_ticker_read(void) -{ - return rtc_read64(); + return &info; } diff --git a/targets/TARGET_Maxim/TARGET_MAX32625/us_ticker.c b/targets/TARGET_Maxim/TARGET_MAX32625/us_ticker.c index e8988e821e..baf095b742 100644 --- a/targets/TARGET_Maxim/TARGET_MAX32625/us_ticker.c +++ b/targets/TARGET_Maxim/TARGET_MAX32625/us_ticker.c @@ -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"), @@ -32,251 +32,84 @@ */ #include -#include "mbed_error.h" -#include "mbed_critical.h" #include "us_ticker_api.h" -#include "PeripheralNames.h" #include "tmr.h" -#include "assert.h" -#define US_TIMER MXC_TMR0 -#define US_TIMER_IRQn TMR0_0_IRQn +#define US_TIMER MXC_TMR0 +#define US_TIMER_IRQn TMR0_0_IRQn +#define US_TIMER_PRESCALE TMR_PRESCALE_DIV_2_5 +#define US_TIMER_MODE TMR32_MODE_COMPARE +#define US_TIMER_WIDTH 32 -static int us_ticker_inited = 0; -static uint32_t ticks_per_us; -static uint32_t tick_win; -static volatile uint64_t current_cnt; // Hold the current ticks -static volatile uint64_t event_cnt; // Holds the value of the next event - -#define MAX_TICK_VAL ((uint64_t)0xFFFFFFFF * ticks_per_us) - -//****************************************************************************** -static inline void inc_current_cnt_no_crit(uint32_t inc) -{ - // Overflow the ticker when the us ticker overflows - current_cnt += inc; - if (current_cnt > MAX_TICK_VAL) { - current_cnt -= (MAX_TICK_VAL + 1); - } -} - -//****************************************************************************** -static inline void inc_current_cnt(uint32_t inc) -{ - core_util_critical_section_enter(); - inc_current_cnt_no_crit(inc); - core_util_critical_section_exit(); -} - -//****************************************************************************** -static inline int event_passed(uint64_t current, uint64_t event) -{ - // Determine if the event has already happened. - // If the event is behind the current ticker, within a window, - // then the event has already happened. - if (((current < tick_win) && ((event < current) || - (event > (MAX_TICK_VAL - (tick_win - current))))) || - ((event < current) && (event > (current - tick_win)))) { - return 1; - } - - return 0; -} - -//****************************************************************************** -static inline uint64_t event_diff(uint64_t current, uint64_t event) -{ - // Check to see if the ticker will overflow before the event - if(current <= event) { - return (event - current); - } - - return ((MAX_TICK_VAL - current) + event); -} - -//****************************************************************************** -static void tmr_handler(void) -{ - uint32_t cmp = TMR32_GetCompare(US_TIMER); - TMR32_SetCompare(US_TIMER, 0xFFFFFFFF); // reset to max value to prevent further interrupts - if (TMR32_GetFlag(US_TIMER)) { - inc_current_cnt_no_crit(cmp); - } - TMR32_ClearFlag(US_TIMER); - NVIC_ClearPendingIRQ(US_TIMER_IRQn); - - if (event_passed(current_cnt + TMR32_GetCount(US_TIMER), event_cnt)) { - // the timestamp has expired - event_cnt = 0xFFFFFFFFFFFFFFFFULL; // reset to max value - us_ticker_irq_handler(); - } else { - uint64_t diff = event_diff(current_cnt, event_cnt); - if (diff < (uint64_t)0xFFFFFFFF) { - // the event occurs before the next overflow - TMR32_SetCompare(US_TIMER, diff); - - // Since the timer keeps counting after the terminal value is reached, it is possible that the new - // terminal value is in the past. - if (TMR32_GetCompare(US_TIMER) < TMR32_GetCount(US_TIMER)) { - // the timestamp has expired - TMR32_SetCompare(US_TIMER, 0xFFFFFFFF); // reset to max value to prevent further interrupts - TMR32_ClearFlag(US_TIMER); - NVIC_ClearPendingIRQ(US_TIMER_IRQn); - event_cnt = 0xFFFFFFFFFFFFFFFFULL; // reset to max value - us_ticker_irq_handler(); - } - } - } -} +static volatile int us_ticker_inited = 0; //****************************************************************************** void us_ticker_init(void) { + tmr32_cfg_t cfg; + if (us_ticker_inited) { return; } - us_ticker_inited = 1; - current_cnt = 0; - event_cnt = 0xFFFFFFFFFFFFFFFFULL; // reset to max value - ticks_per_us = SystemCoreClock / 1000000; - tick_win = SystemCoreClock / 100; // Set the tick window to 10ms - int retval = TMR_Init(US_TIMER, TMR_PRESCALE_DIV_2_0, NULL); - MBED_ASSERT(retval == E_NO_ERROR); - - tmr32_cfg_t cfg; - cfg.mode = TMR32_MODE_CONTINUOUS; + cfg.mode = US_TIMER_MODE; cfg.polarity = TMR_POLARITY_UNUSED; - cfg.compareCount = 0xFFFFFFFF; + cfg.compareCount = UINT32_MAX; + + TMR_Init(US_TIMER, US_TIMER_PRESCALE, NULL); TMR32_Config(US_TIMER, &cfg); - - NVIC_SetVector(US_TIMER_IRQn, (uint32_t)tmr_handler); + NVIC_SetVector(US_TIMER_IRQn, (uint32_t)us_ticker_irq_handler); NVIC_EnableIRQ(US_TIMER_IRQn); - TMR32_EnableINT(US_TIMER); - TMR32_Start(US_TIMER); } -//****************************************************************************** -void us_ticker_deinit(void) -{ - TMR32_Stop(US_TIMER); - TMR32_DisableINT(US_TIMER); - TMR32_ClearFlag(US_TIMER); - us_ticker_inited = 0; -} - //****************************************************************************** uint32_t us_ticker_read(void) { - uint64_t current_cnt1, current_cnt2; - uint32_t cmp, cnt; - uint32_t flag1, flag2; - static uint32_t last = 0; - if (!us_ticker_inited) { us_ticker_init(); } - // Ensure coherency between current_cnt and TMR32_GetCount() - do { - current_cnt1 = current_cnt; - flag1 = TMR32_GetFlag(US_TIMER); - cmp = TMR32_GetCompare(US_TIMER); - cnt = TMR32_GetCount(US_TIMER); - flag2 = TMR32_GetFlag(US_TIMER); - current_cnt2 = current_cnt; - } while ((current_cnt1 != current_cnt2) || (flag1 != flag2)); - - // Account for an unserviced interrupt - if (flag1) { - // Clear peripheral interrupt flag; leaving NVIC pending set - TMR32_ClearFlag(US_TIMER); - // Advance global count - inc_current_cnt(cmp + cnt); - - current_cnt1 += cmp; - } - - current_cnt1 += cnt; - - assert(last <= (current_cnt1 / ticks_per_us)); - last = (current_cnt1 / ticks_per_us); - return last; + return US_TIMER->count32; } //****************************************************************************** void us_ticker_set_interrupt(timestamp_t timestamp) { - // Note: interrupts are disabled before this function is called. - - TMR32_Stop(US_TIMER); - - if (TMR32_GetFlag(US_TIMER)) { - TMR32_ClearFlag(US_TIMER); - NVIC_ClearPendingIRQ(US_TIMER_IRQn); - inc_current_cnt(TMR32_GetCompare(US_TIMER)); - } - - // add and reset the current count value - inc_current_cnt(TMR32_GetCount(US_TIMER)); - TMR32_SetCount(US_TIMER, 0); - - // add the number of cycles that the timer is disabled here for - inc_current_cnt(200); - - event_cnt = (uint64_t)timestamp * ticks_per_us; - - // Check to see if the event has already passed - if (!event_passed(current_cnt, event_cnt)) { - uint64_t diff = event_diff(current_cnt, event_cnt); - if (diff < (uint64_t)0xFFFFFFFF) { - // the event occurs before the next overflow - TMR32_SetCompare(US_TIMER, diff); - } else { - // the event occurs after the next overflow - TMR32_SetCompare(US_TIMER, 0xFFFFFFFF); // set to max - } - } else { - // the requested timestamp occurs in the past - // set the timer up to immediately expire - TMR32_SetCompare(US_TIMER, 1); - } - - TMR32_Start(US_TIMER); + US_TIMER->ctrl = 0; + US_TIMER->term_cnt32 = timestamp; + US_TIMER->inten = MXC_F_TMR_INTEN_TIMER0; + US_TIMER->ctrl = MXC_F_TMR_CTRL_ENABLE0 | + (US_TIMER_MODE << MXC_F_TMR_CTRL_MODE_POS) | + (US_TIMER_PRESCALE << MXC_F_TMR_CTRL_PRESCALE_POS); } //****************************************************************************** void us_ticker_fire_interrupt(void) { - TMR32_SetCompare(US_TIMER, 1); + NVIC_SetPendingIRQ(US_TIMER_IRQn); } //****************************************************************************** void us_ticker_disable_interrupt(void) { - // There are no more events, set timer overflow to the max - TMR32_SetCompare(US_TIMER, 0xFFFFFFFF); + US_TIMER->inten = 0; } //****************************************************************************** void us_ticker_clear_interrupt(void) { - // cleared in the local handler + US_TIMER->intfl = MXC_F_TMR_INTFL_TIMER0; } //****************************************************************************** -void us_ticker_set(timestamp_t timestamp) +const ticker_info_t* us_ticker_get_info(void) { - TMR32_Stop(US_TIMER); - current_cnt = (uint64_t)timestamp * ticks_per_us; - TMR32_SetCount(US_TIMER, 0); - TMR32_SetCompare(US_TIMER, 0xFFFFFFFF); - TMR32_Start(US_TIMER); + static const ticker_info_t info = { + RO_FREQ >> US_TIMER_PRESCALE, + US_TIMER_WIDTH + }; - if (((uint64_t)timestamp * ticks_per_us) >= event_cnt) { - // The next timestamp has elapsed. Trigger the interrupt to handle it. - NVIC_SetPendingIRQ(US_TIMER_IRQn); - } + return &info; }