Si-Labs EFM32 back up domain and BUrtc library
Diff: BUrtc.cpp
- 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);
+}
+
+