mbed-os5 only for TYBLE16
Dependents: TYBLE16_simple_data_logger TYBLE16_MP3_Air
Diff: platform/source/SysTimer.h
- Revision:
- 1:9db0e321a9f4
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/platform/source/SysTimer.h Tue Dec 31 06:02:27 2019 +0000 @@ -0,0 +1,243 @@ +/* mbed Microcontroller Library + * Copyright (c) 2006-2019 ARM Limited + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef MBED_SYS_TIMER_H +#define MBED_SYS_TIMER_H + +#include "platform/NonCopyable.h" +#include "platform/mbed_atomic.h" +#include "drivers/TimerEvent.h" +#include "cmsis.h" + +extern "C" { +#if defined(TARGET_CORTEX_A) +#include "irq_ctrl.h" +#endif +} + +namespace mbed { +namespace internal { + +/** + * \defgroup mbed_SysTimer SysTimer class + * \ingroup platform-internal-api + * @{ + */ + +/** + * The SysTimer class is used to provide timing for system suspension, and + * the idle loop in TICKLESS mode. + * + * Template for speed for testing - only one instance will be used normally. + * + * @note SysTimer is not the part of Mbed API. + */ +template <uint32_t US_IN_TICK, bool IRQ = true> +class SysTimer: private mbed::TimerEvent, private mbed::NonCopyable<SysTimer<US_IN_TICK, IRQ> > { +public: + + /** + * Default constructor uses LPTICKER if available (so the timer will + * continue to run in deep sleep), else USTICKER. + */ + SysTimer(); + + SysTimer(const ticker_data_t *data); + + virtual ~SysTimer(); + + /** + * Get the interrupt number for the tick + * + * @return interrupt number + */ +#if TARGET_CORTEX_A + static IRQn_ID_t get_irq_number(); +#elif TARGET_CORTEX_M + static IRQn_Type get_irq_number(); +#endif + + /** + * Set the wake time + * + * Schedules an interrupt to cause wake-up in time for the event. Interrupt + * may be arranged early to account for latency. If the time has already + * passed, no interrupt will be scheduled. + * + * This is called from outside a critical section, as it is known to be + * a slow operation. + * + * If the wake time is already set, this is a no-op. But that check is racy, + * which means wake_time_set() should be rechecked after taking a critical + * section. + * + * As a side-effect, this clears the unacknowledged tick count - the caller + * is expected to use update_and_get_tick() after the suspend operation. + * + * @param at Wake up tick + * @warning If the ticker tick is already scheduled it needs to be cancelled first! + */ + void set_wake_time(uint64_t at); + + /** + * Check whether the wake time has passed + * + * This is a fast operation, based on checking whether the wake interrupt + * has run. + * + * @return true if the specified wake tick has passed + */ + bool wake_time_passed() const + { + return core_util_atomic_load_bool(&_wake_time_passed); + } + + /** + * Check whether wake timer is active + * + * @return true if the wake timer is active. + */ + bool wake_time_set() const + { + return core_util_atomic_load_bool(&_wake_time_set); + } + + /** + * Cancel any pending wake + */ + void cancel_wake(); + + /** + * Schedule an os tick to fire + * + * Ticks will be rescheduled automatically every tick until cancel_tick is called. + * + * A tick will be fired immediately if there are any unacknowledged ticks. + * + * @warning If a tick is already scheduled it needs to be cancelled first! + */ + void start_tick(); + + /** + * Acknowledge an os tick + * + * This will queue another os tick immediately if the os is running slow + */ + void acknowledge_tick(); + + /** + * Prevent any more scheduled ticks from triggering + * + * If called from OS tick context, there may be remaining unacknowledged ticks. + */ + void cancel_tick(); + + /** + * Check whether ticker is active + * + * Each time the tick interrupt fires, it is automatically rescheduled, + * so this will remain true once the tick is started, except during + * processing. + * + * @return true if the ticker is active. + */ + bool ticking() const + { + return core_util_atomic_load_bool(&_ticking); + } + + /** + * Check unacknowledged ticks + * + * Returns the count of how many times the OS timer has been queued minus + * the number of times is has been acknowledged. + * + * get_tick() - unacknowledged_ticks() should equal the OS's tick count, + * although such a calculation is not atomic if the ticker is currently running. + * + * @return number of unacknowledged ticks + */ + int unacknowledged_ticks() const + { + return core_util_atomic_load_u8(&_unacknowledged_ticks); + } + + /** Get the current tick count + * + * This count is updated by the ticker interrupt, if the ticker interrupt + * is running. It the ticker interrupt is not running, update_and_get_tick() + * should be used instead. + * + * This indicates how many ticks have been generated by the tick interrupt. + * The os_timer should equal this number minus the number of unacknowledged ticks. + * + * @return The number of ticks since timer creation. + */ + uint64_t get_tick() const; + + /** Update and get the current tick count + * + * This is a slow operation that reads the timer and adjusts for elapsed time. + * Can only be used when the ticker is not running, as there is no IRQ + * synchronization. + * + * This clears the unacknowledged tick counter - the caller is assumed to update + * their timer based on this return. + * + * @return The number of ticks since timer creation. + */ + uint64_t update_and_get_tick(); + + /** + * Returns time since last tick + * + * @return Relative time in microseconds + */ + us_timestamp_t get_time_since_tick() const; + + /** + * Get the time + * + * Returns the instantaneous precision time from underlying timer. + * This is a slow operation so should not be called from critical sections. + * + * @return Current time in microseconds + */ + us_timestamp_t get_time() const; + +protected: + virtual void handler(); + void _increment_tick(); + void _schedule_tick(); + uint64_t _elapsed_ticks() const; + static void _set_irq_pending(); + static void _clear_irq_pending(); + us_timestamp_t _time_us; + uint64_t _tick; + uint8_t _unacknowledged_ticks; + bool _wake_time_set; + bool _wake_time_passed; + bool _wake_early; + bool _ticking; + bool _deep_sleep_locked; +}; + +/** @} */ + +} +} + +#endif