Skip to content

Commit eecc67b

Browse files
committed
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.
1 parent 48d8c77 commit eecc67b

File tree

3 files changed

+109
-40
lines changed

3 files changed

+109
-40
lines changed

rtos/TARGET_CORTEX/SysTimer.cpp

Lines changed: 60 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#if DEVICE_LPTICKER
2525

2626
#include "hal/lp_ticker_api.h"
27+
#include "mbed_critical.h"
2728
#include "rtx_core_cm.h"
2829
extern "C" {
2930
#include "rtx_lib.h"
@@ -45,6 +46,8 @@ SysTimer::SysTimer() :
4546
TimerEvent(get_lp_ticker_data()), _start_time(0), _tick(0)
4647
{
4748
_start_time = ticker_read_us(_ticker_data);
49+
_suspend_time_passed = true;
50+
_suspended = false;
4851
}
4952

5053
void SysTimer::setup_irq()
@@ -61,23 +64,30 @@ void SysTimer::setup_irq()
6164
#endif
6265
}
6366

64-
void SysTimer::schedule_tick(uint32_t delta)
67+
void SysTimer::suspend(uint32_t ticks)
6568
{
66-
insert_absolute(_start_time + (_tick + delta) * 1000000ULL / OS_TICK_FREQ);
67-
}
69+
core_util_critical_section_enter();
6870

69-
void SysTimer::cancel_tick()
70-
{
71-
remove();
71+
schedule_tick(ticks);
72+
_suspend_time_passed = false;
73+
_suspended = true;
74+
75+
core_util_critical_section_exit();
7276
}
7377

74-
uint32_t SysTimer::get_tick()
78+
bool SysTimer::suspend_time_passed()
7579
{
76-
return _tick & 0xFFFFFFFF;
80+
return _suspend_time_passed;
7781
}
7882

79-
uint32_t SysTimer::update_tick()
83+
uint32_t SysTimer::resume()
8084
{
85+
core_util_critical_section_enter();
86+
87+
_suspended = false;
88+
_suspend_time_passed = true;
89+
remove();
90+
8191
uint64_t new_tick = (ticker_read_us(_ticker_data) - _start_time) * OS_TICK_FREQ / 1000000;
8292
if (new_tick > _tick) {
8393
// Don't update to the current tick. Instead, update to the
@@ -88,9 +98,34 @@ uint32_t SysTimer::update_tick()
8898
}
8999
uint32_t elapsed_ticks = new_tick - _tick;
90100
_tick = new_tick;
101+
102+
core_util_critical_section_exit();
91103
return elapsed_ticks;
92104
}
93105

106+
void SysTimer::schedule_tick(uint32_t delta)
107+
{
108+
core_util_critical_section_enter();
109+
110+
insert_absolute(_start_time + (_tick + delta) * 1000000ULL / OS_TICK_FREQ);
111+
112+
core_util_critical_section_exit();
113+
}
114+
115+
void SysTimer::cancel_tick()
116+
{
117+
core_util_critical_section_enter();
118+
119+
remove();
120+
121+
core_util_critical_section_exit();
122+
}
123+
124+
uint32_t SysTimer::get_tick()
125+
{
126+
return _tick & 0xFFFFFFFF;
127+
}
128+
94129
us_timestamp_t SysTimer::get_time()
95130
{
96131
return ticker_read_us(_ticker_data);
@@ -100,24 +135,36 @@ SysTimer::~SysTimer()
100135
{
101136
}
102137

103-
void SysTimer::set_irq_pending()
138+
void SysTimer::_set_irq_pending()
104139
{
140+
// Protected function synchronized externally
141+
105142
#if (defined(NO_SYSTICK))
106143
NVIC_SetPendingIRQ(mbed_get_m0_tick_irqn());
107144
#else
108145
SCB->ICSR = SCB_ICSR_PENDSTSET_Msk;
109146
#endif
110147
}
111148

112-
void SysTimer::increment_tick()
149+
void SysTimer::_increment_tick()
113150
{
151+
// Protected function synchronized externally
152+
114153
_tick++;
115154
}
116155

117156
void SysTimer::handler()
118157
{
119-
set_irq_pending();
120-
increment_tick();
158+
core_util_critical_section_enter();
159+
160+
if (_suspended) {
161+
_suspend_time_passed = true;
162+
} else {
163+
_set_irq_pending();
164+
_increment_tick();
165+
}
166+
167+
core_util_critical_section_exit();
121168
}
122169

123170
}

rtos/TARGET_CORTEX/SysTimer.h

Lines changed: 32 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,34 @@ class SysTimer: private mbed::TimerEvent, private mbed::NonCopyable<SysTimer> {
5656
*/
5757
static void setup_irq();
5858

59+
/**
60+
* Set wakeup time and schedule a wakeup event after delta ticks
61+
*
62+
* After suspend has been called the function suspend_time_passed
63+
* can be used to determine if the suspend time has passed.
64+
*
65+
* @param delta Ticks to remain suspended
66+
*/
67+
void suspend(uint32_t delta);
68+
69+
/**
70+
* Check if the suspend time has passed
71+
*
72+
* @return true if the specified number of ticks has passed otherwise false
73+
*/
74+
bool suspend_time_passed();
75+
76+
/**
77+
* Exit suspend mode and return elapsed ticks
78+
*
79+
* Due to a scheduling issue, the number of ticks returned is decremented
80+
* by 1 so that a handler can be called and update to the current value.
81+
* This allows scheduling restart successfully after the OS is resumed.
82+
*
83+
* @return the number of elapsed ticks minus 1
84+
*/
85+
uint32_t resume();
86+
5987
/**
6088
* Schedule an os tick to fire
6189
*
@@ -77,17 +105,6 @@ class SysTimer: private mbed::TimerEvent, private mbed::NonCopyable<SysTimer> {
77105
*/
78106
uint32_t get_tick();
79107

80-
/**
81-
* Update the internal tick count
82-
*
83-
* @return The number of ticks incremented
84-
*
85-
* @note Due to a scheduling issue, the number of ticks returned is decremented
86-
* by 1 so that a handler can be called and update to the current value.
87-
* This allows scheduling restart successfully after the OS is resumed.
88-
*/
89-
uint32_t update_tick();
90-
91108
/**
92109
* Get the time
93110
*
@@ -97,10 +114,12 @@ class SysTimer: private mbed::TimerEvent, private mbed::NonCopyable<SysTimer> {
97114

98115
protected:
99116
virtual void handler();
100-
void increment_tick();
101-
static void set_irq_pending();
117+
void _increment_tick();
118+
static void _set_irq_pending();
102119
us_timestamp_t _start_time;
103120
uint64_t _tick;
121+
bool _suspend_time_passed;
122+
bool _suspended;
104123
};
105124

106125
/**

rtos/TARGET_CORTEX/mbed_rtx_idle.cpp

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -95,21 +95,24 @@ uint32_t OS_Tick_GetInterval (void) {
9595

9696
static void default_idle_hook(void)
9797
{
98-
uint32_t elapsed_ticks = 0;
99-
100-
core_util_critical_section_enter();
101-
uint32_t ticks_to_sleep = svcRtxKernelSuspend();
102-
if (ticks_to_sleep) {
103-
os_timer->schedule_tick(ticks_to_sleep);
104-
105-
sleep();
106-
107-
os_timer->cancel_tick();
108-
// calculate how long we slept
109-
elapsed_ticks = os_timer->update_tick();
98+
uint32_t ticks_to_sleep = osKernelSuspend();
99+
os_timer->suspend(ticks_to_sleep);
100+
101+
bool event_pending = false;
102+
while (!os_timer->suspend_time_passed() && !event_pending) {
103+
104+
core_util_critical_section_enter();
105+
if (osRtxInfo.kernel.pendSV) {
106+
event_pending = true;
107+
} else {
108+
sleep();
109+
}
110+
core_util_critical_section_exit();
111+
112+
// Ensure interrupts get a chance to fire
113+
__ISB();
110114
}
111-
svcRtxKernelResume(elapsed_ticks);
112-
core_util_critical_section_exit();
115+
osKernelResume(os_timer->resume());
113116
}
114117

115118
#elif defined(FEATURE_UVISOR)

0 commit comments

Comments
 (0)