Si-Labs EFM32 back up domain and BUrtc library
BUrtc.cpp@0:7756f444d879, 2016-05-16 (annotated)
- Committer:
- star297
- Date:
- Mon May 16 23:12:27 2016 +0000
- Revision:
- 0:7756f444d879
BUrtc initial release
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
star297 | 0:7756f444d879 | 1 | |
star297 | 0:7756f444d879 | 2 | #include "mbed.h" |
star297 | 0:7756f444d879 | 3 | #include "BUrtc.h" |
star297 | 0:7756f444d879 | 4 | |
star297 | 0:7756f444d879 | 5 | void BUrtcInit(void) |
star297 | 0:7756f444d879 | 6 | { |
star297 | 0:7756f444d879 | 7 | // Read and clear RMU->RSTCAUSE as early as possible |
star297 | 0:7756f444d879 | 8 | resetcause = 0; |
star297 | 0:7756f444d879 | 9 | resetcause = RMU->RSTCAUSE; |
star297 | 0:7756f444d879 | 10 | RMU_ResetCauseClear(); |
star297 | 0:7756f444d879 | 11 | // power up back up domian |
star297 | 0:7756f444d879 | 12 | budSetup(); |
star297 | 0:7756f444d879 | 13 | |
star297 | 0:7756f444d879 | 14 | // If waking from backup mode, restore time from retention registers |
star297 | 0:7756f444d879 | 15 | if ( !(resetcause & RMU_RSTCAUSE_BUBODBUVIN) && (resetcause & RMU_RSTCAUSE_BUMODERST) ) { |
star297 | 0:7756f444d879 | 16 | // Check if retention registers were being written to when backup mode was entered |
star297 | 0:7756f444d879 | 17 | if ( (BURTC->STATUS & BURTC_STATUS_RAMWERR) >> _BURTC_STATUS_RAMWERR_SHIFT ) { |
star297 | 0:7756f444d879 | 18 | } |
star297 | 0:7756f444d879 | 19 | // Check if timestamp is written |
star297 | 0:7756f444d879 | 20 | if (! ((BURTC->STATUS & BURTC_STATUS_BUMODETS) >> _BURTC_STATUS_BUMODETS_SHIFT) ) { |
star297 | 0:7756f444d879 | 21 | } |
star297 | 0:7756f444d879 | 22 | // Restore time from backup RTC + retention memory |
star297 | 0:7756f444d879 | 23 | RTCrestore(); |
star297 | 0:7756f444d879 | 24 | // Reset timestamp |
star297 | 0:7756f444d879 | 25 | BURTC_StatusClear(); |
star297 | 0:7756f444d879 | 26 | } |
star297 | 0:7756f444d879 | 27 | |
star297 | 0:7756f444d879 | 28 | // If normal startup, initialize BURTC |
star297 | 0:7756f444d879 | 29 | else { |
star297 | 0:7756f444d879 | 30 | // Setup BURTC |
star297 | 0:7756f444d879 | 31 | burtcSetup(); |
star297 | 0:7756f444d879 | 32 | set_time(0); |
star297 | 0:7756f444d879 | 33 | // Reset overflow counter |
star297 | 0:7756f444d879 | 34 | rtcOverflowCounter = 0; |
star297 | 0:7756f444d879 | 35 | // Reset BUrtc counter |
star297 | 0:7756f444d879 | 36 | BURTC_CounterReset(); |
star297 | 0:7756f444d879 | 37 | // Backup Reset values to BUrtc retention registers |
star297 | 0:7756f444d879 | 38 | BUrtcBackup(); |
star297 | 0:7756f444d879 | 39 | // Set overflow interval based on counter width and frequency |
star297 | 0:7756f444d879 | 40 | overflow_interval = ((uint64_t)UINT32_MAX+1) / COUNTS_PER_SEC; // in seconds |
star297 | 0:7756f444d879 | 41 | overflow_interval_r = ((uint64_t)UINT32_MAX+1) % COUNTS_PER_SEC; // division remainder |
star297 | 0:7756f444d879 | 42 | // Compute overflow interval (integer) and remainder |
star297 | 0:7756f444d879 | 43 | burtcOverflowIntervalRem = ((uint64_t)UINT32_MAX+1)%COUNTS_BETWEEN_UPDATE; |
star297 | 0:7756f444d879 | 44 | // burtcSetComp( COUNTS_BETWEEN_UPDATE ); |
star297 | 0:7756f444d879 | 45 | BURTC_CompareSet(0, COUNTS_BETWEEN_UPDATE ); |
star297 | 0:7756f444d879 | 46 | } |
star297 | 0:7756f444d879 | 47 | // Enable BURTC interrupts |
star297 | 0:7756f444d879 | 48 | NVIC_ClearPendingIRQ(BURTC_IRQn); |
star297 | 0:7756f444d879 | 49 | NVIC_EnableIRQ(BURTC_IRQn); |
star297 | 0:7756f444d879 | 50 | } |
star297 | 0:7756f444d879 | 51 | |
star297 | 0:7756f444d879 | 52 | void RTCset(int seconds) |
star297 | 0:7756f444d879 | 53 | { |
star297 | 0:7756f444d879 | 54 | // Set system RTC time |
star297 | 0:7756f444d879 | 55 | set_time(seconds); |
star297 | 0:7756f444d879 | 56 | // Set BUrtc to start from zero |
star297 | 0:7756f444d879 | 57 | BURTC_CounterReset(); |
star297 | 0:7756f444d879 | 58 | // Set system RTC epoch offset |
star297 | 0:7756f444d879 | 59 | rtcStartTime = seconds; |
star297 | 0:7756f444d879 | 60 | // reset overflow counter |
star297 | 0:7756f444d879 | 61 | rtcOverflowCounter = 0; |
star297 | 0:7756f444d879 | 62 | // Backup new RTC value to BUrtc retention registers |
star297 | 0:7756f444d879 | 63 | BUrtcBackup(); |
star297 | 0:7756f444d879 | 64 | // Compute overflow interval (integer) and remainder |
star297 | 0:7756f444d879 | 65 | burtcOverflowIntervalRem = ((uint64_t)UINT32_MAX+1)%COUNTS_BETWEEN_UPDATE; |
star297 | 0:7756f444d879 | 66 | // burtcSetComp( COUNTS_BETWEEN_UPDATE ); |
star297 | 0:7756f444d879 | 67 | BURTC_CompareSet(0, COUNTS_BETWEEN_UPDATE ); |
star297 | 0:7756f444d879 | 68 | } |
star297 | 0:7756f444d879 | 69 | |
star297 | 0:7756f444d879 | 70 | void BURTC_IRQHandler(void) |
star297 | 0:7756f444d879 | 71 | { |
star297 | 0:7756f444d879 | 72 | uint32_t irq; |
star297 | 0:7756f444d879 | 73 | irq = BURTC_IntGet(); |
star297 | 0:7756f444d879 | 74 | BURTC_IntClear(irq); |
star297 | 0:7756f444d879 | 75 | // Interrupt source: compare match |
star297 | 0:7756f444d879 | 76 | // Increment compare value and |
star297 | 0:7756f444d879 | 77 | // update TFT display |
star297 | 0:7756f444d879 | 78 | if ( irq & BURTC_IF_COMP0 ) { |
star297 | 0:7756f444d879 | 79 | BURTC_CompareSet(0, BURTC->COMP0 + COUNTS_BETWEEN_UPDATE ); |
star297 | 0:7756f444d879 | 80 | } |
star297 | 0:7756f444d879 | 81 | // Interrupt source: counter overflow |
star297 | 0:7756f444d879 | 82 | // Increase overflow counter |
star297 | 0:7756f444d879 | 83 | // and backup calendar |
star297 | 0:7756f444d879 | 84 | if ( irq & BURTC_IF_OF ) { |
star297 | 0:7756f444d879 | 85 | rtcOverflowCounter++; |
star297 | 0:7756f444d879 | 86 | BUrtcBackup(); |
star297 | 0:7756f444d879 | 87 | } |
star297 | 0:7756f444d879 | 88 | } |
star297 | 0:7756f444d879 | 89 | |
star297 | 0:7756f444d879 | 90 | void BUrtcBackup(void) |
star297 | 0:7756f444d879 | 91 | { |
star297 | 0:7756f444d879 | 92 | // Write overflow counter to retention memory |
star297 | 0:7756f444d879 | 93 | BURTC_RetRegSet(0, rtcOverflowCounter); |
star297 | 0:7756f444d879 | 94 | // Write system RTC epoch offset to retention memory |
star297 | 0:7756f444d879 | 95 | BURTC_RetRegSet(1, rtcStartTime); |
star297 | 0:7756f444d879 | 96 | } |
star297 | 0:7756f444d879 | 97 | |
star297 | 0:7756f444d879 | 98 | void RTCrestore(void) |
star297 | 0:7756f444d879 | 99 | { |
star297 | 0:7756f444d879 | 100 | int burtcStart; |
star297 | 0:7756f444d879 | 101 | int nextUpdate; |
star297 | 0:7756f444d879 | 102 | // Store BURTC->CNT for consistency in display output within this function |
star297 | 0:7756f444d879 | 103 | burtcCount = BURTC_CounterGet(); |
star297 | 0:7756f444d879 | 104 | // Timestamp is BURTC value at time of main power loss |
star297 | 0:7756f444d879 | 105 | burtcTimestamp = BURTC_TimestampGet(); |
star297 | 0:7756f444d879 | 106 | // Read overflow counter from retention memory |
star297 | 0:7756f444d879 | 107 | burtcOverflowCounter = BURTC_RetRegGet(0); |
star297 | 0:7756f444d879 | 108 | // Check for overflow while in backup mode |
star297 | 0:7756f444d879 | 109 | // Assume that overflow interval >> backup source capacity |
star297 | 0:7756f444d879 | 110 | // i.e. that overflow has only occured once during main power loss |
star297 | 0:7756f444d879 | 111 | if ( burtcCount < burtcTimestamp ) { |
star297 | 0:7756f444d879 | 112 | burtcOverflowCounter++; |
star297 | 0:7756f444d879 | 113 | } |
star297 | 0:7756f444d879 | 114 | // Restore epoch offset from retention memory |
star297 | 0:7756f444d879 | 115 | rtcStartTime = (BURTC_RetRegGet(1)); |
star297 | 0:7756f444d879 | 116 | // Restore clock overflow counter |
star297 | 0:7756f444d879 | 117 | rtcOverflowCounter = burtcOverflowCounter; |
star297 | 0:7756f444d879 | 118 | // Calculate start point for current BURTC count cycle |
star297 | 0:7756f444d879 | 119 | // If (COUNTS_BETWEEN_UPDATE/burtcOverflowInterval) is not an integer, |
star297 | 0:7756f444d879 | 120 | // BURTC value at first update is different between each count cycle |
star297 | 0:7756f444d879 | 121 | burtcStart = (burtcOverflowCounter * (COUNTS_BETWEEN_UPDATE - burtcOverflowIntervalRem)) % COUNTS_BETWEEN_UPDATE; |
star297 | 0:7756f444d879 | 122 | // Calculate next update compare value |
star297 | 0:7756f444d879 | 123 | // Add 1 extra UPDATE_INTERVAL to be sure that counter doesn't |
star297 | 0:7756f444d879 | 124 | // pass COMP value before interrupts are enabled |
star297 | 0:7756f444d879 | 125 | nextUpdate = burtcStart + ((burtcCount / COUNTS_BETWEEN_UPDATE) +1 ) * COUNTS_BETWEEN_UPDATE ; |
star297 | 0:7756f444d879 | 126 | BURTC_CompareSet(0, nextUpdate); |
star297 | 0:7756f444d879 | 127 | // Add the time offset |
star297 | 0:7756f444d879 | 128 | trtc = rtcStartTime; |
star297 | 0:7756f444d879 | 129 | // Add time based on number of counter overflows |
star297 | 0:7756f444d879 | 130 | trtc += rtcOverflowCounter * overflow_interval; |
star297 | 0:7756f444d879 | 131 | // Correct if overflow interval is not an integer |
star297 | 0:7756f444d879 | 132 | if ( overflow_interval_r != 0 ) { |
star297 | 0:7756f444d879 | 133 | trtc += rtcOverflowCounter * overflow_interval_r / COUNTS_PER_SEC; |
star297 | 0:7756f444d879 | 134 | } |
star297 | 0:7756f444d879 | 135 | // Add the number of seconds for BURTC |
star297 | 0:7756f444d879 | 136 | trtc += int(BURTC->CNT / COUNTS_PER_SEC); |
star297 | 0:7756f444d879 | 137 | // Wait to line up next second BUrtc interrupt |
star297 | 0:7756f444d879 | 138 | while(!BURTC_IntGet()){} |
star297 | 0:7756f444d879 | 139 | // restore RTC time |
star297 | 0:7756f444d879 | 140 | set_time (trtc+1); |
star297 | 0:7756f444d879 | 141 | } |
star297 | 0:7756f444d879 | 142 | |
star297 | 0:7756f444d879 | 143 | void burtcSetup(void) |
star297 | 0:7756f444d879 | 144 | { |
star297 | 0:7756f444d879 | 145 | BURTC_Init_TypeDef burtcInit = BURTC_INIT_DEFAULT; |
star297 | 0:7756f444d879 | 146 | // Select LFXO as clock source for BURTC |
star297 | 0:7756f444d879 | 147 | burtcInit.clkSel = burtcClkSelLFXO; |
star297 | 0:7756f444d879 | 148 | //Enable BURTC operation in EM0-EM4 |
star297 | 0:7756f444d879 | 149 | burtcInit.mode = burtcModeEM4; |
star297 | 0:7756f444d879 | 150 | // Set prescaler to max. Resolution is not that important here |
star297 | 0:7756f444d879 | 151 | burtcInit.clkDiv = 128; |
star297 | 0:7756f444d879 | 152 | // Enable BURTC timestamp upon backup mode entry |
star297 | 0:7756f444d879 | 153 | burtcInit.timeStamp = true; |
star297 | 0:7756f444d879 | 154 | // Counter doesn't wrap around when CNT == COMP0 |
star297 | 0:7756f444d879 | 155 | burtcInit.compare0Top = false; |
star297 | 0:7756f444d879 | 156 | burtcInit.enable = true; |
star297 | 0:7756f444d879 | 157 | // Enable interrupt on compare match |
star297 | 0:7756f444d879 | 158 | BURTC_IntClear(BURTC_IEN_COMP0); |
star297 | 0:7756f444d879 | 159 | BURTC_IntEnable(BURTC_IEN_COMP0); |
star297 | 0:7756f444d879 | 160 | BURTC_Init(&burtcInit); |
star297 | 0:7756f444d879 | 161 | } |
star297 | 0:7756f444d879 | 162 | |
star297 | 0:7756f444d879 | 163 | void budSetup(void ) |
star297 | 0:7756f444d879 | 164 | { |
star297 | 0:7756f444d879 | 165 | EMU_EM4Init_TypeDef em4Init = EMU_EM4INIT_DEFAULT; |
star297 | 0:7756f444d879 | 166 | EMU_BUPDInit_TypeDef bupdInit = EMU_BUPDINIT_DEFAULT; |
star297 | 0:7756f444d879 | 167 | // Unlock configuration |
star297 | 0:7756f444d879 | 168 | EMU_EM4Lock(false); |
star297 | 0:7756f444d879 | 169 | //Enable backup status pin |
star297 | 0:7756f444d879 | 170 | bupdInit.statusPinEnable = false; |
star297 | 0:7756f444d879 | 171 | // Enable backup power domain |
star297 | 0:7756f444d879 | 172 | bupdInit.enable = true; |
star297 | 0:7756f444d879 | 173 | // Normal operation: Connect main power to backup power through diode |
star297 | 0:7756f444d879 | 174 | bupdInit.inactivePower = emuPower_MainBU; |
star297 | 0:7756f444d879 | 175 | // Backup mode: No connection between backup power and main power |
star297 | 0:7756f444d879 | 176 | bupdInit.activePower = emuPower_None; |
star297 | 0:7756f444d879 | 177 | // Set backup "charging" resistor |
star297 | 0:7756f444d879 | 178 | bupdInit.resistor = emuRes_Res3; |
star297 | 0:7756f444d879 | 179 | EMU_BUPDInit(&bupdInit); |
star297 | 0:7756f444d879 | 180 | // Wait until backup power functionality is ready |
star297 | 0:7756f444d879 | 181 | EMU_BUReady(); |
star297 | 0:7756f444d879 | 182 | // Release reset for backup domain |
star297 | 0:7756f444d879 | 183 | RMU_ResetControl(rmuResetBU, rmuResetModeClear); |
star297 | 0:7756f444d879 | 184 | // Enable BU_VIN pin |
star297 | 0:7756f444d879 | 185 | bupdInit.enable = true; |
star297 | 0:7756f444d879 | 186 | // Enable voltage regulator in backup mode |
star297 | 0:7756f444d879 | 187 | em4Init.vreg = true; |
star297 | 0:7756f444d879 | 188 | // Configure oscillators in EM4 |
star297 | 0:7756f444d879 | 189 | em4Init.osc = emuEM4Osc_LFXO; |
star297 | 0:7756f444d879 | 190 | // Lock configuration in case of brown out |
star297 | 0:7756f444d879 | 191 | em4Init.lockConfig = true; |
star297 | 0:7756f444d879 | 192 | EMU_EM4Init(&em4Init); |
star297 | 0:7756f444d879 | 193 | } |
star297 | 0:7756f444d879 | 194 | |
star297 | 0:7756f444d879 | 195 |