-
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
ztimer: fix required_pm_mode initialization #15911
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. |
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.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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_mode
should be applied to the 'base' clock (i.e. the periph_timer or periph_rtt clock)This PR sets
required_pm_mode
onZTIMER_USEC_BASE
andZTIMER_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_mode
toZTIMER_CLOCK_NO_REQUIRED_PM_MODE
instead 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_MSEC
clock 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.