mbed library sources. Supersedes mbed-src.

Dependents:   Nucleo_Hello_Encoder BLE_iBeaconScan AM1805_DEMO DISCO-F429ZI_ExportTemplate1 ... more

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;
 }