mirror of https://github.com/ARMmbed/mbed-os.git
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.pull/6534/head
parent
4a5ac149ec
commit
953bbeb7de
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -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);
|
||||
|
||||
bool event_pending = false;
|
||||
while (!os_timer->suspend_time_passed() && !event_pending) {
|
||||
|
||||
core_util_critical_section_enter();
|
||||
uint32_t ticks_to_sleep = svcRtxKernelSuspend();
|
||||
if (ticks_to_sleep) {
|
||||
os_timer->schedule_tick(ticks_to_sleep);
|
||||
|
||||
if (osRtxInfo.kernel.pendSV) {
|
||||
event_pending = true;
|
||||
} else {
|
||||
sleep();
|
||||
|
||||
os_timer->cancel_tick();
|
||||
// calculate how long we slept
|
||||
elapsed_ticks = os_timer->update_tick();
|
||||
}
|
||||
svcRtxKernelResume(elapsed_ticks);
|
||||
core_util_critical_section_exit();
|
||||
|
||||
// Ensure interrupts get a chance to fire
|
||||
__ISB();
|
||||
}
|
||||
osKernelResume(os_timer->resume());
|
||||
}
|
||||
|
||||
#elif defined(FEATURE_UVISOR)
|
||||
|
|
Loading…
Reference in New Issue