Si-Labs EFM32 back up domain and BUrtc library
Revision 0:7756f444d879, committed 2016-05-16
- 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