mbed library sources. Supersedes mbed-src.
Dependents: Nucleo_Hello_Encoder BLE_iBeaconScan AM1805_DEMO DISCO-F429ZI_ExportTemplate1 ... more
hal/LowPowerTickerWrapper.cpp@189:f392fc9709a3, 2019-02-20 (annotated)
- Committer:
- AnnaBridge
- Date:
- Wed Feb 20 22:31:08 2019 +0000
- Revision:
- 189:f392fc9709a3
- Parent:
- 188:bcfe06ba3d64
mbed library release version 165
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
AnnaBridge | 188:bcfe06ba3d64 | 1 | /* mbed Microcontroller Library |
AnnaBridge | 188:bcfe06ba3d64 | 2 | * Copyright (c) 2018 ARM Limited |
AnnaBridge | 189:f392fc9709a3 | 3 | * SPDX-License-Identifier: Apache-2.0 |
AnnaBridge | 188:bcfe06ba3d64 | 4 | * |
AnnaBridge | 188:bcfe06ba3d64 | 5 | * Licensed under the Apache License, Version 2.0 (the "License"); |
AnnaBridge | 188:bcfe06ba3d64 | 6 | * you may not use this file except in compliance with the License. |
AnnaBridge | 188:bcfe06ba3d64 | 7 | * You may obtain a copy of the License at |
AnnaBridge | 188:bcfe06ba3d64 | 8 | * |
AnnaBridge | 188:bcfe06ba3d64 | 9 | * http://www.apache.org/licenses/LICENSE-2.0 |
AnnaBridge | 188:bcfe06ba3d64 | 10 | * |
AnnaBridge | 188:bcfe06ba3d64 | 11 | * Unless required by applicable law or agreed to in writing, software |
AnnaBridge | 188:bcfe06ba3d64 | 12 | * distributed under the License is distributed on an "AS IS" BASIS, |
AnnaBridge | 188:bcfe06ba3d64 | 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
AnnaBridge | 188:bcfe06ba3d64 | 14 | * See the License for the specific language governing permissions and |
AnnaBridge | 188:bcfe06ba3d64 | 15 | * limitations under the License. |
AnnaBridge | 188:bcfe06ba3d64 | 16 | */ |
AnnaBridge | 188:bcfe06ba3d64 | 17 | #include "hal/LowPowerTickerWrapper.h" |
AnnaBridge | 188:bcfe06ba3d64 | 18 | #include "platform/Callback.h" |
AnnaBridge | 188:bcfe06ba3d64 | 19 | |
AnnaBridge | 188:bcfe06ba3d64 | 20 | LowPowerTickerWrapper::LowPowerTickerWrapper(const ticker_data_t *data, const ticker_interface_t *interface, uint32_t min_cycles_between_writes, uint32_t min_cycles_until_match) |
AnnaBridge | 188:bcfe06ba3d64 | 21 | : _intf(data->interface), _min_count_between_writes(min_cycles_between_writes + 1), _min_count_until_match(min_cycles_until_match + 1), _suspended(false) |
AnnaBridge | 188:bcfe06ba3d64 | 22 | { |
AnnaBridge | 188:bcfe06ba3d64 | 23 | core_util_critical_section_enter(); |
AnnaBridge | 188:bcfe06ba3d64 | 24 | |
AnnaBridge | 188:bcfe06ba3d64 | 25 | this->data.interface = interface; |
AnnaBridge | 188:bcfe06ba3d64 | 26 | this->data.queue = data->queue; |
AnnaBridge | 188:bcfe06ba3d64 | 27 | _reset(); |
AnnaBridge | 188:bcfe06ba3d64 | 28 | |
AnnaBridge | 188:bcfe06ba3d64 | 29 | core_util_critical_section_exit(); |
AnnaBridge | 188:bcfe06ba3d64 | 30 | } |
AnnaBridge | 188:bcfe06ba3d64 | 31 | |
AnnaBridge | 188:bcfe06ba3d64 | 32 | void LowPowerTickerWrapper::irq_handler(ticker_irq_handler_type handler) |
AnnaBridge | 188:bcfe06ba3d64 | 33 | { |
AnnaBridge | 188:bcfe06ba3d64 | 34 | core_util_critical_section_enter(); |
AnnaBridge | 188:bcfe06ba3d64 | 35 | |
AnnaBridge | 189:f392fc9709a3 | 36 | // This code no longer filters out early interrupts. Instead it |
AnnaBridge | 189:f392fc9709a3 | 37 | // passes them through to the next layer and ignores further interrupts |
AnnaBridge | 189:f392fc9709a3 | 38 | // until the next call to set_interrrupt or fire_interrupt (when not suspended). |
AnnaBridge | 189:f392fc9709a3 | 39 | // This is to ensure that the device doesn't get stuck in sleep due to an |
AnnaBridge | 189:f392fc9709a3 | 40 | // early low power ticker interrupt that was ignored. |
AnnaBridge | 189:f392fc9709a3 | 41 | if (_pending_fire_now || _pending_match || _suspended) { |
AnnaBridge | 188:bcfe06ba3d64 | 42 | _timeout.detach(); |
AnnaBridge | 188:bcfe06ba3d64 | 43 | _pending_timeout = false; |
AnnaBridge | 188:bcfe06ba3d64 | 44 | _pending_match = false; |
AnnaBridge | 188:bcfe06ba3d64 | 45 | _pending_fire_now = false; |
AnnaBridge | 188:bcfe06ba3d64 | 46 | if (handler) { |
AnnaBridge | 188:bcfe06ba3d64 | 47 | handler(&data); |
AnnaBridge | 188:bcfe06ba3d64 | 48 | } |
AnnaBridge | 188:bcfe06ba3d64 | 49 | } else { |
AnnaBridge | 188:bcfe06ba3d64 | 50 | // Spurious interrupt |
AnnaBridge | 188:bcfe06ba3d64 | 51 | _intf->clear_interrupt(); |
AnnaBridge | 188:bcfe06ba3d64 | 52 | } |
AnnaBridge | 188:bcfe06ba3d64 | 53 | |
AnnaBridge | 188:bcfe06ba3d64 | 54 | core_util_critical_section_exit(); |
AnnaBridge | 188:bcfe06ba3d64 | 55 | } |
AnnaBridge | 188:bcfe06ba3d64 | 56 | |
AnnaBridge | 188:bcfe06ba3d64 | 57 | void LowPowerTickerWrapper::suspend() |
AnnaBridge | 188:bcfe06ba3d64 | 58 | { |
AnnaBridge | 188:bcfe06ba3d64 | 59 | core_util_critical_section_enter(); |
AnnaBridge | 188:bcfe06ba3d64 | 60 | |
AnnaBridge | 188:bcfe06ba3d64 | 61 | // Wait until rescheduling is allowed |
AnnaBridge | 188:bcfe06ba3d64 | 62 | while (!_set_interrupt_allowed) { |
AnnaBridge | 188:bcfe06ba3d64 | 63 | timestamp_t current = _intf->read(); |
AnnaBridge | 188:bcfe06ba3d64 | 64 | if (((current - _last_actual_set_interrupt) & _mask) >= _min_count_between_writes) { |
AnnaBridge | 188:bcfe06ba3d64 | 65 | _set_interrupt_allowed = true; |
AnnaBridge | 188:bcfe06ba3d64 | 66 | } |
AnnaBridge | 188:bcfe06ba3d64 | 67 | } |
AnnaBridge | 188:bcfe06ba3d64 | 68 | |
AnnaBridge | 188:bcfe06ba3d64 | 69 | _reset(); |
AnnaBridge | 188:bcfe06ba3d64 | 70 | _suspended = true; |
AnnaBridge | 188:bcfe06ba3d64 | 71 | |
AnnaBridge | 188:bcfe06ba3d64 | 72 | core_util_critical_section_exit(); |
AnnaBridge | 188:bcfe06ba3d64 | 73 | } |
AnnaBridge | 188:bcfe06ba3d64 | 74 | |
AnnaBridge | 188:bcfe06ba3d64 | 75 | void LowPowerTickerWrapper::resume() |
AnnaBridge | 188:bcfe06ba3d64 | 76 | { |
AnnaBridge | 188:bcfe06ba3d64 | 77 | core_util_critical_section_enter(); |
AnnaBridge | 188:bcfe06ba3d64 | 78 | |
AnnaBridge | 188:bcfe06ba3d64 | 79 | // Wait until rescheduling is allowed |
AnnaBridge | 188:bcfe06ba3d64 | 80 | while (!_set_interrupt_allowed) { |
AnnaBridge | 188:bcfe06ba3d64 | 81 | timestamp_t current = _intf->read(); |
AnnaBridge | 188:bcfe06ba3d64 | 82 | if (((current - _last_actual_set_interrupt) & _mask) >= _min_count_between_writes) { |
AnnaBridge | 188:bcfe06ba3d64 | 83 | _set_interrupt_allowed = true; |
AnnaBridge | 188:bcfe06ba3d64 | 84 | } |
AnnaBridge | 188:bcfe06ba3d64 | 85 | } |
AnnaBridge | 188:bcfe06ba3d64 | 86 | |
AnnaBridge | 188:bcfe06ba3d64 | 87 | _suspended = false; |
AnnaBridge | 188:bcfe06ba3d64 | 88 | |
AnnaBridge | 188:bcfe06ba3d64 | 89 | core_util_critical_section_exit(); |
AnnaBridge | 188:bcfe06ba3d64 | 90 | } |
AnnaBridge | 188:bcfe06ba3d64 | 91 | |
AnnaBridge | 188:bcfe06ba3d64 | 92 | bool LowPowerTickerWrapper::timeout_pending() |
AnnaBridge | 188:bcfe06ba3d64 | 93 | { |
AnnaBridge | 188:bcfe06ba3d64 | 94 | core_util_critical_section_enter(); |
AnnaBridge | 188:bcfe06ba3d64 | 95 | |
AnnaBridge | 188:bcfe06ba3d64 | 96 | bool pending = _pending_timeout; |
AnnaBridge | 188:bcfe06ba3d64 | 97 | |
AnnaBridge | 188:bcfe06ba3d64 | 98 | core_util_critical_section_exit(); |
AnnaBridge | 188:bcfe06ba3d64 | 99 | return pending; |
AnnaBridge | 188:bcfe06ba3d64 | 100 | } |
AnnaBridge | 188:bcfe06ba3d64 | 101 | |
AnnaBridge | 188:bcfe06ba3d64 | 102 | void LowPowerTickerWrapper::init() |
AnnaBridge | 188:bcfe06ba3d64 | 103 | { |
AnnaBridge | 188:bcfe06ba3d64 | 104 | core_util_critical_section_enter(); |
AnnaBridge | 188:bcfe06ba3d64 | 105 | |
AnnaBridge | 188:bcfe06ba3d64 | 106 | _reset(); |
AnnaBridge | 188:bcfe06ba3d64 | 107 | _intf->init(); |
AnnaBridge | 188:bcfe06ba3d64 | 108 | |
AnnaBridge | 188:bcfe06ba3d64 | 109 | core_util_critical_section_exit(); |
AnnaBridge | 188:bcfe06ba3d64 | 110 | } |
AnnaBridge | 188:bcfe06ba3d64 | 111 | |
AnnaBridge | 188:bcfe06ba3d64 | 112 | void LowPowerTickerWrapper::free() |
AnnaBridge | 188:bcfe06ba3d64 | 113 | { |
AnnaBridge | 188:bcfe06ba3d64 | 114 | core_util_critical_section_enter(); |
AnnaBridge | 188:bcfe06ba3d64 | 115 | |
AnnaBridge | 188:bcfe06ba3d64 | 116 | _reset(); |
AnnaBridge | 188:bcfe06ba3d64 | 117 | _intf->free(); |
AnnaBridge | 188:bcfe06ba3d64 | 118 | |
AnnaBridge | 188:bcfe06ba3d64 | 119 | core_util_critical_section_exit(); |
AnnaBridge | 188:bcfe06ba3d64 | 120 | } |
AnnaBridge | 188:bcfe06ba3d64 | 121 | |
AnnaBridge | 188:bcfe06ba3d64 | 122 | uint32_t LowPowerTickerWrapper::read() |
AnnaBridge | 188:bcfe06ba3d64 | 123 | { |
AnnaBridge | 188:bcfe06ba3d64 | 124 | core_util_critical_section_enter(); |
AnnaBridge | 188:bcfe06ba3d64 | 125 | |
AnnaBridge | 188:bcfe06ba3d64 | 126 | timestamp_t current = _intf->read(); |
AnnaBridge | 188:bcfe06ba3d64 | 127 | if (!_suspended && _match_check(current)) { |
AnnaBridge | 188:bcfe06ba3d64 | 128 | _intf->fire_interrupt(); |
AnnaBridge | 188:bcfe06ba3d64 | 129 | } |
AnnaBridge | 188:bcfe06ba3d64 | 130 | |
AnnaBridge | 188:bcfe06ba3d64 | 131 | core_util_critical_section_exit(); |
AnnaBridge | 188:bcfe06ba3d64 | 132 | return current; |
AnnaBridge | 188:bcfe06ba3d64 | 133 | } |
AnnaBridge | 188:bcfe06ba3d64 | 134 | |
AnnaBridge | 188:bcfe06ba3d64 | 135 | void LowPowerTickerWrapper::set_interrupt(timestamp_t timestamp) |
AnnaBridge | 188:bcfe06ba3d64 | 136 | { |
AnnaBridge | 188:bcfe06ba3d64 | 137 | core_util_critical_section_enter(); |
AnnaBridge | 188:bcfe06ba3d64 | 138 | |
AnnaBridge | 188:bcfe06ba3d64 | 139 | _last_set_interrupt = _intf->read(); |
AnnaBridge | 188:bcfe06ba3d64 | 140 | _cur_match_time = timestamp; |
AnnaBridge | 188:bcfe06ba3d64 | 141 | _pending_match = true; |
AnnaBridge | 188:bcfe06ba3d64 | 142 | if (!_suspended) { |
AnnaBridge | 188:bcfe06ba3d64 | 143 | _schedule_match(_last_set_interrupt); |
AnnaBridge | 188:bcfe06ba3d64 | 144 | } else { |
AnnaBridge | 188:bcfe06ba3d64 | 145 | _intf->set_interrupt(timestamp); |
AnnaBridge | 188:bcfe06ba3d64 | 146 | _last_actual_set_interrupt = _last_set_interrupt; |
AnnaBridge | 188:bcfe06ba3d64 | 147 | _set_interrupt_allowed = false; |
AnnaBridge | 188:bcfe06ba3d64 | 148 | } |
AnnaBridge | 188:bcfe06ba3d64 | 149 | |
AnnaBridge | 188:bcfe06ba3d64 | 150 | core_util_critical_section_exit(); |
AnnaBridge | 188:bcfe06ba3d64 | 151 | } |
AnnaBridge | 188:bcfe06ba3d64 | 152 | |
AnnaBridge | 188:bcfe06ba3d64 | 153 | void LowPowerTickerWrapper::disable_interrupt() |
AnnaBridge | 188:bcfe06ba3d64 | 154 | { |
AnnaBridge | 188:bcfe06ba3d64 | 155 | core_util_critical_section_enter(); |
AnnaBridge | 188:bcfe06ba3d64 | 156 | |
AnnaBridge | 188:bcfe06ba3d64 | 157 | _intf->disable_interrupt(); |
AnnaBridge | 188:bcfe06ba3d64 | 158 | |
AnnaBridge | 188:bcfe06ba3d64 | 159 | core_util_critical_section_exit(); |
AnnaBridge | 188:bcfe06ba3d64 | 160 | } |
AnnaBridge | 188:bcfe06ba3d64 | 161 | |
AnnaBridge | 188:bcfe06ba3d64 | 162 | void LowPowerTickerWrapper::clear_interrupt() |
AnnaBridge | 188:bcfe06ba3d64 | 163 | { |
AnnaBridge | 188:bcfe06ba3d64 | 164 | core_util_critical_section_enter(); |
AnnaBridge | 188:bcfe06ba3d64 | 165 | |
AnnaBridge | 188:bcfe06ba3d64 | 166 | _intf->clear_interrupt(); |
AnnaBridge | 188:bcfe06ba3d64 | 167 | |
AnnaBridge | 188:bcfe06ba3d64 | 168 | core_util_critical_section_exit(); |
AnnaBridge | 188:bcfe06ba3d64 | 169 | } |
AnnaBridge | 188:bcfe06ba3d64 | 170 | |
AnnaBridge | 188:bcfe06ba3d64 | 171 | void LowPowerTickerWrapper::fire_interrupt() |
AnnaBridge | 188:bcfe06ba3d64 | 172 | { |
AnnaBridge | 188:bcfe06ba3d64 | 173 | core_util_critical_section_enter(); |
AnnaBridge | 188:bcfe06ba3d64 | 174 | |
AnnaBridge | 188:bcfe06ba3d64 | 175 | _pending_fire_now = 1; |
AnnaBridge | 188:bcfe06ba3d64 | 176 | _intf->fire_interrupt(); |
AnnaBridge | 188:bcfe06ba3d64 | 177 | |
AnnaBridge | 188:bcfe06ba3d64 | 178 | core_util_critical_section_exit(); |
AnnaBridge | 188:bcfe06ba3d64 | 179 | } |
AnnaBridge | 188:bcfe06ba3d64 | 180 | |
AnnaBridge | 188:bcfe06ba3d64 | 181 | const ticker_info_t *LowPowerTickerWrapper::get_info() |
AnnaBridge | 188:bcfe06ba3d64 | 182 | { |
AnnaBridge | 188:bcfe06ba3d64 | 183 | |
AnnaBridge | 188:bcfe06ba3d64 | 184 | core_util_critical_section_enter(); |
AnnaBridge | 188:bcfe06ba3d64 | 185 | |
AnnaBridge | 188:bcfe06ba3d64 | 186 | const ticker_info_t *info = _intf->get_info(); |
AnnaBridge | 188:bcfe06ba3d64 | 187 | |
AnnaBridge | 188:bcfe06ba3d64 | 188 | core_util_critical_section_exit(); |
AnnaBridge | 188:bcfe06ba3d64 | 189 | return info; |
AnnaBridge | 188:bcfe06ba3d64 | 190 | } |
AnnaBridge | 188:bcfe06ba3d64 | 191 | |
AnnaBridge | 188:bcfe06ba3d64 | 192 | void LowPowerTickerWrapper::_reset() |
AnnaBridge | 188:bcfe06ba3d64 | 193 | { |
AnnaBridge | 188:bcfe06ba3d64 | 194 | MBED_ASSERT(core_util_in_critical_section()); |
AnnaBridge | 188:bcfe06ba3d64 | 195 | |
AnnaBridge | 188:bcfe06ba3d64 | 196 | _timeout.detach(); |
AnnaBridge | 188:bcfe06ba3d64 | 197 | _pending_timeout = false; |
AnnaBridge | 188:bcfe06ba3d64 | 198 | _pending_match = false; |
AnnaBridge | 188:bcfe06ba3d64 | 199 | _pending_fire_now = false; |
AnnaBridge | 188:bcfe06ba3d64 | 200 | _set_interrupt_allowed = true; |
AnnaBridge | 188:bcfe06ba3d64 | 201 | _cur_match_time = 0; |
AnnaBridge | 188:bcfe06ba3d64 | 202 | _last_set_interrupt = 0; |
AnnaBridge | 188:bcfe06ba3d64 | 203 | _last_actual_set_interrupt = 0; |
AnnaBridge | 188:bcfe06ba3d64 | 204 | |
AnnaBridge | 188:bcfe06ba3d64 | 205 | const ticker_info_t *info = _intf->get_info(); |
AnnaBridge | 188:bcfe06ba3d64 | 206 | if (info->bits >= 32) { |
AnnaBridge | 188:bcfe06ba3d64 | 207 | _mask = 0xffffffff; |
AnnaBridge | 188:bcfe06ba3d64 | 208 | } else { |
AnnaBridge | 188:bcfe06ba3d64 | 209 | _mask = ((uint64_t)1 << info->bits) - 1; |
AnnaBridge | 188:bcfe06ba3d64 | 210 | } |
AnnaBridge | 188:bcfe06ba3d64 | 211 | |
AnnaBridge | 188:bcfe06ba3d64 | 212 | // Round us_per_tick up |
AnnaBridge | 188:bcfe06ba3d64 | 213 | _us_per_tick = (1000000 + info->frequency - 1) / info->frequency; |
AnnaBridge | 188:bcfe06ba3d64 | 214 | } |
AnnaBridge | 188:bcfe06ba3d64 | 215 | |
AnnaBridge | 188:bcfe06ba3d64 | 216 | void LowPowerTickerWrapper::_timeout_handler() |
AnnaBridge | 188:bcfe06ba3d64 | 217 | { |
AnnaBridge | 188:bcfe06ba3d64 | 218 | core_util_critical_section_enter(); |
AnnaBridge | 188:bcfe06ba3d64 | 219 | _pending_timeout = false; |
AnnaBridge | 188:bcfe06ba3d64 | 220 | |
AnnaBridge | 188:bcfe06ba3d64 | 221 | timestamp_t current = _intf->read(); |
AnnaBridge | 188:bcfe06ba3d64 | 222 | /* Add extra check for '_last_set_interrupt == _cur_match_time' |
AnnaBridge | 189:f392fc9709a3 | 223 | * |
AnnaBridge | 188:bcfe06ba3d64 | 224 | * When '_last_set_interrupt == _cur_match_time', _ticker_match_interval_passed sees it as |
AnnaBridge | 188:bcfe06ba3d64 | 225 | * one-round interval rather than just-pass, so add extra check for it. In rare cases, we |
AnnaBridge | 188:bcfe06ba3d64 | 226 | * may trap in _timeout_handler/_schedule_match loop. This check can break it. |
AnnaBridge | 188:bcfe06ba3d64 | 227 | */ |
AnnaBridge | 188:bcfe06ba3d64 | 228 | if ((_last_set_interrupt == _cur_match_time) || |
AnnaBridge | 189:f392fc9709a3 | 229 | _ticker_match_interval_passed(_last_set_interrupt, current, _cur_match_time)) { |
AnnaBridge | 188:bcfe06ba3d64 | 230 | _intf->fire_interrupt(); |
AnnaBridge | 188:bcfe06ba3d64 | 231 | } else { |
AnnaBridge | 188:bcfe06ba3d64 | 232 | _schedule_match(current); |
AnnaBridge | 188:bcfe06ba3d64 | 233 | } |
AnnaBridge | 188:bcfe06ba3d64 | 234 | |
AnnaBridge | 188:bcfe06ba3d64 | 235 | core_util_critical_section_exit(); |
AnnaBridge | 188:bcfe06ba3d64 | 236 | } |
AnnaBridge | 188:bcfe06ba3d64 | 237 | |
AnnaBridge | 188:bcfe06ba3d64 | 238 | bool LowPowerTickerWrapper::_match_check(timestamp_t current) |
AnnaBridge | 188:bcfe06ba3d64 | 239 | { |
AnnaBridge | 188:bcfe06ba3d64 | 240 | MBED_ASSERT(core_util_in_critical_section()); |
AnnaBridge | 188:bcfe06ba3d64 | 241 | |
AnnaBridge | 188:bcfe06ba3d64 | 242 | if (!_pending_match) { |
AnnaBridge | 188:bcfe06ba3d64 | 243 | return false; |
AnnaBridge | 188:bcfe06ba3d64 | 244 | } |
AnnaBridge | 188:bcfe06ba3d64 | 245 | /* Add extra check for '_last_set_interrupt == _cur_match_time' as above */ |
AnnaBridge | 188:bcfe06ba3d64 | 246 | return (_last_set_interrupt == _cur_match_time) || |
AnnaBridge | 189:f392fc9709a3 | 247 | _ticker_match_interval_passed(_last_set_interrupt, current, _cur_match_time); |
AnnaBridge | 188:bcfe06ba3d64 | 248 | } |
AnnaBridge | 188:bcfe06ba3d64 | 249 | |
AnnaBridge | 188:bcfe06ba3d64 | 250 | uint32_t LowPowerTickerWrapper::_lp_ticks_to_us(uint32_t ticks) |
AnnaBridge | 188:bcfe06ba3d64 | 251 | { |
AnnaBridge | 188:bcfe06ba3d64 | 252 | MBED_ASSERT(core_util_in_critical_section()); |
AnnaBridge | 188:bcfe06ba3d64 | 253 | |
AnnaBridge | 188:bcfe06ba3d64 | 254 | // Add 4 microseconds to round up the micro second ticker time (which has a frequency of at least 250KHz - 4us period) |
AnnaBridge | 188:bcfe06ba3d64 | 255 | return _us_per_tick * ticks + 4; |
AnnaBridge | 188:bcfe06ba3d64 | 256 | } |
AnnaBridge | 188:bcfe06ba3d64 | 257 | |
AnnaBridge | 188:bcfe06ba3d64 | 258 | void LowPowerTickerWrapper::_schedule_match(timestamp_t current) |
AnnaBridge | 188:bcfe06ba3d64 | 259 | { |
AnnaBridge | 188:bcfe06ba3d64 | 260 | MBED_ASSERT(core_util_in_critical_section()); |
AnnaBridge | 188:bcfe06ba3d64 | 261 | |
AnnaBridge | 188:bcfe06ba3d64 | 262 | // Check if _intf->set_interrupt is allowed |
AnnaBridge | 188:bcfe06ba3d64 | 263 | if (!_set_interrupt_allowed) { |
AnnaBridge | 188:bcfe06ba3d64 | 264 | if (((current - _last_actual_set_interrupt) & _mask) >= _min_count_between_writes) { |
AnnaBridge | 188:bcfe06ba3d64 | 265 | _set_interrupt_allowed = true; |
AnnaBridge | 188:bcfe06ba3d64 | 266 | } |
AnnaBridge | 188:bcfe06ba3d64 | 267 | } |
AnnaBridge | 188:bcfe06ba3d64 | 268 | |
AnnaBridge | 188:bcfe06ba3d64 | 269 | uint32_t cycles_until_match = (_cur_match_time - current) & _mask; |
AnnaBridge | 188:bcfe06ba3d64 | 270 | bool too_close = cycles_until_match < _min_count_until_match; |
AnnaBridge | 188:bcfe06ba3d64 | 271 | |
AnnaBridge | 188:bcfe06ba3d64 | 272 | if (!_set_interrupt_allowed) { |
AnnaBridge | 188:bcfe06ba3d64 | 273 | |
AnnaBridge | 188:bcfe06ba3d64 | 274 | // Can't use _intf->set_interrupt so use microsecond Timeout instead |
AnnaBridge | 188:bcfe06ba3d64 | 275 | |
AnnaBridge | 188:bcfe06ba3d64 | 276 | // Speed optimization - if a timer has already been scheduled |
AnnaBridge | 188:bcfe06ba3d64 | 277 | // then don't schedule it again. |
AnnaBridge | 188:bcfe06ba3d64 | 278 | if (!_pending_timeout) { |
AnnaBridge | 188:bcfe06ba3d64 | 279 | uint32_t ticks = cycles_until_match < _min_count_until_match ? cycles_until_match : _min_count_until_match; |
AnnaBridge | 188:bcfe06ba3d64 | 280 | _timeout.attach_us(mbed::callback(this, &LowPowerTickerWrapper::_timeout_handler), _lp_ticks_to_us(ticks)); |
AnnaBridge | 188:bcfe06ba3d64 | 281 | _pending_timeout = true; |
AnnaBridge | 188:bcfe06ba3d64 | 282 | } |
AnnaBridge | 188:bcfe06ba3d64 | 283 | return; |
AnnaBridge | 188:bcfe06ba3d64 | 284 | } |
AnnaBridge | 188:bcfe06ba3d64 | 285 | |
AnnaBridge | 188:bcfe06ba3d64 | 286 | if (!too_close) { |
AnnaBridge | 188:bcfe06ba3d64 | 287 | |
AnnaBridge | 188:bcfe06ba3d64 | 288 | // Schedule LP ticker |
AnnaBridge | 188:bcfe06ba3d64 | 289 | _intf->set_interrupt(_cur_match_time); |
AnnaBridge | 188:bcfe06ba3d64 | 290 | current = _intf->read(); |
AnnaBridge | 188:bcfe06ba3d64 | 291 | _last_actual_set_interrupt = current; |
AnnaBridge | 188:bcfe06ba3d64 | 292 | _set_interrupt_allowed = false; |
AnnaBridge | 188:bcfe06ba3d64 | 293 | |
AnnaBridge | 188:bcfe06ba3d64 | 294 | // Check for overflow |
AnnaBridge | 188:bcfe06ba3d64 | 295 | uint32_t new_cycles_until_match = (_cur_match_time - current) & _mask; |
AnnaBridge | 188:bcfe06ba3d64 | 296 | if (new_cycles_until_match > cycles_until_match) { |
AnnaBridge | 188:bcfe06ba3d64 | 297 | // Overflow so fire now |
AnnaBridge | 188:bcfe06ba3d64 | 298 | _intf->fire_interrupt(); |
AnnaBridge | 188:bcfe06ba3d64 | 299 | return; |
AnnaBridge | 188:bcfe06ba3d64 | 300 | } |
AnnaBridge | 188:bcfe06ba3d64 | 301 | |
AnnaBridge | 188:bcfe06ba3d64 | 302 | // Update variables with new time |
AnnaBridge | 188:bcfe06ba3d64 | 303 | cycles_until_match = new_cycles_until_match; |
AnnaBridge | 188:bcfe06ba3d64 | 304 | too_close = cycles_until_match < _min_count_until_match; |
AnnaBridge | 188:bcfe06ba3d64 | 305 | } |
AnnaBridge | 188:bcfe06ba3d64 | 306 | |
AnnaBridge | 188:bcfe06ba3d64 | 307 | if (too_close) { |
AnnaBridge | 188:bcfe06ba3d64 | 308 | |
AnnaBridge | 188:bcfe06ba3d64 | 309 | // Low power ticker incremented to less than _min_count_until_match |
AnnaBridge | 188:bcfe06ba3d64 | 310 | // so low power ticker may not fire. Use Timeout to ensure it does fire. |
AnnaBridge | 188:bcfe06ba3d64 | 311 | uint32_t ticks = cycles_until_match < _min_count_until_match ? cycles_until_match : _min_count_until_match; |
AnnaBridge | 188:bcfe06ba3d64 | 312 | _timeout.attach_us(mbed::callback(this, &LowPowerTickerWrapper::_timeout_handler), _lp_ticks_to_us(ticks)); |
AnnaBridge | 188:bcfe06ba3d64 | 313 | _pending_timeout = true; |
AnnaBridge | 188:bcfe06ba3d64 | 314 | return; |
AnnaBridge | 188:bcfe06ba3d64 | 315 | } |
AnnaBridge | 188:bcfe06ba3d64 | 316 | } |