Skip to content
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

sys/pm_layered: use array representation, get rid of implicit IDLE mode #17895

Merged
merged 5 commits into from
Apr 8, 2022

Conversation

benpicco
Copy link
Contributor

@benpicco benpicco commented Apr 2, 2022

Contribution description

PM_NUM_MODES is confusing as it must not include the default IDLE mode.
In #17883 I added the IDLE mode to PM_NUM_MODES of samd5x so it can be blocked too (falling back to polling the CPU), which introduced an introducing.

I think this was done to fit all blockers for the modes into an uint32_t, but is is entirely unnecessary as the blockers are typically accessed as an array anyway.

So always make pm_blocker_t an array to remove the limitation to 4 modes.

Testing procedure

This should retain the current behavior. samd5x was not changed as it already implements the new convention.
native was accidentally already using the new convention, causing it not to enter sleep at all with the current implementation. As a side effect, this is now fixed by this PR.

Issues/PRs references

#13475

@github-actions github-actions bot added Area: cpu Area: CPU/MCU ports Area: sys Area: System Platform: ARM Platform: This PR/issue effects ARM-based platforms Platform: ESP Platform: This PR/issue effects ESP-based platforms labels Apr 2, 2022
@benpicco benpicco requested a review from maribu April 2, 2022 18:39
@benpicco benpicco added Process: API change Integration Process: PR contains or issue proposes an API change. Should be handled with care. CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR labels Apr 2, 2022
@github-actions github-actions bot added the Area: examples Area: Example Applications label Apr 2, 2022
@kaspar030
Copy link
Contributor

I think this was done to fit all blockers for the modes into an uint32_t, but is is entirely unnecessary as the blockers are typically accessed as an array anyway.

well, this was done to minimize the irq off phase, and handle blocker changes that happen while pm_set_lowest() is figuring out which mode to set, efficiently.
the current blocker value is copied into a local variable (hopefully into a register), the mode is figured out, then the blocker value is compared again to see if it has changed in the meantime, and the mode is not set in that case.
I wanted to minimize the cases where the scheduler goes into deep-sleep, just to wake up right away.
Maybe premature optimization.

Can we measure the time spent in pm_set_lowest() before and after this PR?

@benpicco
Copy link
Contributor Author

benpicco commented Apr 3, 2022

It's actually a bit faster with the new code:

master
diff --git a/sys/pm_layered/pm.c b/sys/pm_layered/pm.c
index 2d2b0e0aec..27195c21c8 100644
--- a/sys/pm_layered/pm.c
+++ b/sys/pm_layered/pm.c
@@ -44,6 +44,8 @@ static pm_blocker_t pm_blocker = { .val_u32 = PM_BLOCKER_INITIAL };
 
 void pm_set_lowest(void)
 {
+    LED1_ON;
+
     pm_blocker_t blocker = { .val_u32 = atomic_load_u32(&pm_blocker.val_u32) };
     unsigned mode = PM_NUM_MODES;
     while (mode) {
@@ -57,9 +59,11 @@ void pm_set_lowest(void)
     unsigned state = irq_disable();
     if (blocker.val_u32 == pm_blocker.val_u32) {
         DEBUG("pm: setting mode %u\n", mode);
+        LED1_OFF;
         pm_set(mode);
     }
     else {
+        LED1_OFF;
         DEBUG("pm: mode block changed\n");
     }
     irq_restore(state);

bmp_23_000

this PR
diff --git a/sys/pm_layered/pm.c b/sys/pm_layered/pm.c
index f5645c88f2..d3c798c326 100644
--- a/sys/pm_layered/pm.c
+++ b/sys/pm_layered/pm.c
@@ -59,6 +59,7 @@ static pm_blocker_t pm_blocker = { .val_u8 = PM_BLOCKER_INITIAL };
 
 void pm_set_lowest(void)
 {
+    LED1_ON;
     unsigned mode = PM_NUM_MODES;
 
     /* set lowest mode if blocker is still the same */
@@ -71,6 +72,7 @@ void pm_set_lowest(void)
     }
 
     if (mode != PM_NUM_MODES) {
+        LED1_OFF;
         pm_set(mode);
     }
     irq_restore(state);

bmp_23_001

I tested with examples/timer_periodic_wakeup on same54-xpro where I set the CPU to run at 1.2 MHz and defined LED1 as a spare GPIO that I connected to the scope.

same54-xpro
diff --git a/boards/same54-xpro/include/board.h b/boards/same54-xpro/include/board.h
index 45f57e455f..9d90648455 100644
--- a/boards/same54-xpro/include/board.h
+++ b/boards/same54-xpro/include/board.h
@@ -59,6 +59,13 @@ extern "C" {
 #define LED0_TOGGLE         (LED_PORT.OUTTGL.reg = LED0_MASK)
 /** @} */
 
+#define LED1_PIN            GPIO_PIN(PC, 7)
+#define LED1_MASK           (1 << 7)
+#define LED1_ON             (LED_PORT.OUTSET.reg = LED1_MASK)
+#define LED1_OFF            (LED_PORT.OUTCLR.reg = LED1_MASK)
+#define LED1_TOGGLE         (LED_PORT.OUTTGL.reg = LED1_MASK)
+
+
 /**
  * @name SW0 (Button) pin definitions
  * @{
diff --git a/boards/same54-xpro/include/periph_conf.h b/boards/same54-xpro/include/periph_conf.h
index fbd66a1024..086e4c4a9a 100644
--- a/boards/same54-xpro/include/periph_conf.h
+++ b/boards/same54-xpro/include/periph_conf.h
@@ -33,7 +33,7 @@ extern "C" {
  *          frequency to 12 MHz.
  */
 #ifndef USE_XOSC_ONLY
-#define USE_XOSC_ONLY       (0)
+#define USE_XOSC_ONLY       (1)
 #endif
 
 /**
@@ -49,7 +49,7 @@ extern "C" {
  */
 #ifndef CLOCK_CORECLOCK
 #if USE_XOSC_ONLY
-#define CLOCK_CORECLOCK     XOSC1_FREQUENCY
+#define CLOCK_CORECLOCK     XOSC1_FREQUENCY/10
 #else
 #define CLOCK_CORECLOCK     MHZ(120)
 #endif

Copy link
Member

@maribu maribu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ACK. Looks good to me and doesn't change the logic for when to go to sleep and when not.

sys/pm_layered/pm.c Outdated Show resolved Hide resolved
sys/include/pm_layered.h Outdated Show resolved Hide resolved
sys/pm_layered/pm.c Outdated Show resolved Hide resolved
@kaspar030
Copy link
Contributor

kaspar030 commented Apr 4, 2022

I tested with examples/timer_periodic_wakeup on same54-xpro where I set the CPU to run at 1.2 MHz and defined LED1 as a spare GPIO that I connected to the scope.

👍

Thanks for testing!

@github-actions github-actions bot added the Area: tests Area: tests and testing framework label Apr 4, 2022
@benpicco
Copy link
Contributor Author

benpicco commented Apr 7, 2022

@OlegHahm can we have this in for the release? It does not change behavior but makes it more consistent.

@OlegHahm OlegHahm merged commit f3ffe13 into RIOT-OS:master Apr 8, 2022
@benpicco benpicco deleted the pm_blocker_array branch April 8, 2022 12:06
benpicco added a commit to benpicco/RIOT that referenced this pull request Apr 21, 2022
This is already unblocked and will trigger an assertion.
The code is still broken as other modes might be unblocked too,
but at least it is just as broken as it was before RIOT-OS#17895
OlegHahm pushed a commit to OlegHahm/RIOT that referenced this pull request Apr 21, 2022
This is already unblocked and will trigger an assertion.
The code is still broken as other modes might be unblocked too,
but at least it is just as broken as it was before RIOT-OS#17895

(cherry picked from commit 520aa2d)
@OlegHahm OlegHahm added this to the Release 2022.04 milestone Apr 25, 2022
Comment on lines +152 to +160
/*
* Enable deep sleep power mode (e.g. STOP mode on STM32) which
* in general provides RAM retention after wake-up.
*/
#if IS_USED(MODULE_PM_LAYERED)
for (unsigned i = 1; i < PM_NUM_MODES; ++i) {
pm_unblock(i);
}
#endif
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't get this. Why would one decrement a ref counter with no coordination?

It triggers the assertion in pm.c on non-STM32 boards right away, because not every ref counter is higher than 1. But this is bound to break any periph driver than explicitly requested a certain clock.

We should rather try to adapt the periph_uart implementation to not keep a clock required after TX is completed when no RX callback is set.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area: cpu Area: CPU/MCU ports Area: examples Area: Example Applications Area: sys Area: System Area: tests Area: tests and testing framework CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR Platform: ARM Platform: This PR/issue effects ARM-based platforms Platform: ESP Platform: This PR/issue effects ESP-based platforms Process: API change Integration Process: PR contains or issue proposes an API change. Should be handled with care.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants