-
Notifications
You must be signed in to change notification settings - Fork 7.7k
nRF: Add system clock stability policy #27398
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
nRF: Add system clock stability policy #27398
Conversation
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.
No complaints about the code. But is this really a good candidate for a global API? Right now it's just the one platform that needs to care about this. Maybe we should start this out as an internal thing with the nRF timer driver and promote the kconfig API to a global one only later?
I guess my criteria for this is: if we add a kconfig value to the core kernel, and it's never inspected by or modified by any of the code or tests dealing with the core kernel, it shouldn't be a core kernel feature. ... ?
Seems to me that there is also sam0_rtc driver which seems to currently wait for the clock: zephyr/drivers/timer/sam0_rtc_timer.c Line 191 in e227f5b
Not sure who is maintaining it. |
786dba1
to
300675d
Compare
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.
One question about whether EVENT_LFCLKSTART
could be handled by the ISR and cleared before the spinwait that's looking for it. E.g. if something else like a bootloader had done some clock configuration so it could be triggered faster than normal.
I like the two-phase startup for LFXO to catch the distinct stages.
/* Synth source start is almost instant and LFCLKSTARTED may | ||
* happen before calling idle. That would lead to deadlock. | ||
*/ | ||
if (!IS_ENABLED(CONFIG_CLOCK_CONTROL_NRF_K32SRC_SYNTH)) { |
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 see the goal here, but z_clock_driver_init()
will invoke z_nrf_clock_control_lf_on()
which on its first entry will use the onoff manager to trigger TASK_LFCLKSTART
. All that is before interrupts are locked on entry to this function.
There is a typical 1 ms startup time for this on nRF52840, but it does seem like the ISR may have already processed LFCLKSTARTED before the lock is taken, so deadlock is still possible.
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.
There is a typical 1 ms startup time for this on nRF52840, but it does seem like the ISR may have already processed LFCLKSTARTED before the lock is taken, so deadlock is still possible.
Interrupts are locked at this point of startup. I call irq_lock
just to get key
which is required by k_cpu_atomic_idle
and irq_unlock
for consistency.
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 will see if i can do something to support call of z_nrf_clock_control_lf_on
without that assumption.
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.
Interrupts are locked at this point of startup.
Could you expand on this?
z_clock_driver_init()
at PRE_KERNEL_2/CONFIG_SYSTEM_CLOCK_INIT_PRIORITY invokes
z_nrf_clock_control_lf_on()
invokes
onoff_request()
invokes
lfclk_start()
triggers NRF_CLOCK_TASK_LFCLKSTART then
z_nrf_clock_control_lf_on()
invokes lfclk_spinwait()
Nothing on that path appears to disables interrupts, so theoretically the EVENT_LFCLKSTARTED
could have been cleared by clock_event_check_and_clean()
in nrf_power_clock_isr()
before the subsequent lfclk_spinwait()
gets control and does disable interrupt, expecting to be able to see that event itself.
What am I missing?
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.
Nothing on that path appears to disables interrupts
driver initialization is called from z_cstart
which has interrupts disabled.
I have added support to spinwaiting from thread context and added test for that.
8f59953
to
9a817bd
Compare
DNM until #27422 is merged |
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.
Switching from comment to block because we've lost momentum and I don't want this concern to be missed.
694b393
to
38458e6
Compare
Upmerged since #27422 got merged. Removed DNM. |
Should this be tagged for 2.4.0? @carlescufi |
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'd like to see the logical operators used for boolean expressions, since we're going that way for MISRA. That's the only request changes. Otherwise this looks fine by inspection.
I get failures on drivers.clock.nrf_lf_clock_start_xtal_*
variants on nrf52840dk_nrf52840
running sanitycheck with --device-testing
. For *=available
the failure mode is that it appears that configuration doesn't output anything so the test times out, and it always fails under sanity check but passes manually. This may be a race condition specific to the test infrastructure.
I got one failure with *=no_wait
:
tirzah[765]$ cat sanity-out/nrf52840dk_nrf52840/tests/drivers/clock_control/nrf_lf_clock_start/drivers.clock.nrf_lf_clock_start_xtal_no_wait/handler.log
CLOCK_CONTROL_NRF_K32SRC=XTAL
SYSTEM_CLOCK_NO_WAIT=y
SYSTEM_CLOCK_WAIT_FOR_AVAILABILITY=n
SYSTEM_CLOCK_WAIT_FOR_STABILITY=n
Running test suite test_nrf_lf_clock_start
===================================================================
START - test_clock_check
PASS - test_clock_check
===================================================================
O MhFE: SPSEL in thread mode does not indicate PSP
ASSERTION FAIL [esf != ((void *)0)] @ WEST_TOPDIR/zephyr/arch/arm/core/aarch32/cortex_m/fault.c:955
ESF could not be retrieved successfully. Shall never occur.
E: ***** HARD FAULT *****
E: Fault escalation (see below)
E: ***** BUS FAULT *****
E: Imprecise data bus error
E: r0/a1: 0x00000004 r1/a2: 0x000003bb r2/a3: 0x00000001
E: r3/a4: 0x00000000 r12/ip: 0x00000000 r14/lr: 0x00001d71
E: xpsr: 0x61000005
E: Faulting instruction address (r15/pc): 0x00005880
E: >>> ZEPHYR FATAL ERROR 0: CPU exception on CPU 0
E: Fault during interrupt handling
E: Current thread: 0x20000240 (main)
E: Halting system
@@ -427,17 +426,64 @@ static void lfclk_spinwait(nrf_clock_lfclk_t t) | |||
{ | |||
nrf_clock_domain_t d = NRF_CLOCK_DOMAIN_LFCLK; | |||
nrf_clock_lfclk_t type; | |||
static const bool lfxo_target = | |||
IS_ENABLED(CONFIG_CLOCK_CONTROL_NRF_K32SRC_XTAL) | |
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.
These should be ||
since the operands and result are essentially boolean.
Same in other locations (isr_mode
next definition)
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.
done
zassert_false(on, "Clock should be off"); | ||
} else if (IS_ENABLED(CONFIG_SYSTEM_CLOCK_WAIT_FOR_AVAILABILITY)) { | ||
bool is_running = | ||
rtc_cnt | (on && (type == NRF_CLOCK_LFCLK_RC)); |
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.
so for essential type this should be (rtc_cnt != 0) || (on ...
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.
done
on = nrf_clock_is_running(NRF_CLOCK, NRF_CLOCK_DOMAIN_LFCLK, &type); | ||
k_busy_wait(100); | ||
rtc_cnt = k_cycle_get_32(); | ||
|
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.
Would you be open to this patch at this point in the code:
--- a/tests/drivers/clock_control/nrf_lf_clock_start/src/main.c
+++ b/tests/drivers/clock_control/nrf_lf_clock_start/src/main.c
@@ -98,6 +98,18 @@ void test_main(void)
k_busy_wait(100);
rtc_cnt = k_cycle_get_32();
+ TC_PRINT("CLOCK_CONTROL_NRF_K32SRC=%s\n",
+ IS_ENABLED(CONFIG_CLOCK_CONTROL_NRF_K32SRC_RC) ? "RC"
+ : IS_ENABLED(CONFIG_CLOCK_CONTROL_NRF_K32SRC_SYNTH) ? "SYNTH"
+ : IS_ENABLED(CONFIG_CLOCK_CONTROL_NRF_K32SRC_XTAL) ? "XTAL"
+ : "???");
+ TC_PRINT("SYSTEM_CLOCK_NO_WAIT=%c\n",
+ IS_ENABLED(CONFIG_SYSTEM_CLOCK_NO_WAIT) ? 'y' : 'n');
+ TC_PRINT("SYSTEM_CLOCK_WAIT_FOR_AVAILABILITY=%c\n",
+ IS_ENABLED(CONFIG_SYSTEM_CLOCK_WAIT_FOR_AVAILABILITY) ? 'y' : 'n');
+ TC_PRINT("SYSTEM_CLOCK_WAIT_FOR_STABILITY=%c\n",
+ IS_ENABLED(CONFIG_SYSTEM_CLOCK_WAIT_FOR_STABILITY) ? 'y' : 'n');
+
ztest_test_suite(test_nrf_lf_clock_start,
ztest_unit_test(test_clock_check),
ztest_unit_test(test_wait_in_thread)
This produces the following in the handler.log
which is helpful when trying to correlate the build tags with the configuration:
CLOCK_CONTROL_NRF_K32SRC=SYNTH
SYSTEM_CLOCK_NO_WAIT=n
SYSTEM_CLOCK_WAIT_FOR_AVAILABILITY=n
SYSTEM_CLOCK_WAIT_FOR_STABILITY=y
Running test suite test_nrf_lf_clock_start
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.
sure, added.
38458e6
to
7937b16
Compare
@andyross could you please take a look so we can merge this in time for 2.4.0? |
a44c12c
to
7ce2fb7
Compare
Running on this PR solves the problem with |
@PerMac thanks for running it on that PR, i will look into nrf53 issue then. |
nrf53 is fixed by #28121 |
We have restricted it to the scope of the nRF timer for now, and after the 2.4 release we will consider expanding this to the rest of platforms. |
@anangl please take a look |
@@ -463,13 +510,20 @@ void z_nrf_clock_control_lf_on(enum nrf_lfclk_start_mode start_mode) | |||
__ASSERT_NO_MSG(err >= 0); | |||
} | |||
|
|||
/* In case of simulated board leave immediately. */ | |||
if (IS_ENABLED(CONFIG_BOARD_NRF52_BSIM)) { |
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.
Make this check more generic and consistent with what is used in the Bluetooth controller:
if (IS_ENABLED(CONFIG_BOARD_NRF52_BSIM)) { | |
if (IS_ENABLED(CONFIG_SOC_SERIES_BSIM_NRFXX)) { |
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.
done
while (!(nrfx_clock_is_running(d, (void *)&type) && (type == t))) { | ||
/* empty */ | ||
while (!(nrfx_clock_is_running(d, (void *)&type) | ||
&& ((type == t) || (type == CLOCK_CONTROL_NRF_K32SRC)))) { |
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 won't work for CONFIG_CLOCK_CONTROL_NRF_K32SRC_EXT_LOW_SWING
and CONFIG_CLOCK_CONTROL_NRF_K32SRC_EXT_FULL_SWING
, as type
will be NRF_CLOCK_LFCLK_Xtal
then.
I'd propose to correct it and simplify a bit the logic used here as follows.
First, to change the function signature to:
static void lfclk_spinwait(enum nrf_lfclk_start_mode start_mode)
then instead of lfxo_target
use something like:
nrf_clock_lfclk_t target_type =
/* For sources XTAL, EXT_LOW_SWING, and EXT_FULL_SWING,
* NRF_CLOCK_LFCLK_Xtal is returned as the type of running clock.
*/
(IS_ENABLED(CONFIG_CLOCK_CONTROL_NRF_K32SRC_XTAL) ||
IS_ENABLED(CONFIG_CLOCK_CONTROL_NRF_K32SRC_EXT_LOW_SWING) ||
IS_ENABLED(CONFIG_CLOCK_CONTROL_NRF_K32SRC_EXT_FULL_SWING))
? NRF_CLOCK_LFCLK_Xtal
: CLOCK_CONTROL_NRF_K32SRC;
and then use here:
while (!(nrfx_clock_is_running(d, (void *)&type)
&& ((type == target_type)
|| (mode == NRF_LFCLK_START_MODE_SPINWAIT_AVAILABLE))) {
and below:
if (target_type == NRF_CLOCK_LFCLK_Xtal
&& (nrf_clock_lf_src_get(NRF_CLOCK) == NRF_CLOCK_LFCLK_RC)
&& nrf_clock_event_check(NRF_CLOCK,
...
In the switch
in z_nrf_clock_control_lf_on()
we'll have then:
case NRF_LFCLK_START_MODE_SPINWAIT_STABLE:
case NRF_LFCLK_START_MODE_SPINWAIT_AVAILABLE:
lfclk_spinwait(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.
Nice suggestion. Done.
enum nrf_lfclk_start_mode { | ||
NRF_LFCLK_START_MODE_NOWAIT, | ||
NRF_LFCLK_START_MODE_SPINWAIT_RUNNING, | ||
NRF_LFCLK_START_MODE_SPINWAIT_AVAILABLE, | ||
NRF_LFCLK_START_MODE_SPINWAIT_STABLE, | ||
}; |
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.
Shouldn't we use other prefixes here? I know, CLOCK_CONTROL_NRF_
is lengthy, but the current one is not consistent with the other stuff defined in this file.
(It's probably not something to be corrected in this PR, just spotted it here).
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.
renamed to CLOCK_CONTROL_NRF_LF_START_[STABLE, AVAILABLE,NOWAIT]
Added configuration for approach to starting system clock source. There are 3 options: no wait, wait untill available, wait until stable. Added support for those modes in clock control driver which handles low frequency source clock. Signed-off-by: Krzysztof Chruscinski <[email protected]>
4ed3453
to
1df5f57
Compare
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.
LGTM. One unnecessary comment could be removed.
case CLOCK_CONTROL_NRF_LF_START_AVAILABLE: | ||
/* fall through. */ | ||
case CLOCK_CONTROL_NRF_LF_START_STABLE: |
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 comment here is not needed. There is no code between those two cases, so there will be no warning here. It's not a "true fall through". ;-)
Enabled going to idle when waiting for low frequency clock. Added 2 stages of starting LF clock when XTAL is used. First stage is starting RC and then when it is ready XTAL is started. It is done to get event/interrupt when RC is ready which means that LF clock is available (but not stable). Signed-off-by: Krzysztof Chruscinski <[email protected]>
Added test which verifies various modes of waiting for system clock (no wait, available, stable) for different clock configurations (xtal, rc, synth). Signed-off-by: Krzysztof Chruscinski <[email protected]>
1df5f57
to
356694d
Compare
@carlescufi since this is now nordic only maybe i could be merged. |
- nrf_security: update mbedtls heap to const struct device Zephyr upmerge introduces device bindings const struct as part of: zephyrproject-rtos/zephyr#24873 This const'ify mbedtls_heap.c init function. - mpls: Added `select MULTITHREADING_LOCK` to Kconfig With the changes related to: nrfconnect/sdk-nrf#2861 zephyrproject-rtos/zephyr#27398 The mpsl clock control is no longer needed, but mpsl still requires MULTITHREADING_LOCK, and is therefore moved to its right location. Signed-off-by: Torsten Rasmussen <[email protected]>
- nrf_security: update mbedtls heap to const struct device Zephyr upmerge introduces device bindings const struct as part of: zephyrproject-rtos/zephyr#24873 This const'ify mbedtls_heap.c init function. - mpls: Added `select MULTITHREADING_LOCK` to Kconfig With the changes related to: nrfconnect/sdk-nrf#2861 zephyrproject-rtos/zephyr#27398 The mpsl clock control is no longer needed, but mpsl still requires MULTITHREADING_LOCK, and is therefore moved to its right location. Signed-off-by: Torsten Rasmussen <[email protected]>
- nrf_security: update mbedtls heap to const struct device Zephyr upmerge introduces device bindings const struct as part of: zephyrproject-rtos/zephyr#24873 This const'ify mbedtls_heap.c init function. - mpls: Added `select MULTITHREADING_LOCK` to Kconfig With the changes related to: nrfconnect/sdk-nrf#2861 zephyrproject-rtos/zephyr#27398 The mpsl clock control is no longer needed, but mpsl still requires MULTITHREADING_LOCK, and is therefore moved to its right location. Signed-off-by: Torsten Rasmussen <[email protected]>
- nrf_security: update mbedtls heap to const struct device Zephyr upmerge introduces device bindings const struct as part of: zephyrproject-rtos/zephyr#24873 This const'ify mbedtls_heap.c init function. - mpls: Added `select MULTITHREADING_LOCK` to Kconfig With the changes related to: nrfconnect/sdk-nrf#2861 zephyrproject-rtos/zephyr#27398 The mpsl clock control is no longer needed, but mpsl still requires MULTITHREADING_LOCK, and is therefore moved to its right location. Signed-off-by: Torsten Rasmussen <[email protected]>
- nrf_security: update mbedtls heap to const struct device Zephyr upmerge introduces device bindings const struct as part of: zephyrproject-rtos/zephyr#24873 This const'ify mbedtls_heap.c init function. - mpls: Added `select MULTITHREADING_LOCK` to Kconfig With the changes related to: nrfconnect/sdk-nrf#2861 zephyrproject-rtos/zephyr#27398 The mpsl clock control is no longer needed, but mpsl still requires MULTITHREADING_LOCK, and is therefore moved to its right location. - softdevice_controller: Mark 2M and Coded PHY as supported These helper configs were introduced in upstream zephyr. Signed-off-by: Torsten Rasmussen <[email protected]> Signed-off-by: Rubin Gerritsen <[email protected]>
- nrf_security: update mbedtls heap to const struct device Zephyr upmerge introduces device bindings const struct as part of: zephyrproject-rtos/zephyr#24873 This const'ify mbedtls_heap.c init function. - mpls: Added `select MULTITHREADING_LOCK` to Kconfig With the changes related to: nrfconnect/sdk-nrf#2861 zephyrproject-rtos/zephyr#27398 The mpsl clock control is no longer needed, but mpsl still requires MULTITHREADING_LOCK, and is therefore moved to its right location. - softdevice_controller: Mark 2M and Coded PHY as supported These helper configs were introduced in upstream zephyr. Signed-off-by: Torsten Rasmussen <[email protected]> Signed-off-by: Rubin Gerritsen <[email protected]>
- nrf_security: update mbedtls heap to const struct device Zephyr upmerge introduces device bindings const struct as part of: zephyrproject-rtos/zephyr#24873 This const'ify mbedtls_heap.c init function. - mpls: Added `select MULTITHREADING_LOCK` to Kconfig With the changes related to: nrfconnect/sdk-nrf#2861 zephyrproject-rtos/zephyr#27398 The mpsl clock control is no longer needed, but mpsl still requires MULTITHREADING_LOCK, and is therefore moved to its right location. - softdevice_controller: Mark 2M and Coded PHY as supported These helper configs were introduced in upstream zephyr. Signed-off-by: Torsten Rasmussen <[email protected]> Signed-off-by: Rubin Gerritsen <[email protected]>
Pull request adds clock stability policy configuration to the system clock (see #22758) and adds support to Nordic platform. Additionally, spin waiting for stable or available clock has been reworked for Nordic to allow going to idle while waiting for clock readiness (it can take up to 250 ms). Added test dedicated for Nordic platforms which validates correctness of behavior for each configuration against various clock sources.
Fixes #22758.
Fixes #26280.