Si-Labs EFM32 back up domain and BUrtc library

Dependents:   EFM32_BUrtc-Demo

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);
}