-
Notifications
You must be signed in to change notification settings - Fork 3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fixes for tickless and LPTICKER_DELAY_TICKS #7524
Conversation
Hi Russ I have started a full non regression for each STM32 family. In parallel, I quickly checked TICKLESS mode with F401. I agree status is much better. For the moment, I only added some DeepSleepLock in tests-mbed_drivers-lp_ticker. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Potential inconsistency between result returned by sleep_manager_can_deep_sleep()
and action performed by sleep_manager_sleep_auto()
.
hal/mbed_sleep_manager.c
Outdated
@@ -196,7 +203,11 @@ void sleep_manager_sleep_auto(void) | |||
#ifdef MBED_DEBUG | |||
hal_sleep(); | |||
#else | |||
if (sleep_manager_can_deep_sleep()) { | |||
if (sleep_manager_can_deep_sleep() | |||
#if DEVICE_LPTICKER && (LPTICKER_DELAY_TICKS > 0) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If lp ticker's Timeout object is in use (i.e. lp_ticker_get_timeout_pending()
returns true
) and deep-sleep is not locked by other features (i.e. lock_count==1
), then:
sleep_manager_can_deep_sleep()
returnstrue
- indicates that we can put board into deep-sleep mode.sleep_manager_sleep_auto()
puts the board into the sleep mode (not deep-sleep).
It looks like a design issue since we can not relay on sleep_manager_can_deep_sleep()
function.
From the user perspective it can be very misleading. From the testing perspective sleep_manager_can_deep_sleep()
function is used in tests to check if current environment state allows to go into deep-sleep mode which is to be tested. So in some cases the test may test sleep mode instead of required deep-sleep mode.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like a design issue since we can not relay on sleep_manager_can_deep_sleep() function.
where this comes from?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree with @mprse, sleep_manager_can_deep_sleep()
shouldn't be updated this way. I do understand the purpose, but think this change should be test specific, not general.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please take a look at these changes c85856b.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some possible alternatives I can think of are:
- Modify tests to suspend the OS before running the tests - this may be intrusive as you can no longer use most OS primitives
- Assert in tests using a different function - something like sleep_manager_can_deep_sleep_test()
- Assert something different in the tests, such as time actually spent in deep sleep
Do you have any thoughts or preferences on this @mprse and @fkjagodzinski?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In my opinion first bullet is ok, but only for low level tests (HAL) where target specific drivers are tested, where the OS can be omitted. For driver layer tests I think that OS should be working normally and tests should take into consideration possible influence of the OS like systick handling, task scheduling, ticker interrupts, etc. So I suggest to use second bullet for upper layer tests.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since one of the problems is:
The Timeout object used by the lp ticker wrapper locks deep sleep at various times causing tests which assert that deep sleep is allowed to fail
we could modify the tests to wait for the deep sleep to be unlocked before calling sleep()
. But even this would require using critical section, so would also introduce more complexity to tests.
Adding sleep_manager_can_deep_sleep_test()
seems straight forward, but such change would mean we accept that tests are occasionally run in an environment different from what they were supposed to. Simply put, the test result can be meaningless sometimes.
In my opinion the most honest solution would be adding
#if DEVICE_LPTICKER && (LPTICKER_DELAY_TICKS > 0)
#error [NOT_SUPPORTED] Test not supported for this target
#endif
or executing affected test cases conditionally based on LPTICKER_DELAY_TICKS > 0
.
hal/mbed_sleep_manager.c
Outdated
return deep_sleep_lock == 0 ? true : false; | ||
uint32_t lock_count = deep_sleep_lock; | ||
#if DEVICE_LPTICKER && (LPTICKER_DELAY_TICKS > 0) | ||
if (lp_ticker_get_timeout_pending() && (lock_count > 0)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(lock_count > 0)
- is this condition needed?
In case when lp ticker's Timeout object is in use deep-sleep is locked (i.e. lock_count > 0
).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The check is to prevent underflow. If this function is wrapped in a critical section then the check wouldn't be needed, as lock_count would always be at least 1 if lp_ticker_get_timeout_pending() returned true.
More detailed status with NUCLEO_F401RE: I applied few patches: And I still got issues with:
[1531833600.45][CONN][RXD] >>> Running case #5: 'Schedule zero ticks'... |
Regarding
So the first bullet is the case when we have some hardware limitations like on
In this case the nearest interrupt which can be set is mbed-os/targets/TARGET_NORDIC/TARGET_NRF5x/common_rtc.c Lines 198 to 205 in c29fe89
Personally I prefer current option since usage of Regarding second bullet I'm not sure if I correctly understand the problem. Can you provide some use case for this? |
Hi @mprse, the primary problem is the second point - some low power ticker hardware cannot be written to twice within a certain number of low power clock cycles (LPTICKER_DELAY_TICKS ticks).
If the next tick time is written to the low power ticker immediately the new match time will be dropped, as the hardware is still trying to set the first match value. Options to work around this are:
Option 1. is what was done prior to the ticker HAL specification. The problem with this is interrupt latency is impacted. An example in practice is the NUCLEO_F401RE. It has a low power ticker clock speed of 8KHz and requires 3 clock cycles between writes. This means that back-to-back writes will block for 366us in a critical section. Option 2. was considered but it was found that a large number of targets have this low power ticker hardware behavior. Vendors with effected targets include ST, Nuvoton and OnSemi to name a few. Because this would rule out tickless for many targets this option was less than ideal as well. Note - the large number of vendors/targets impacted was also one of the main reason this was done in a common layer. Option 3. both preserves interrupt latency and allows targets with this low power ticker behavior still implement the low power ticker API. Compared to Option 1, power savings is better since the CPU can go into sleep mode rather than busy waiting. Unfortunately it does add complexity and interferes with deep sleep tests. @mprse do you know of any alternatives which could simplify this? These were the only options that I could think of, but if there is a better way to do it would be great. |
@c1728p9 Thanks Russ for detailed explanation of the problem. It looks like option number 3 despite its complexity is the best solution for now. We have disused with @fkjagodzinski possible solutions for the
Since |
@mprse @fkjagodzinski I updated this PR to address the feedback you gave me. In specific I added and updated the test to use the function |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@c1728p9 Looks good to me.
What bothers me is that test for sleep_manager_can_deep_sleep_test_check()
is missing (even though this function is intended for use in testing). I think it should be added or task for this should be created.
I suggest also to add information in the description of sleep_manager_can_deep_sleep_test_check()
that timeout is set to 2 ms.
/morph build |
hal/mbed_lp_ticker_wrapper.h
Outdated
/** | ||
* Wrapper around lp_ticker_set_interrupt to prevent blocking | ||
* | ||
* Problems this function is solving: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
Build : SUCCESSBuild number : 2710 Triggering tests/morph test |
Exporter Build : SUCCESSBuild number : 2339 |
Test : FAILUREBuild number : 2441 |
When the define LPTICKER_DELAY_TICKS is set deep sleep can be randomly disallowed when using the low power ticker. This is because a Timer object, which locks deep sleep, is used to protect from back-to-back writes to lp tickers which can't support that. This causes tests which assert that deep sleep is allowed to intermittently fail. To fix this intermittent failure this patch adds the function sleep_manager_can_deep_sleep_test_check() which checks if deep sleep is allowed over a duration. It updates all the tests to use sleep_manager_can_deep_sleep_test_check() rather than sleep_manager_can_deep_sleep() so the tests work even if deep sleep is spuriously blocked.
Update the low power ticker wrapper code so it does not violate any properties of the ticker specification. In specific this patch fixes the following: - Prevent spurious interrupts - Fire interrupt only when the ticker times increments to or past the value set by ticker_set_interrupt - Disable interrupts when ticker_init is called
/morph build |
Build : FAILUREBuild number : 2820 |
Fix the HAL common_tickers and sleep tests so they work correctly when the define LPTICKER_DELAY_TICKS is set.
To handle timer rollovers the test tests-mbed_hal-common_tickers_freq calls intf->set_interrupt(0). For this to work correctly the ticker implementation must fire an interrupt on every rollover event though intf->set_interrupt(0) was called only once. Whether an interrupt will fire only once or multiple times is undefined behavior which cannot be relied upon. To avoid this undefined behavior this patch continually schedules an interrupt and performs overflow detection on every read. This also removes the possibility of race conditions due to overflowCounter incrementing at the wrong time.
Only reschedule the Timeout object in the low power ticker wrapper if it is not already pending.
/morph build |
Build : SUCCESSBuild number : 2835 Triggering tests/morph test |
Exporter Build : SUCCESSBuild number : 2464 |
Test : FAILUREBuild number : 2585 |
/morph test |
/morph uvisor-test |
Test : SUCCESSBuild number : 2598 |
Fixes for tickless and LPTICKER_DELAY_TICKS
Description
This PR fixes problems that occur when both tickless and LPTICKER_DELAY_TICKS are turned on. The two primary problems are:
The tests susceptible to problem 1 are:
The tests susceptible to problem 2 are:
This PR fixes the problems mentioned above. Unfortunately, there are still additional problems which need to be addressed. Further fixes require:
Pull request type