Si-Labs EFM32 back up domain and BUrtc library

Dependents:   EFM32_BUrtc-Demo

Files at this revision

API Documentation at this revision

Comitter:
star297
Date:
Mon May 16 23:12:27 2016 +0000
Commit message:
BUrtc initial release

Changed in this revision

BUrtc.cpp Show annotated file Show diff for this revision Revisions of this file
BUrtc.h Show annotated file Show diff for this revision Revisions of this file
--- /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);
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BUrtc.h	Mon May 16 23:12:27 2016 +0000
@@ -0,0 +1,42 @@
+#ifndef __BUrtc_H
+#define __BUrtc_H
+
+#include "mbed.h"
+#include "em_emu.h"
+#include "em_rmu.h"
+#include "em_burtc.h"
+
+#define UINT32_MAX       4294967295UL
+
+/* This variables must reflect BURTC frequency */
+#define COUNTS_PER_SEC (32768/128)
+/* Clock defines */
+#define LFXO_FREQUENCY 32768
+#define BURTC_PRESCALING 128
+#define UPDATE_INTERVAL 1
+//#define COUNTS_PER_SEC (LFXO_FREQUENCY/BURTC_PRESCALING)
+#define COUNTS_BETWEEN_UPDATE (UPDATE_INTERVAL*COUNTS_PER_SEC)
+
+
+void BUrtcInit(void);
+void budSetup(void);
+void burtcSetup(void);
+void RTCset(int seconds);
+void RTCrestore(void);
+void BURTC_IRQHandler(void);
+void BUrtcBackup(void);
+
+static int burtcCount;
+static int burtcOverflowCounter;
+static int burtcOverflowIntervalRem;
+static int burtcTimestamp;
+static int rtcStartTime;
+static int rtcOverflowCounter;
+static int overflow_interval;
+static int overflow_interval_r;
+
+static int trtc;
+static int lcdUpdate;
+static int resetcause;
+
+#endif