-
Notifications
You must be signed in to change notification settings - Fork 2k
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
cpu: PM_NUM_MODES must only count non-IDLE modes #13475
Conversation
Also adapt the defines to the documentation - CPUs define up to 4 power modes (from zero, the lowest power mode, to PM_NUM_MODES-1, the highest) - >> there is an implicit extra idle mode (which has the number PM_NUM_MODES) << Previously on saml21 this would always generate pm_set(3) which is an illegal state. Now pm_layered will correctly generate pm_set(2) for IDLE modes. Idle power consumption dropped from 750µA to 368µA and wake-up from standby is also possible. (Before it would just enter STANDBY again as the mode register was never written with the illegal value.)
From the documentation: - CPUs define up to 4 power modes (from zero, the lowest power mode, to PM_NUM_MODES-1, the highest) - there is an implicit extra idle mode (which has the number PM_NUM_MODES)
The mode PM_NUM_MODES is the IDLE mode, so do not skip it.
Thanks for the fix! Will have a look at it, even though I don't have many boards if any available! |
Yeah, the reasoning was along the lines that a) usually there's no benefit in blocking idle, b) this allows one more blockable mode, c) there's always a mode to go to. |
Is there a way to prevent this in the future? Drop the extra mode, require implementations to actually count it, assert in pm_set_lowest() that the chosen mode is in range? |
|
Probably the better solution - In the first version of this PR I did that and added #ifndef PM_BLOCKER_INITIAL
#if PM_NUM_MODES == 4
#define PM_BLOCKER_INITIAL 0x01010101 /* block all but IDLE by default */
#elif PM_NUM_MODES == 3
#define PM_BLOCKER_INITIAL 0x00010101 /* block all but IDLE by default */
#elif PM_NUM_MODES == 2
#define PM_BLOCKER_INITIAL 0x00000101 /* block all but IDLE by default */
#elif PM_NUM_MODES == 1
#define PM_BLOCKER_INITIAL 0x00000000 /* block all but IDLE by default */
#endif
#endif because I thought the other implementations got it wrong and forgot to include the IDLE mode in Then I read the documentation again, cursed, and changed it back. |
FYI: SAMR30 looks fine with this patch |
Should I split this so we can get at least the changes for sam0 in? |
IMO that should be a compile time choice. Who wants to actually use multiple IDLE modes in a single application? |
Contribution description
From the documentation:
to
PM_NUM_MODES-1
, the highest)PM_NUM_MODES
)I must say that an 'implicit extra mode' is a very surprising concept, but most implementations did get it right that there are in fact
PM_NUM_MODES + 1
modes.This fixes the ones that didn't.
Testing procedure
Run
tests/periph_pm
and observe the power consumptionI tested the sam0 CPUs and manually checked the code of the other implementations.
Issues/PRs references
I noticed that saml21 would not wake up from STANDBY (mode 1) in
tests/periph_pm
.It would briefly wake up, but immediately go back to STANDBY.
It turned out that pm_layered would always call
pm_set(3)
, which is out of range.As a result, the
SLEEPMODE
register would never be written and the previous value (STANDBY) would be used.Another side effect was that the CPU never entered idle mode.
With this patch, IDLE consumption drops from 750µA to 368µA.