ztimer: fix required_pm_mode initialization#15911
ztimer: fix required_pm_mode initialization#15911vincent-d wants to merge 3 commits intoRIOT-OS:masterfrom
Conversation
For ZTIMER_USEC and ZTIMER_MSEC, the required_pm_mode should be set on the base clock (ZTIMER_USEC_BASE and ZTIMER_MSEC_BASE respectively) as they represent the hardware clocks that have pm constraints.
convert and convert_frac clocks do not have om constraints, thus setting their required_pm_mode to ZTIMER_CLOCK_NO_REQUIRED_PM_MODE.
adjust do not exist anymore and have been replaced by adjust_set and adjust_sleep.
|
@jue89 I think this change is valid, could you double check? |
|
Good catch! I never unblocked PM mode 0 before ... so this bug never showed up on my application. Code-wise this looks good to me, too. Furthermore, no board use CONFIG_ZTIMER_.*_ADJUST, no fixes required there as well. |
|
it is not ztimer(which scale ever) that needs a specific pm but its base timer there for the configuration value should be |
|
I am also very fine with rebaseing and editing #15715 after this is merged. If this is faster. |
jue89
left a comment
There was a problem hiding this comment.
As advertised, I've tested this PR using the samr30-xpro. Sorry that this took so long ...
Power-savings are still achieved - so I'm fine with this PR. Just some minor suggestions.
Hacked-together test based on the hello-world example
diff --git a/examples/hello-world/Makefile b/examples/hello-world/Makefile
index 258d8e9baf..b72257d9ff 100644
--- a/examples/hello-world/Makefile
+++ b/examples/hello-world/Makefile
@@ -12,6 +12,16 @@ RIOTBASE ?= $(CURDIR)/../..
# development process:
DEVELHELP ?= 1
+USEMODULE += gnrc_netdev_default
+USEMODULE += auto_init_gnrc_netif
+
+USEMODULE += ztimer ztimer_usec ztimer_msec ztimer_periph_rtt ztimer_xtimer_compat
+USEMODULE += pm_layered
+
+CFLAGS += '-DCONFIG_ZTIMER_MSEC_REQUIRED_PM_MODE=0'
+CFLAGS += '-DCONFIG_ZTIMER_USEC_REQUIRED_PM_MODE=1'
+CFLAGS += '-DPM_BLOCKER_INITIAL=0x00000000'
+
# Change this to 0 show compiler invocation lines by default:
QUIET ?= 1
diff --git a/examples/hello-world/main.c b/examples/hello-world/main.c
index f51bf8c0a0..fd915fb6b5 100644
--- a/examples/hello-world/main.c
+++ b/examples/hello-world/main.c
@@ -21,6 +21,14 @@
#include <stdio.h>
+#include "net/netif.h"
+#include "ztimer.h"
+#include "timex.h"
+
+static void callback (void * arg) {
+ puts((char*) arg);
+}
+
int main(void)
{
puts("Hello World!");
@@ -28,5 +36,20 @@ int main(void)
printf("You are running RIOT on a(n) %s board.\n", RIOT_BOARD);
printf("This board features a(n) %s MCU.\n", RIOT_MCU);
+ /* The SAM-R30 board boots with its netif enabled and draws several mA of current. */
+ /* Send it to sleep mode ... */
+ netif_t *iface = netif_iter(NULL);
+ netopt_state_t state = NETOPT_STATE_SLEEP;
+ netif_set_opt(iface, NETOPT_STATE, 0, &state, sizeof(netopt_state_t));
+
+ /* 1. Run a callback after 3s */
+ static ztimer_t cb_timer = {.callback = callback, .arg = "Hello World"};
+ ztimer_set(ZTIMER_USEC, &cb_timer, 3 * US_PER_SEC);
+
+ /* 2. Sleep the current thread for 60s */
+ ztimer_sleep(ZTIMER_MSEC, 60 * MS_PER_SEC);
+
+ while (true) {}
+
return 0;
}| LOG_DEBUG("ztimer_init(): ZTIMER_MSEC setting adjust_sleep value to %i\n", | ||
| CONFIG_ZTIMER_USEC_ADJUST_SLEEP ); |
There was a problem hiding this comment.
| LOG_DEBUG("ztimer_init(): ZTIMER_MSEC setting adjust_sleep value to %i\n", | |
| CONFIG_ZTIMER_USEC_ADJUST_SLEEP ); | |
| LOG_DEBUG("ztimer_init(): ZTIMER_MSEC setting adjust_sleep value to %i\n", | |
| CONFIG_ZTIMER_USEC_ADJUST_SLEEP); |
| # ifdef MODULE_PM_LAYERED | ||
| LOG_DEBUG("ztimer_init(): ZTIMER_USEC setting required_pm_mode to %i\n", | ||
| CONFIG_ZTIMER_USEC_REQUIRED_PM_MODE); | ||
| ZTIMER_USEC_BASE->required_pm_mode = CONFIG_ZTIMER_USEC_REQUIRED_PM_MODE; | ||
| # endif |
There was a problem hiding this comment.
This section can cause errors during compilation if CONFIG_ZTIMER_USEC_REQUIRED_PM_MODE is configured with the wrongly typed value:
In file included from /home/jue/Projects/RIOT/sys/ztimer/auto_init.c:48:
/home/jue/Projects/RIOT/sys/ztimer/auto_init.c: In function 'ztimer_init':
/home/jue/Projects/RIOT/sys/ztimer/auto_init.c:115:15: error: format '%i' expects argument of type 'int', but argument 2 has type 'long unsigned int' [-Werror=format=]
115 | LOG_DEBUG("ztimer_init(): ZTIMER_USEC setting required_pm_mode to %i\n",
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This happens, if I use the defines made by the cpu vendor.
I'd say the easy solution is to set ZTIMER_USEC_BASE->required_pm_mode and then print that value. If I'm familiar enough with GCC and clang this should fix casting issues due to implicit casting.
| # ifdef MODULE_PM_LAYERED | |
| LOG_DEBUG("ztimer_init(): ZTIMER_USEC setting required_pm_mode to %i\n", | |
| CONFIG_ZTIMER_USEC_REQUIRED_PM_MODE); | |
| ZTIMER_USEC_BASE->required_pm_mode = CONFIG_ZTIMER_USEC_REQUIRED_PM_MODE; | |
| # endif | |
| # ifdef MODULE_PM_LAYERED | |
| ZTIMER_USEC_BASE->required_pm_mode = CONFIG_ZTIMER_USEC_REQUIRED_PM_MODE; | |
| LOG_DEBUG("ztimer_init(): ZTIMER_USEC setting required_pm_mode to "PRIu8"\n", | |
| ZTIMER_USEC_BASE->required_pm_mode); | |
| # endif |
The same goes with the respective MSEC section.
What do you think?
Maybe @kaspar030 has an opinion on this, too?
There was a problem hiding this comment.
If you apply this, please use the past tense in the debug message. (setting -> set)
|
@vincent-d: would you please check if current #15715 also fixes this. |
|
ping @vincent-d :) |
|
@vincent-d: #16172 should have solved fix this. |
|
@kfessel sorry for the long delay. Indeed, it should fix the initialization order issue. But if I'm not mistaken, the convert clock pm mode is still not initialized, though. |
|
@vincent-d: I think we don't need to init the convert_clocks (highlevel like *SEC) pm_mode_block if we init the base clocks (rtt timer or rtc) pm_mode_block |
This makes a lot of sense to me. I didn't check to confirm that this does actually cause issues. But IMO purely virtual clocks should use |
|
@vincent-d: Care to rebase and update? |
need their init fuctions it just worked cause i never activated pm_mode 0 |
|
Any updates here? |
@kfessel can you provide a patch for what you identified is missing here? |
|
see #16573 |
Contribution description
This might be flawed, but from my understanding:
required_pm_modeshould be applied to the 'base' clock (i.e. the periph_timer or periph_rtt clock)This PR sets
required_pm_modeonZTIMER_USEC_BASEandZTIMER_MSEC_BASE. Setting this field is also moved before those clocks are used as they can be used inztimer_convert_frac_init().I also changed 'convert' clocks init so they set their internal
required_pm_modetoZTIMER_CLOCK_NO_REQUIRED_PM_MODEinstead of nothing (which makes it 0, thus blocking a power mode by error).As a last minor change, I fixed the initialization of 'adjust' parameter for the
ZTIMER_MSECclock as the field was renamed.Testing procedure
I tested with our main application and checked that pm was behaving as expected. Before this change, it could never go to sleep.