Si-Labs EFM32 back up domain and BUrtc library

Dependents:   EFM32_BUrtc-Demo

Revision:
0:7756f444d879
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BUrtc.cpp	Mon May 16 23:12:27 2016 +0000
@@ -0,0 +1,195 @@
+
+#include "mbed.h"
+#include "BUrtc.h"
+
+void BUrtcInit(void)
+{   
+    // Read and clear RMU->RSTCAUSE as early as possible
+    resetcause = 0;
+    resetcause = RMU->RSTCAUSE;
+    RMU_ResetCauseClear();
+    // power up back up domian
+    budSetup();
+ 
+    // If waking from backup mode, restore time from retention registers
+    if ( !(resetcause & RMU_RSTCAUSE_BUBODBUVIN) && (resetcause & RMU_RSTCAUSE_BUMODERST) ) {
+        // Check if retention registers were being written to when backup mode was entered
+        if ( (BURTC->STATUS & BURTC_STATUS_RAMWERR) >> _BURTC_STATUS_RAMWERR_SHIFT ) {
+        }
+        // Check if timestamp is written
+        if (! ((BURTC->STATUS & BURTC_STATUS_BUMODETS) >> _BURTC_STATUS_BUMODETS_SHIFT) ) {
+        }
+        // Restore time from backup RTC + retention memory
+        RTCrestore();
+        // Reset timestamp
+        BURTC_StatusClear();
+    }
+
+    // If normal startup, initialize BURTC
+    else {
+        // Setup BURTC
+        burtcSetup();
+        set_time(0);
+        // Reset overflow counter
+        rtcOverflowCounter = 0;
+        // Reset BUrtc counter
+        BURTC_CounterReset();        
+        // Backup Reset values to BUrtc retention registers
+        BUrtcBackup();    
+        // Set overflow interval based on counter width and frequency
+        overflow_interval  =  ((uint64_t)UINT32_MAX+1) / COUNTS_PER_SEC; // in seconds
+        overflow_interval_r = ((uint64_t)UINT32_MAX+1) % COUNTS_PER_SEC; // division remainder
+        // Compute overflow interval (integer) and remainder
+        burtcOverflowIntervalRem = ((uint64_t)UINT32_MAX+1)%COUNTS_BETWEEN_UPDATE;
+        // burtcSetComp( COUNTS_BETWEEN_UPDATE );
+        BURTC_CompareSet(0, COUNTS_BETWEEN_UPDATE );                
+    } 
+    // Enable BURTC interrupts   
+    NVIC_ClearPendingIRQ(BURTC_IRQn);
+    NVIC_EnableIRQ(BURTC_IRQn);   
+}
+
+void RTCset(int seconds)
+{  
+    // Set system RTC time
+    set_time(seconds);
+    // Set BUrtc to start from zero
+    BURTC_CounterReset();
+    // Set system RTC epoch offset
+    rtcStartTime = seconds;
+    // reset overflow counter
+    rtcOverflowCounter = 0;
+    // Backup new RTC value to BUrtc retention registers
+    BUrtcBackup();
+    // Compute overflow interval (integer) and remainder
+    burtcOverflowIntervalRem = ((uint64_t)UINT32_MAX+1)%COUNTS_BETWEEN_UPDATE;
+    // burtcSetComp( COUNTS_BETWEEN_UPDATE );
+    BURTC_CompareSet(0, COUNTS_BETWEEN_UPDATE ); 
+}
+
+void BURTC_IRQHandler(void)
+{
+    uint32_t irq;
+    irq = BURTC_IntGet();
+    BURTC_IntClear(irq);
+    //   Interrupt source: compare match
+    //   Increment compare value and
+    //   update TFT display 
+    if ( irq & BURTC_IF_COMP0 ) {
+        BURTC_CompareSet(0, BURTC->COMP0 + COUNTS_BETWEEN_UPDATE );
+    }
+    //   Interrupt source: counter overflow
+    //   Increase overflow counter
+    //   and backup calendar
+    if ( irq & BURTC_IF_OF ) {
+        rtcOverflowCounter++;
+        BUrtcBackup();
+    }   
+}
+
+void BUrtcBackup(void)
+{
+    // Write overflow counter to retention memory
+    BURTC_RetRegSet(0, rtcOverflowCounter);
+    // Write system RTC epoch offset to retention memory
+    BURTC_RetRegSet(1, rtcStartTime);
+}
+
+void RTCrestore(void)  
+{
+    int burtcStart;
+    int nextUpdate;
+    // Store BURTC->CNT for consistency in display output within this function
+    burtcCount = BURTC_CounterGet();
+    // Timestamp is BURTC value at time of main power loss
+    burtcTimestamp = BURTC_TimestampGet();
+    // Read overflow counter from retention memory
+    burtcOverflowCounter = BURTC_RetRegGet(0);
+    //   Check for overflow while in backup mode
+    //   Assume that overflow interval >> backup source capacity
+    //   i.e. that overflow has only occured once during main power loss
+    if ( burtcCount < burtcTimestamp ) {
+        burtcOverflowCounter++;
+    }
+    // Restore epoch offset from retention memory
+    rtcStartTime = (BURTC_RetRegGet(1));
+    // Restore clock overflow counter 
+    rtcOverflowCounter = burtcOverflowCounter;
+    //   Calculate start point for current BURTC count cycle
+    //   If (COUNTS_BETWEEN_UPDATE/burtcOverflowInterval) is not an integer,
+    //   BURTC value at first update is different between each count cycle
+    burtcStart = (burtcOverflowCounter * (COUNTS_BETWEEN_UPDATE - burtcOverflowIntervalRem)) % COUNTS_BETWEEN_UPDATE;
+    //  Calculate next update compare value
+    //  Add 1 extra UPDATE_INTERVAL to be sure that counter doesn't
+    //  pass COMP value before interrupts are enabled 
+    nextUpdate = burtcStart + ((burtcCount / COUNTS_BETWEEN_UPDATE) +1 ) * COUNTS_BETWEEN_UPDATE ;
+    BURTC_CompareSet(0, nextUpdate);
+    // Add the time offset
+    trtc = rtcStartTime;
+    // Add time based on number of counter overflows
+    trtc += rtcOverflowCounter * overflow_interval;
+    // Correct if overflow interval is not an integer
+    if ( overflow_interval_r != 0 )  {
+        trtc += rtcOverflowCounter * overflow_interval_r / COUNTS_PER_SEC;
+    }
+    // Add the number of seconds for BURTC
+    trtc += int(BURTC->CNT / COUNTS_PER_SEC);
+    // Wait to line up next second BUrtc interrupt
+    while(!BURTC_IntGet()){}
+    // restore RTC time
+    set_time (trtc+1);
+}
+
+void burtcSetup(void)
+{
+    BURTC_Init_TypeDef burtcInit = BURTC_INIT_DEFAULT;
+    // Select LFXO as clock source for BURTC
+    burtcInit.clkSel = burtcClkSelLFXO;
+    //Enable BURTC operation in EM0-EM4
+    burtcInit.mode = burtcModeEM4;
+    // Set prescaler to max. Resolution is not that important here
+    burtcInit.clkDiv = 128;
+    // Enable BURTC timestamp upon backup mode entry
+    burtcInit.timeStamp = true;
+    // Counter doesn't wrap around when CNT == COMP0
+    burtcInit.compare0Top = false;
+    burtcInit.enable = true;
+    // Enable interrupt on compare match
+    BURTC_IntClear(BURTC_IEN_COMP0);
+    BURTC_IntEnable(BURTC_IEN_COMP0);
+    BURTC_Init(&burtcInit);
+}
+
+void budSetup(void )
+{
+    EMU_EM4Init_TypeDef em4Init = EMU_EM4INIT_DEFAULT;
+    EMU_BUPDInit_TypeDef bupdInit = EMU_BUPDINIT_DEFAULT;
+    // Unlock configuration
+    EMU_EM4Lock(false);
+    //Enable backup status pin
+    bupdInit.statusPinEnable = false;
+    // Enable backup power domain
+    bupdInit.enable = true;
+    // Normal operation: Connect main power to backup power through diode
+    bupdInit.inactivePower = emuPower_MainBU;
+    // Backup mode: No connection between backup power and main power
+    bupdInit.activePower = emuPower_None;
+    // Set backup "charging" resistor
+    bupdInit.resistor = emuRes_Res3;
+    EMU_BUPDInit(&bupdInit);
+    // Wait until backup power functionality is ready
+    EMU_BUReady();
+    // Release reset for backup domain
+    RMU_ResetControl(rmuResetBU, rmuResetModeClear);
+    // Enable BU_VIN pin
+    bupdInit.enable = true;
+    // Enable voltage regulator in backup mode
+    em4Init.vreg = true;
+    // Configure oscillators in EM4
+    em4Init.osc = emuEM4Osc_LFXO;
+    // Lock configuration in case of brown out
+    em4Init.lockConfig = true;
+    EMU_EM4Init(&em4Init);
+}
+
+