mbed library sources. Supersedes mbed-src. Fixed broken STM32F1xx RTC on rtc_api.c
Dependents: Nucleo_F103RB_RTC_battery_bkup_pwr_off_okay
Fork of mbed-dev by
targets/TARGET_ublox/TARGET_HI2110/lp_ticker.c@150:02e0a0aed4ec, 2016-11-08 (annotated)
- Committer:
- <>
- Date:
- Tue Nov 08 17:45:16 2016 +0000
- Revision:
- 150:02e0a0aed4ec
- Child:
- 160:d5399cc887bb
This updates the lib to the mbed lib v129
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
<> | 150:02e0a0aed4ec | 1 | /* mbed Microcontroller Library |
<> | 150:02e0a0aed4ec | 2 | * Copyright (c) 2016 u-blox |
<> | 150:02e0a0aed4ec | 3 | * |
<> | 150:02e0a0aed4ec | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
<> | 150:02e0a0aed4ec | 5 | * you may not use this file except in compliance with the License. |
<> | 150:02e0a0aed4ec | 6 | * You may obtain a copy of the License at |
<> | 150:02e0a0aed4ec | 7 | * |
<> | 150:02e0a0aed4ec | 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
<> | 150:02e0a0aed4ec | 9 | * |
<> | 150:02e0a0aed4ec | 10 | * Unless required by applicable law or agreed to in writing, software |
<> | 150:02e0a0aed4ec | 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
<> | 150:02e0a0aed4ec | 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
<> | 150:02e0a0aed4ec | 13 | * See the License for the specific language governing permissions and |
<> | 150:02e0a0aed4ec | 14 | * limitations under the License. |
<> | 150:02e0a0aed4ec | 15 | */ |
<> | 150:02e0a0aed4ec | 16 | |
<> | 150:02e0a0aed4ec | 17 | /* The LP Ticker performs two functions for mbed: |
<> | 150:02e0a0aed4ec | 18 | * |
<> | 150:02e0a0aed4ec | 19 | * 1. Allows tracking of the passage of time. |
<> | 150:02e0a0aed4ec | 20 | * 2. Allows the system to enter the lowest power |
<> | 150:02e0a0aed4ec | 21 | * state for a given time. |
<> | 150:02e0a0aed4ec | 22 | * |
<> | 150:02e0a0aed4ec | 23 | * For this to work the single RTC interrupt needs |
<> | 150:02e0a0aed4ec | 24 | * to perform two functions. It needs to increment |
<> | 150:02e0a0aed4ec | 25 | * an overflow counter at every 32-bit overflow without |
<> | 150:02e0a0aed4ec | 26 | * otherwise affecting the system state (i.e. not waking it |
<> | 150:02e0a0aed4ec | 27 | * up and not putting it to sleep) and, when requested, |
<> | 150:02e0a0aed4ec | 28 | * it *also* needs to wake the system up from sleep |
<> | 150:02e0a0aed4ec | 29 | * at a specific time. Note also that the units of time |
<> | 150:02e0a0aed4ec | 30 | * from an mbed perspective are useconds, whereas the RTC |
<> | 150:02e0a0aed4ec | 31 | * is clocked at 32 kHz, hence there is conversion to be done. |
<> | 150:02e0a0aed4ec | 32 | * |
<> | 150:02e0a0aed4ec | 33 | * Since it is not possible to reset the RTC, we maintain |
<> | 150:02e0a0aed4ec | 34 | * a 32-bit window on it, starting at g_last_32bit_overflow_value |
<> | 150:02e0a0aed4ec | 35 | * and ending at g_next_32bit_overflow_value. All values |
<> | 150:02e0a0aed4ec | 36 | * fed back up to mbed are relative to g_last_32bit_overflow_value. |
<> | 150:02e0a0aed4ec | 37 | */ |
<> | 150:02e0a0aed4ec | 38 | |
<> | 150:02e0a0aed4ec | 39 | #include "lp_ticker_api.h" |
<> | 150:02e0a0aed4ec | 40 | #include "sleep_api.h" |
<> | 150:02e0a0aed4ec | 41 | #include "critical.h" |
<> | 150:02e0a0aed4ec | 42 | |
<> | 150:02e0a0aed4ec | 43 | /* ---------------------------------------------------------------- |
<> | 150:02e0a0aed4ec | 44 | * MACROS |
<> | 150:02e0a0aed4ec | 45 | * ----------------------------------------------------------------*/ |
<> | 150:02e0a0aed4ec | 46 | |
<> | 150:02e0a0aed4ec | 47 | /* The maximum value of the RTC (48 bits) */ |
<> | 150:02e0a0aed4ec | 48 | #define RTC_MAX 0x0000FFFFFFFFFFFFULL |
<> | 150:02e0a0aed4ec | 49 | |
<> | 150:02e0a0aed4ec | 50 | /* RTC modulo */ |
<> | 150:02e0a0aed4ec | 51 | #define RTC_MODULO (RTC_MAX + 1) |
<> | 150:02e0a0aed4ec | 52 | |
<> | 150:02e0a0aed4ec | 53 | /* The 32-bit overflow value */ |
<> | 150:02e0a0aed4ec | 54 | #define MODULO_32BIT 0x100000000ULL |
<> | 150:02e0a0aed4ec | 55 | |
<> | 150:02e0a0aed4ec | 56 | /* Macro to increment a 64-bit RTC value x by y, with wrap */ |
<> | 150:02e0a0aed4ec | 57 | #define INCREMENT_MOD(x, y) (x = ((uint64_t) x + (uint64_t) y) % RTC_MODULO) |
<> | 150:02e0a0aed4ec | 58 | |
<> | 150:02e0a0aed4ec | 59 | /* Macro to get MSBs from a 64-bit integer */ |
<> | 150:02e0a0aed4ec | 60 | #define MSBS(x) ((uint32_t) ((uint64_t) (x) >> 32)) |
<> | 150:02e0a0aed4ec | 61 | |
<> | 150:02e0a0aed4ec | 62 | /* Macro to get LSBs from a 64-bit integer */ |
<> | 150:02e0a0aed4ec | 63 | #define LSBS(x) ((uint32_t) (x)) |
<> | 150:02e0a0aed4ec | 64 | |
<> | 150:02e0a0aed4ec | 65 | /* ---------------------------------------------------------------- |
<> | 150:02e0a0aed4ec | 66 | * TYPES |
<> | 150:02e0a0aed4ec | 67 | * ----------------------------------------------------------------*/ |
<> | 150:02e0a0aed4ec | 68 | |
<> | 150:02e0a0aed4ec | 69 | /* ---------------------------------------------------------------- |
<> | 150:02e0a0aed4ec | 70 | * GLOBAL VARIABLES |
<> | 150:02e0a0aed4ec | 71 | * ----------------------------------------------------------------*/ |
<> | 150:02e0a0aed4ec | 72 | |
<> | 150:02e0a0aed4ec | 73 | /* Incremented each time the RTC goes over 32 bits */ |
<> | 150:02e0a0aed4ec | 74 | static uint32_t g_overflow_count = 0; |
<> | 150:02e0a0aed4ec | 75 | |
<> | 150:02e0a0aed4ec | 76 | /* Set when a user interrupt has been requested but an overflow |
<> | 150:02e0a0aed4ec | 77 | * interrupt needs to happen first */ |
<> | 150:02e0a0aed4ec | 78 | static bool g_user_interrupt_pending = false; |
<> | 150:02e0a0aed4ec | 79 | |
<> | 150:02e0a0aed4ec | 80 | /* Set when a user interrupt is the next interrupt to happen */ |
<> | 150:02e0a0aed4ec | 81 | static bool g_user_interrupt_set = false; |
<> | 150:02e0a0aed4ec | 82 | |
<> | 150:02e0a0aed4ec | 83 | /* Initialised flag, used to protect against interrupts going |
<> | 150:02e0a0aed4ec | 84 | * off before we're initialised */ |
<> | 150:02e0a0aed4ec | 85 | static bool g_initialised = false; |
<> | 150:02e0a0aed4ec | 86 | |
<> | 150:02e0a0aed4ec | 87 | /* The next overflow value to be used */ |
<> | 150:02e0a0aed4ec | 88 | static uint64_t g_next_32bit_overflow_value; |
<> | 150:02e0a0aed4ec | 89 | |
<> | 150:02e0a0aed4ec | 90 | /* The next match-compare value to be used */ |
<> | 150:02e0a0aed4ec | 91 | static uint64_t g_next_compare_value; |
<> | 150:02e0a0aed4ec | 92 | |
<> | 150:02e0a0aed4ec | 93 | /* Keep track of the previous 32-bit overflow |
<> | 150:02e0a0aed4ec | 94 | * value so that we can report 32-bit time |
<> | 150:02e0a0aed4ec | 95 | * correctly */ |
<> | 150:02e0a0aed4ec | 96 | static uint64_t g_last_32bit_overflow_value; |
<> | 150:02e0a0aed4ec | 97 | |
<> | 150:02e0a0aed4ec | 98 | /* ---------------------------------------------------------------- |
<> | 150:02e0a0aed4ec | 99 | * FUNCTION PROTOTYPES |
<> | 150:02e0a0aed4ec | 100 | * ----------------------------------------------------------------*/ |
<> | 150:02e0a0aed4ec | 101 | |
<> | 150:02e0a0aed4ec | 102 | static void set_interrupt_to_32bit_overflow(void); |
<> | 150:02e0a0aed4ec | 103 | static void set_interrupt_to_user_value(void); |
<> | 150:02e0a0aed4ec | 104 | |
<> | 150:02e0a0aed4ec | 105 | /* ---------------------------------------------------------------- |
<> | 150:02e0a0aed4ec | 106 | * STATIC FUNCTIONS |
<> | 150:02e0a0aed4ec | 107 | * ----------------------------------------------------------------*/ |
<> | 150:02e0a0aed4ec | 108 | |
<> | 150:02e0a0aed4ec | 109 | /* Convert a tick value (32,768 Hz) into a microsecond value */ |
<> | 150:02e0a0aed4ec | 110 | static inline uint32_t ticksToUSeconds(uint32_t x) |
<> | 150:02e0a0aed4ec | 111 | { |
<> | 150:02e0a0aed4ec | 112 | /* TODO: find a way to avoid the multiply by 1000000 |
<> | 150:02e0a0aed4ec | 113 | * Shift by 20 would introduce a 5% error, which is |
<> | 150:02e0a0aed4ec | 114 | * probably too much */ |
<> | 150:02e0a0aed4ec | 115 | uint64_t result = ((((uint64_t) x) * 1000000) >> 15); |
<> | 150:02e0a0aed4ec | 116 | |
<> | 150:02e0a0aed4ec | 117 | if (result > 0xFFFFFFFF) { |
<> | 150:02e0a0aed4ec | 118 | result = 0xFFFFFFFF; |
<> | 150:02e0a0aed4ec | 119 | } |
<> | 150:02e0a0aed4ec | 120 | |
<> | 150:02e0a0aed4ec | 121 | return (uint32_t) result; |
<> | 150:02e0a0aed4ec | 122 | } |
<> | 150:02e0a0aed4ec | 123 | |
<> | 150:02e0a0aed4ec | 124 | /* Convert a microsecond value into a tick value (32,768 Hz) */ |
<> | 150:02e0a0aed4ec | 125 | static inline uint32_t uSecondsToTicks(uint32_t x) |
<> | 150:02e0a0aed4ec | 126 | { |
<> | 150:02e0a0aed4ec | 127 | /* TODO: find a way to avoid the divide by 1000000 |
<> | 150:02e0a0aed4ec | 128 | * Shift by 20 would introduce a 5% error, which is |
<> | 150:02e0a0aed4ec | 129 | * probably too much */ |
<> | 150:02e0a0aed4ec | 130 | return (uint32_t) ((((uint64_t) x) << 15) / 1000000); |
<> | 150:02e0a0aed4ec | 131 | } |
<> | 150:02e0a0aed4ec | 132 | |
<> | 150:02e0a0aed4ec | 133 | /* Take g_next_32bit_overflow_value and apply it to g_next_compare_value and |
<> | 150:02e0a0aed4ec | 134 | * then the chip registers |
<> | 150:02e0a0aed4ec | 135 | * NOTE: the RTC interrupt should be disabled when calling this function */ |
<> | 150:02e0a0aed4ec | 136 | static inline void set_interrupt_to_32bit_overflow() |
<> | 150:02e0a0aed4ec | 137 | { |
<> | 150:02e0a0aed4ec | 138 | /* Load up the values */ |
<> | 150:02e0a0aed4ec | 139 | g_next_compare_value = g_next_32bit_overflow_value; |
<> | 150:02e0a0aed4ec | 140 | |
<> | 150:02e0a0aed4ec | 141 | /* Set up the match register values */ |
<> | 150:02e0a0aed4ec | 142 | RTC_IRQ_TIME_MSBS = MSBS(g_next_compare_value); |
<> | 150:02e0a0aed4ec | 143 | RTC_IRQ_TIME_LSBS = LSBS(g_next_compare_value); |
<> | 150:02e0a0aed4ec | 144 | } |
<> | 150:02e0a0aed4ec | 145 | |
<> | 150:02e0a0aed4ec | 146 | /* Take g_next_compare_value and apply it to the chip registers |
<> | 150:02e0a0aed4ec | 147 | * NOTE: the RTC interrupt should be disabled when calling this function */ |
<> | 150:02e0a0aed4ec | 148 | static inline void set_interrupt_to_user_value() |
<> | 150:02e0a0aed4ec | 149 | { |
<> | 150:02e0a0aed4ec | 150 | g_user_interrupt_set = true; |
<> | 150:02e0a0aed4ec | 151 | |
<> | 150:02e0a0aed4ec | 152 | /* Write MSBS first, then the value is latched on LSBS write */ |
<> | 150:02e0a0aed4ec | 153 | RTC_IRQ_TIME_MSBS = MSBS(g_next_compare_value); |
<> | 150:02e0a0aed4ec | 154 | RTC_IRQ_TIME_LSBS = LSBS(g_next_compare_value); |
<> | 150:02e0a0aed4ec | 155 | } |
<> | 150:02e0a0aed4ec | 156 | |
<> | 150:02e0a0aed4ec | 157 | /* Get the RTC value |
<> | 150:02e0a0aed4ec | 158 | * NOTE: the RTC interrupt should be disabled when calling this function */ |
<> | 150:02e0a0aed4ec | 159 | static inline uint64_t get_rtc_value() |
<> | 150:02e0a0aed4ec | 160 | { |
<> | 150:02e0a0aed4ec | 161 | uint64_t rtc_value; |
<> | 150:02e0a0aed4ec | 162 | |
<> | 150:02e0a0aed4ec | 163 | rtc_value = ((uint64_t) RTC_TIME_MSBS) << 32; |
<> | 150:02e0a0aed4ec | 164 | rtc_value |= RTC_TIME_LSBS; |
<> | 150:02e0a0aed4ec | 165 | |
<> | 150:02e0a0aed4ec | 166 | return rtc_value; |
<> | 150:02e0a0aed4ec | 167 | } |
<> | 150:02e0a0aed4ec | 168 | |
<> | 150:02e0a0aed4ec | 169 | /* ---------------------------------------------------------------- |
<> | 150:02e0a0aed4ec | 170 | * NON-API FUNCTIONS |
<> | 150:02e0a0aed4ec | 171 | * ----------------------------------------------------------------*/ |
<> | 150:02e0a0aed4ec | 172 | |
<> | 150:02e0a0aed4ec | 173 | /* RTC handler */ |
<> | 150:02e0a0aed4ec | 174 | void IRQ0_RTC_Handler(void) |
<> | 150:02e0a0aed4ec | 175 | { |
<> | 150:02e0a0aed4ec | 176 | /* Have seen this interrupt occurring before initialisation, so guard |
<> | 150:02e0a0aed4ec | 177 | * against that */ |
<> | 150:02e0a0aed4ec | 178 | if (g_initialised) { |
<> | 150:02e0a0aed4ec | 179 | if (g_user_interrupt_pending) { |
<> | 150:02e0a0aed4ec | 180 | /* If there was a user interrupt pending, set it now */ |
<> | 150:02e0a0aed4ec | 181 | set_interrupt_to_user_value(); |
<> | 150:02e0a0aed4ec | 182 | |
<> | 150:02e0a0aed4ec | 183 | /* Reset the pending flag */ |
<> | 150:02e0a0aed4ec | 184 | g_user_interrupt_pending = false; |
<> | 150:02e0a0aed4ec | 185 | |
<> | 150:02e0a0aed4ec | 186 | /* This must have been a 32-bit overflow interrupt so |
<> | 150:02e0a0aed4ec | 187 | * increment the count */ |
<> | 150:02e0a0aed4ec | 188 | g_overflow_count++; |
<> | 150:02e0a0aed4ec | 189 | g_last_32bit_overflow_value = g_next_32bit_overflow_value; |
<> | 150:02e0a0aed4ec | 190 | INCREMENT_MOD(g_next_32bit_overflow_value, MODULO_32BIT); |
<> | 150:02e0a0aed4ec | 191 | } else { |
<> | 150:02e0a0aed4ec | 192 | if (g_user_interrupt_set) { |
<> | 150:02e0a0aed4ec | 193 | /* It's a user interrupt, so wake from sleep but don't |
<> | 150:02e0a0aed4ec | 194 | * increment the overflow count as this is not an |
<> | 150:02e0a0aed4ec | 195 | * overflow interrupt */ |
<> | 150:02e0a0aed4ec | 196 | |
<> | 150:02e0a0aed4ec | 197 | /* Reset the user interrupt flag and call mbed */ |
<> | 150:02e0a0aed4ec | 198 | g_user_interrupt_set = false; |
<> | 150:02e0a0aed4ec | 199 | lp_ticker_irq_handler(); |
<> | 150:02e0a0aed4ec | 200 | } else { |
<> | 150:02e0a0aed4ec | 201 | /* Increment the count as this was a 32-bit overflow |
<> | 150:02e0a0aed4ec | 202 | * interrupt rather than a user interrupt */ |
<> | 150:02e0a0aed4ec | 203 | g_overflow_count++; |
<> | 150:02e0a0aed4ec | 204 | g_last_32bit_overflow_value = g_next_32bit_overflow_value; |
<> | 150:02e0a0aed4ec | 205 | INCREMENT_MOD(g_next_32bit_overflow_value, MODULO_32BIT); |
<> | 150:02e0a0aed4ec | 206 | } |
<> | 150:02e0a0aed4ec | 207 | |
<> | 150:02e0a0aed4ec | 208 | /* Set the next interrupt to be at the 32-bit overflow */ |
<> | 150:02e0a0aed4ec | 209 | set_interrupt_to_32bit_overflow(); |
<> | 150:02e0a0aed4ec | 210 | } |
<> | 150:02e0a0aed4ec | 211 | } |
<> | 150:02e0a0aed4ec | 212 | |
<> | 150:02e0a0aed4ec | 213 | /* Clear the interrupt */ |
<> | 150:02e0a0aed4ec | 214 | RTC_IRQ_CLR = 0xFFFFFFFF; |
<> | 150:02e0a0aed4ec | 215 | } |
<> | 150:02e0a0aed4ec | 216 | |
<> | 150:02e0a0aed4ec | 217 | /* ---------------------------------------------------------------- |
<> | 150:02e0a0aed4ec | 218 | * MBED API CALLS |
<> | 150:02e0a0aed4ec | 219 | * ----------------------------------------------------------------*/ |
<> | 150:02e0a0aed4ec | 220 | |
<> | 150:02e0a0aed4ec | 221 | /* This will be called once at start of day to get the RTC running */ |
<> | 150:02e0a0aed4ec | 222 | void lp_ticker_init(void) |
<> | 150:02e0a0aed4ec | 223 | { |
<> | 150:02e0a0aed4ec | 224 | if (!g_initialised) { |
<> | 150:02e0a0aed4ec | 225 | /* Reset the overflow count and the flags */ |
<> | 150:02e0a0aed4ec | 226 | g_overflow_count = 0; |
<> | 150:02e0a0aed4ec | 227 | g_user_interrupt_pending = false; |
<> | 150:02e0a0aed4ec | 228 | g_user_interrupt_set = false; |
<> | 150:02e0a0aed4ec | 229 | |
<> | 150:02e0a0aed4ec | 230 | /* Setup the next natural 32-bit overflow value */ |
<> | 150:02e0a0aed4ec | 231 | g_next_32bit_overflow_value = get_rtc_value(); |
<> | 150:02e0a0aed4ec | 232 | g_last_32bit_overflow_value = g_next_32bit_overflow_value; |
<> | 150:02e0a0aed4ec | 233 | INCREMENT_MOD(g_next_32bit_overflow_value, MODULO_32BIT); |
<> | 150:02e0a0aed4ec | 234 | |
<> | 150:02e0a0aed4ec | 235 | /* Clear the interrupt */ |
<> | 150:02e0a0aed4ec | 236 | RTC_IRQ_CLR = 0xFFFFFFFF; |
<> | 150:02e0a0aed4ec | 237 | |
<> | 150:02e0a0aed4ec | 238 | /* Interrupt at 32-bit overflow */ |
<> | 150:02e0a0aed4ec | 239 | set_interrupt_to_32bit_overflow(); |
<> | 150:02e0a0aed4ec | 240 | |
<> | 150:02e0a0aed4ec | 241 | /* Enable the interrupt */ |
<> | 150:02e0a0aed4ec | 242 | g_initialised = true; |
<> | 150:02e0a0aed4ec | 243 | NVIC_EnableIRQ(RTC_IRQn); |
<> | 150:02e0a0aed4ec | 244 | } |
<> | 150:02e0a0aed4ec | 245 | } |
<> | 150:02e0a0aed4ec | 246 | |
<> | 150:02e0a0aed4ec | 247 | uint32_t lp_ticker_read(void) |
<> | 150:02e0a0aed4ec | 248 | { |
<> | 150:02e0a0aed4ec | 249 | uint64_t rtcNow; |
<> | 150:02e0a0aed4ec | 250 | |
<> | 150:02e0a0aed4ec | 251 | /* Disable interrupts to avoid collisions */ |
<> | 150:02e0a0aed4ec | 252 | core_util_critical_section_enter(); |
<> | 150:02e0a0aed4ec | 253 | |
<> | 150:02e0a0aed4ec | 254 | /* Just in case this is called before initialisation has been performed */ |
<> | 150:02e0a0aed4ec | 255 | if (!g_initialised) { |
<> | 150:02e0a0aed4ec | 256 | lp_ticker_init(); |
<> | 150:02e0a0aed4ec | 257 | } |
<> | 150:02e0a0aed4ec | 258 | |
<> | 150:02e0a0aed4ec | 259 | /* What mbed expects here is a 32 bit timer value. There is no |
<> | 150:02e0a0aed4ec | 260 | * way to reset the RTC so, to pretend it is 32 bits, we have to |
<> | 150:02e0a0aed4ec | 261 | * maintain a 32-bit window on it using the remembered overflow |
<> | 150:02e0a0aed4ec | 262 | * value */ |
<> | 150:02e0a0aed4ec | 263 | rtcNow = get_rtc_value(); |
<> | 150:02e0a0aed4ec | 264 | |
<> | 150:02e0a0aed4ec | 265 | /* Put interrupts back */ |
<> | 150:02e0a0aed4ec | 266 | core_util_critical_section_exit(); |
<> | 150:02e0a0aed4ec | 267 | |
<> | 150:02e0a0aed4ec | 268 | return ticksToUSeconds(rtcNow - g_last_32bit_overflow_value); |
<> | 150:02e0a0aed4ec | 269 | } |
<> | 150:02e0a0aed4ec | 270 | |
<> | 150:02e0a0aed4ec | 271 | void lp_ticker_set_interrupt(timestamp_t time) |
<> | 150:02e0a0aed4ec | 272 | { |
<> | 150:02e0a0aed4ec | 273 | uint32_t timeNow = get_rtc_value() - g_last_32bit_overflow_value; |
<> | 150:02e0a0aed4ec | 274 | uint32_t timeOffset = uSecondsToTicks(time) - timeNow; |
<> | 150:02e0a0aed4ec | 275 | |
<> | 150:02e0a0aed4ec | 276 | /* Disable interrupts to avoid collisions */ |
<> | 150:02e0a0aed4ec | 277 | core_util_critical_section_enter(); |
<> | 150:02e0a0aed4ec | 278 | |
<> | 150:02e0a0aed4ec | 279 | g_user_interrupt_pending = false; |
<> | 150:02e0a0aed4ec | 280 | g_user_interrupt_set = false; |
<> | 150:02e0a0aed4ec | 281 | |
<> | 150:02e0a0aed4ec | 282 | /* Handle time slipping into the past */ |
<> | 150:02e0a0aed4ec | 283 | if (timeOffset > 0xEFFFFFFF) { |
<> | 150:02e0a0aed4ec | 284 | timeOffset = 100; |
<> | 150:02e0a0aed4ec | 285 | } |
<> | 150:02e0a0aed4ec | 286 | |
<> | 150:02e0a0aed4ec | 287 | /* Read the current time */ |
<> | 150:02e0a0aed4ec | 288 | g_next_compare_value = get_rtc_value(); |
<> | 150:02e0a0aed4ec | 289 | |
<> | 150:02e0a0aed4ec | 290 | /* Add the offset */ |
<> | 150:02e0a0aed4ec | 291 | INCREMENT_MOD(g_next_compare_value, timeOffset); |
<> | 150:02e0a0aed4ec | 292 | |
<> | 150:02e0a0aed4ec | 293 | /* We must let the normal overflow interrupt occur as |
<> | 150:02e0a0aed4ec | 294 | * well as setting this interrupt so, if the value |
<> | 150:02e0a0aed4ec | 295 | * of 'time' would occur after the overflow point, |
<> | 150:02e0a0aed4ec | 296 | * put the change of compare-value off until afterwards. */ |
<> | 150:02e0a0aed4ec | 297 | /* TODO: this needs proper testing. */ |
<> | 150:02e0a0aed4ec | 298 | if (g_next_32bit_overflow_value > g_next_compare_value) { |
<> | 150:02e0a0aed4ec | 299 | /* The easy case, no overlap */ |
<> | 150:02e0a0aed4ec | 300 | } else { |
<> | 150:02e0a0aed4ec | 301 | /* Could be because g_next_compare_value has wrapped (around the |
<> | 150:02e0a0aed4ec | 302 | * 48-bit limit of the RTC) */ |
<> | 150:02e0a0aed4ec | 303 | if (g_next_32bit_overflow_value - g_next_compare_value >= MODULO_32BIT) { |
<> | 150:02e0a0aed4ec | 304 | /* The wrap case, we're OK */ |
<> | 150:02e0a0aed4ec | 305 | } else { |
<> | 150:02e0a0aed4ec | 306 | /* There is an overlap, apply the value later */ |
<> | 150:02e0a0aed4ec | 307 | g_user_interrupt_pending = true; |
<> | 150:02e0a0aed4ec | 308 | |
<> | 150:02e0a0aed4ec | 309 | if (g_next_32bit_overflow_value == g_next_compare_value) { |
<> | 150:02e0a0aed4ec | 310 | /* If they are on top of each other, bump this |
<> | 150:02e0a0aed4ec | 311 | * one forward to avoid losing the interrupt */ |
<> | 150:02e0a0aed4ec | 312 | INCREMENT_MOD(g_next_compare_value, 2); |
<> | 150:02e0a0aed4ec | 313 | } |
<> | 150:02e0a0aed4ec | 314 | } |
<> | 150:02e0a0aed4ec | 315 | } |
<> | 150:02e0a0aed4ec | 316 | |
<> | 150:02e0a0aed4ec | 317 | if (!g_user_interrupt_pending) { |
<> | 150:02e0a0aed4ec | 318 | /* Make the change immediately */ |
<> | 150:02e0a0aed4ec | 319 | set_interrupt_to_user_value(); |
<> | 150:02e0a0aed4ec | 320 | } |
<> | 150:02e0a0aed4ec | 321 | |
<> | 150:02e0a0aed4ec | 322 | /* Put interrupts back */ |
<> | 150:02e0a0aed4ec | 323 | core_util_critical_section_exit(); |
<> | 150:02e0a0aed4ec | 324 | } |
<> | 150:02e0a0aed4ec | 325 | |
<> | 150:02e0a0aed4ec | 326 | void lp_ticker_disable_interrupt(void) |
<> | 150:02e0a0aed4ec | 327 | { |
<> | 150:02e0a0aed4ec | 328 | /* Can't disable interrupts as we need them to manage |
<> | 150:02e0a0aed4ec | 329 | * overflow. Instead, switch off the user part. */ |
<> | 150:02e0a0aed4ec | 330 | g_user_interrupt_pending = false; |
<> | 150:02e0a0aed4ec | 331 | g_user_interrupt_set = false; |
<> | 150:02e0a0aed4ec | 332 | } |
<> | 150:02e0a0aed4ec | 333 | |
<> | 150:02e0a0aed4ec | 334 | void lp_ticker_clear_interrupt(void) |
<> | 150:02e0a0aed4ec | 335 | { |
<> | 150:02e0a0aed4ec | 336 | /* Can't disable interrupts as we need them to manage |
<> | 150:02e0a0aed4ec | 337 | * overflow. Instead, switch off the user part. */ |
<> | 150:02e0a0aed4ec | 338 | g_user_interrupt_pending = false; |
<> | 150:02e0a0aed4ec | 339 | g_user_interrupt_set = false; |
<> | 150:02e0a0aed4ec | 340 | } |