Si-Labs EFM32 back up domain and BUrtc library
BUrtc.cpp
- Committer:
- star297
- Date:
- 2016-05-16
- Revision:
- 0:7756f444d879
File content as of revision 0:7756f444d879:
#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); }