From 953bbeb7de60bce65039962c421ce6f7b287adba Mon Sep 17 00:00:00 2001 From: Russ Butler Date: Wed, 28 Mar 2018 00:31:57 +0200 Subject: [PATCH] Update idle loop to reduce calls to suspend Change tickless handling to use public RTX calls and to prevent unnecessary calls to suspend/resume by looping until the kernel needs to be resumed. --- rtos/TARGET_CORTEX/SysTimer.cpp | 77 ++++++++++++++++++++++------ rtos/TARGET_CORTEX/SysTimer.h | 45 +++++++++++----- rtos/TARGET_CORTEX/mbed_rtx_idle.cpp | 25 +++++---- 3 files changed, 108 insertions(+), 39 deletions(-) diff --git a/rtos/TARGET_CORTEX/SysTimer.cpp b/rtos/TARGET_CORTEX/SysTimer.cpp index fc2e06bc36..632a1314cf 100644 --- a/rtos/TARGET_CORTEX/SysTimer.cpp +++ b/rtos/TARGET_CORTEX/SysTimer.cpp @@ -24,6 +24,7 @@ #if DEVICE_LOWPOWERTIMER #include "hal/lp_ticker_api.h" +#include "mbed_critical.h" #include "rtx_core_cm.h" extern "C" { #include "rtx_lib.h" @@ -45,6 +46,8 @@ SysTimer::SysTimer() : TimerEvent(get_lp_ticker_data()), _start_time(0), _tick(0) { _start_time = ticker_read_us(_ticker_data); + _suspend_time_passed = true; + _suspended = false; } void SysTimer::setup_irq() @@ -61,23 +64,30 @@ void SysTimer::setup_irq() #endif } -void SysTimer::schedule_tick(uint32_t delta) +void SysTimer::suspend(uint32_t ticks) { - insert_absolute(_start_time + (_tick + delta) * 1000000ULL / OS_TICK_FREQ); + core_util_critical_section_enter(); + + schedule_tick(ticks); + _suspend_time_passed = false; + _suspended = true; + + core_util_critical_section_exit(); } -void SysTimer::cancel_tick() +bool SysTimer::suspend_time_passed() { + return _suspend_time_passed; +} + +uint32_t SysTimer::resume() +{ + core_util_critical_section_enter(); + + _suspended = false; + _suspend_time_passed = true; remove(); -} -uint32_t SysTimer::get_tick() -{ - return _tick & 0xFFFFFFFF; -} - -uint32_t SysTimer::update_tick() -{ uint64_t new_tick = (ticker_read_us(_ticker_data) - _start_time) * OS_TICK_FREQ / 1000000; if (new_tick > _tick) { // Don't update to the current tick. Instead, update to the @@ -88,9 +98,34 @@ uint32_t SysTimer::update_tick() } uint32_t elapsed_ticks = new_tick - _tick; _tick = new_tick; + + core_util_critical_section_exit(); return elapsed_ticks; } +void SysTimer::schedule_tick(uint32_t delta) +{ + core_util_critical_section_enter(); + + insert_absolute(_start_time + (_tick + delta) * 1000000ULL / OS_TICK_FREQ); + + core_util_critical_section_exit(); +} + +void SysTimer::cancel_tick() +{ + core_util_critical_section_enter(); + + remove(); + + core_util_critical_section_exit(); +} + +uint32_t SysTimer::get_tick() +{ + return _tick & 0xFFFFFFFF; +} + us_timestamp_t SysTimer::get_time() { return ticker_read_us(_ticker_data); @@ -100,8 +135,10 @@ SysTimer::~SysTimer() { } -void SysTimer::set_irq_pending() +void SysTimer::_set_irq_pending() { + // Protected function synchronized externally + #if (defined(NO_SYSTICK)) NVIC_SetPendingIRQ(mbed_get_m0_tick_irqn()); #else @@ -109,15 +146,25 @@ void SysTimer::set_irq_pending() #endif } -void SysTimer::increment_tick() +void SysTimer::_increment_tick() { + // Protected function synchronized externally + _tick++; } void SysTimer::handler() { - set_irq_pending(); - increment_tick(); + core_util_critical_section_enter(); + + if (_suspended) { + _suspend_time_passed = true; + } else { + _set_irq_pending(); + _increment_tick(); + } + + core_util_critical_section_exit(); } } diff --git a/rtos/TARGET_CORTEX/SysTimer.h b/rtos/TARGET_CORTEX/SysTimer.h index 2af7c8ec33..e43668405f 100644 --- a/rtos/TARGET_CORTEX/SysTimer.h +++ b/rtos/TARGET_CORTEX/SysTimer.h @@ -56,6 +56,34 @@ public: */ static void setup_irq(); + /** + * Set wakeup time and schedule a wakeup event after delta ticks + * + * After suspend has been called the function suspend_time_passed + * can be used to determine if the suspend time has passed. + * + * @param delta Ticks to remain suspended + */ + void suspend(uint32_t delta); + + /** + * Check if the suspend time has passed + * + * @return true if the specified number of ticks has passed otherwise false + */ + bool suspend_time_passed(); + + /** + * Exit suspend mode and return elapsed ticks + * + * Due to a scheduling issue, the number of ticks returned is decremented + * by 1 so that a handler can be called and update to the current value. + * This allows scheduling restart successfully after the OS is resumed. + * + * @return the number of elapsed ticks minus 1 + */ + uint32_t resume(); + /** * Schedule an os tick to fire * @@ -77,17 +105,6 @@ public: */ uint32_t get_tick(); - /** - * Update the internal tick count - * - * @return The number of ticks incremented - * - * @note Due to a scheduling issue, the number of ticks returned is decremented - * by 1 so that a handler can be called and update to the current value. - * This allows scheduling restart successfully after the OS is resumed. - */ - uint32_t update_tick(); - /** * Get the time * @@ -97,10 +114,12 @@ public: protected: virtual void handler(); - void increment_tick(); - static void set_irq_pending(); + void _increment_tick(); + static void _set_irq_pending(); us_timestamp_t _start_time; uint64_t _tick; + bool _suspend_time_passed; + bool _suspended; }; /** diff --git a/rtos/TARGET_CORTEX/mbed_rtx_idle.cpp b/rtos/TARGET_CORTEX/mbed_rtx_idle.cpp index 6e568e415c..a4a003fa9b 100644 --- a/rtos/TARGET_CORTEX/mbed_rtx_idle.cpp +++ b/rtos/TARGET_CORTEX/mbed_rtx_idle.cpp @@ -95,21 +95,24 @@ uint32_t OS_Tick_GetInterval (void) { static void default_idle_hook(void) { - uint32_t elapsed_ticks = 0; + uint32_t ticks_to_sleep = osKernelSuspend(); + os_timer->suspend(ticks_to_sleep); - core_util_critical_section_enter(); - uint32_t ticks_to_sleep = svcRtxKernelSuspend(); - if (ticks_to_sleep) { - os_timer->schedule_tick(ticks_to_sleep); + bool event_pending = false; + while (!os_timer->suspend_time_passed() && !event_pending) { - sleep(); + core_util_critical_section_enter(); + if (osRtxInfo.kernel.pendSV) { + event_pending = true; + } else { + sleep(); + } + core_util_critical_section_exit(); - os_timer->cancel_tick(); - // calculate how long we slept - elapsed_ticks = os_timer->update_tick(); + // Ensure interrupts get a chance to fire + __ISB(); } - svcRtxKernelResume(elapsed_ticks); - core_util_critical_section_exit(); + osKernelResume(os_timer->resume()); } #elif defined(FEATURE_UVISOR)