Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: nRF51_Vdd TextLCD BME280
LowPowerTickerWrapper.cpp
00001 /* mbed Microcontroller Library 00002 * Copyright (c) 2018 ARM Limited 00003 * 00004 * Licensed under the Apache License, Version 2.0 (the "License"); 00005 * you may not use this file except in compliance with the License. 00006 * You may obtain a copy of the License at 00007 * 00008 * http://www.apache.org/licenses/LICENSE-2.0 00009 * 00010 * Unless required by applicable law or agreed to in writing, software 00011 * distributed under the License is distributed on an "AS IS" BASIS, 00012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00013 * See the License for the specific language governing permissions and 00014 * limitations under the License. 00015 */ 00016 #include "hal/LowPowerTickerWrapper.h" 00017 #include "platform/Callback.h" 00018 00019 LowPowerTickerWrapper::LowPowerTickerWrapper(const ticker_data_t *data, const ticker_interface_t *interface, uint32_t min_cycles_between_writes, uint32_t min_cycles_until_match) 00020 : _intf(data->interface), _min_count_between_writes(min_cycles_between_writes + 1), _min_count_until_match(min_cycles_until_match + 1), _suspended(false) 00021 { 00022 core_util_critical_section_enter(); 00023 00024 this->data.interface = interface; 00025 this->data.queue = data->queue; 00026 _reset(); 00027 00028 core_util_critical_section_exit(); 00029 } 00030 00031 void LowPowerTickerWrapper::irq_handler(ticker_irq_handler_type handler) 00032 { 00033 core_util_critical_section_enter(); 00034 00035 if (_pending_fire_now || _match_check(_intf->read()) || _suspended) { 00036 _timeout.detach(); 00037 _pending_timeout = false; 00038 _pending_match = false; 00039 _pending_fire_now = false; 00040 if (handler) { 00041 handler(&data); 00042 } 00043 } else { 00044 // Spurious interrupt 00045 _intf->clear_interrupt(); 00046 } 00047 00048 core_util_critical_section_exit(); 00049 } 00050 00051 void LowPowerTickerWrapper::suspend() 00052 { 00053 core_util_critical_section_enter(); 00054 00055 // Wait until rescheduling is allowed 00056 while (!_set_interrupt_allowed) { 00057 timestamp_t current = _intf->read(); 00058 if (((current - _last_actual_set_interrupt) & _mask) >= _min_count_between_writes) { 00059 _set_interrupt_allowed = true; 00060 } 00061 } 00062 00063 _reset(); 00064 _suspended = true; 00065 00066 core_util_critical_section_exit(); 00067 } 00068 00069 void LowPowerTickerWrapper::resume() 00070 { 00071 core_util_critical_section_enter(); 00072 00073 // Wait until rescheduling is allowed 00074 while (!_set_interrupt_allowed) { 00075 timestamp_t current = _intf->read(); 00076 if (((current - _last_actual_set_interrupt) & _mask) >= _min_count_between_writes) { 00077 _set_interrupt_allowed = true; 00078 } 00079 } 00080 00081 _suspended = false; 00082 00083 core_util_critical_section_exit(); 00084 } 00085 00086 bool LowPowerTickerWrapper::timeout_pending() 00087 { 00088 core_util_critical_section_enter(); 00089 00090 bool pending = _pending_timeout; 00091 00092 core_util_critical_section_exit(); 00093 return pending; 00094 } 00095 00096 void LowPowerTickerWrapper::init() 00097 { 00098 core_util_critical_section_enter(); 00099 00100 _reset(); 00101 _intf->init(); 00102 00103 core_util_critical_section_exit(); 00104 } 00105 00106 void LowPowerTickerWrapper::free() 00107 { 00108 core_util_critical_section_enter(); 00109 00110 _reset(); 00111 _intf->free(); 00112 00113 core_util_critical_section_exit(); 00114 } 00115 00116 uint32_t LowPowerTickerWrapper::read() 00117 { 00118 core_util_critical_section_enter(); 00119 00120 timestamp_t current = _intf->read(); 00121 if (!_suspended && _match_check(current)) { 00122 _intf->fire_interrupt(); 00123 } 00124 00125 core_util_critical_section_exit(); 00126 return current; 00127 } 00128 00129 void LowPowerTickerWrapper::set_interrupt(timestamp_t timestamp) 00130 { 00131 core_util_critical_section_enter(); 00132 00133 _last_set_interrupt = _intf->read(); 00134 _cur_match_time = timestamp; 00135 _pending_match = true; 00136 if (!_suspended) { 00137 _schedule_match(_last_set_interrupt); 00138 } else { 00139 _intf->set_interrupt(timestamp); 00140 _last_actual_set_interrupt = _last_set_interrupt; 00141 _set_interrupt_allowed = false; 00142 } 00143 00144 core_util_critical_section_exit(); 00145 } 00146 00147 void LowPowerTickerWrapper::disable_interrupt() 00148 { 00149 core_util_critical_section_enter(); 00150 00151 _intf->disable_interrupt(); 00152 00153 core_util_critical_section_exit(); 00154 } 00155 00156 void LowPowerTickerWrapper::clear_interrupt() 00157 { 00158 core_util_critical_section_enter(); 00159 00160 _intf->clear_interrupt(); 00161 00162 core_util_critical_section_exit(); 00163 } 00164 00165 void LowPowerTickerWrapper::fire_interrupt() 00166 { 00167 core_util_critical_section_enter(); 00168 00169 _pending_fire_now = 1; 00170 _intf->fire_interrupt(); 00171 00172 core_util_critical_section_exit(); 00173 } 00174 00175 const ticker_info_t *LowPowerTickerWrapper::get_info() 00176 { 00177 00178 core_util_critical_section_enter(); 00179 00180 const ticker_info_t *info = _intf->get_info(); 00181 00182 core_util_critical_section_exit(); 00183 return info; 00184 } 00185 00186 void LowPowerTickerWrapper::_reset() 00187 { 00188 MBED_ASSERT(core_util_in_critical_section()); 00189 00190 _timeout.detach(); 00191 _pending_timeout = false; 00192 _pending_match = false; 00193 _pending_fire_now = false; 00194 _set_interrupt_allowed = true; 00195 _cur_match_time = 0; 00196 _last_set_interrupt = 0; 00197 _last_actual_set_interrupt = 0; 00198 00199 const ticker_info_t *info = _intf->get_info(); 00200 if (info->bits >= 32) { 00201 _mask = 0xffffffff; 00202 } else { 00203 _mask = ((uint64_t)1 << info->bits) - 1; 00204 } 00205 00206 // Round us_per_tick up 00207 _us_per_tick = (1000000 + info->frequency - 1) / info->frequency; 00208 } 00209 00210 void LowPowerTickerWrapper::_timeout_handler() 00211 { 00212 core_util_critical_section_enter(); 00213 _pending_timeout = false; 00214 00215 timestamp_t current = _intf->read(); 00216 /* Add extra check for '_last_set_interrupt == _cur_match_time' 00217 * 00218 * When '_last_set_interrupt == _cur_match_time', _ticker_match_interval_passed sees it as 00219 * one-round interval rather than just-pass, so add extra check for it. In rare cases, we 00220 * may trap in _timeout_handler/_schedule_match loop. This check can break it. 00221 */ 00222 if ((_last_set_interrupt == _cur_match_time) || 00223 _ticker_match_interval_passed(_last_set_interrupt, current, _cur_match_time)) { 00224 _intf->fire_interrupt(); 00225 } else { 00226 _schedule_match(current); 00227 } 00228 00229 core_util_critical_section_exit(); 00230 } 00231 00232 bool LowPowerTickerWrapper::_match_check(timestamp_t current) 00233 { 00234 MBED_ASSERT(core_util_in_critical_section()); 00235 00236 if (!_pending_match) { 00237 return false; 00238 } 00239 /* Add extra check for '_last_set_interrupt == _cur_match_time' as above */ 00240 return (_last_set_interrupt == _cur_match_time) || 00241 _ticker_match_interval_passed(_last_set_interrupt, current, _cur_match_time); 00242 } 00243 00244 uint32_t LowPowerTickerWrapper::_lp_ticks_to_us(uint32_t ticks) 00245 { 00246 MBED_ASSERT(core_util_in_critical_section()); 00247 00248 // Add 4 microseconds to round up the micro second ticker time (which has a frequency of at least 250KHz - 4us period) 00249 return _us_per_tick * ticks + 4; 00250 } 00251 00252 void LowPowerTickerWrapper::_schedule_match(timestamp_t current) 00253 { 00254 MBED_ASSERT(core_util_in_critical_section()); 00255 00256 // Check if _intf->set_interrupt is allowed 00257 if (!_set_interrupt_allowed) { 00258 if (((current - _last_actual_set_interrupt) & _mask) >= _min_count_between_writes) { 00259 _set_interrupt_allowed = true; 00260 } 00261 } 00262 00263 uint32_t cycles_until_match = (_cur_match_time - current) & _mask; 00264 bool too_close = cycles_until_match < _min_count_until_match; 00265 00266 if (!_set_interrupt_allowed) { 00267 00268 // Can't use _intf->set_interrupt so use microsecond Timeout instead 00269 00270 // Speed optimization - if a timer has already been scheduled 00271 // then don't schedule it again. 00272 if (!_pending_timeout) { 00273 uint32_t ticks = cycles_until_match < _min_count_until_match ? cycles_until_match : _min_count_until_match; 00274 _timeout.attach_us(mbed::callback(this, &LowPowerTickerWrapper::_timeout_handler), _lp_ticks_to_us(ticks)); 00275 _pending_timeout = true; 00276 } 00277 return; 00278 } 00279 00280 if (!too_close) { 00281 00282 // Schedule LP ticker 00283 _intf->set_interrupt(_cur_match_time); 00284 current = _intf->read(); 00285 _last_actual_set_interrupt = current; 00286 _set_interrupt_allowed = false; 00287 00288 // Check for overflow 00289 uint32_t new_cycles_until_match = (_cur_match_time - current) & _mask; 00290 if (new_cycles_until_match > cycles_until_match) { 00291 // Overflow so fire now 00292 _intf->fire_interrupt(); 00293 return; 00294 } 00295 00296 // Update variables with new time 00297 cycles_until_match = new_cycles_until_match; 00298 too_close = cycles_until_match < _min_count_until_match; 00299 } 00300 00301 if (too_close) { 00302 00303 // Low power ticker incremented to less than _min_count_until_match 00304 // so low power ticker may not fire. Use Timeout to ensure it does fire. 00305 uint32_t ticks = cycles_until_match < _min_count_until_match ? cycles_until_match : _min_count_until_match; 00306 _timeout.attach_us(mbed::callback(this, &LowPowerTickerWrapper::_timeout_handler), _lp_ticks_to_us(ticks)); 00307 _pending_timeout = true; 00308 return; 00309 } 00310 }
Generated on Tue Jul 12 2022 15:15:48 by
