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