8000 nrf: Fix non-running LFCLK. · micropython/micropython@c5089ef · GitHub
[go: up one dir, main page]

Skip to content

Commit c5089ef

Browse files
committed
nrf: Fix non-running LFCLK.
Under some circumstances, after a hard reset, the low-frequency clock would not be running. This caused time.ticks_ms() to return 0, time.sleep_ms() to get stuck, and other misbehavior. A soft reboot would return it to a working state. The cause was a race condition that was hit when the bootloader would itself turn LFCLK on, but turn it off again shortly before launching the main application (this apparently happens with the Adafruit bootloader from https://github.com/fanoush/ds-d6/tree/master/micropython). Stopping the clock is an asynchronous operation and it continues running for a short time after the stop command is given. When MicroPython checked whether to start it by looking at the LFCLKSTAT register (nrf_clock_lf_is_running) during that time, it would mistakenly not be started again. What MicroPython should be looking at is not whether the clock is running at this time, but whether a start/stop command has been given, which is indicated by the LFCLKRUN register (nrf_clock_lf_start_task_status_get). It is not clearly documented, but empirically LFCLKRUN is not just set when the LFCLKSTART task is triggered, but also cleared when the LFCLKSTOP task is triggered, which is exactly what we need. The matter is complicated by the fact that the nRF52832 has an anomaly (see [errata](https://infocenter.nordicsemi.com/topic/errata_nRF52832_Rev3/ERR/nRF52832/Rev3/latest/anomaly_832_132.html?cp=5_2_1_0_1_33)) where starting the LFCLK will not work between 66µs and 138µs after it last stopped. Apply a workaround for that. See nrfx_clock_lfclk_start() in micropython/lib/nrfx/drivers/src/nrfx_clock.c for reference, but I am not using that because it also does other things and makes the code larger. Signed-off-by: Christian Walther <cwalther@gmx.ch>
1 parent adc0459 commit c5089ef

File tree

3 files changed

+35
-6
lines changed

3 files changed

+35
-6
lines changed

ports/nrf/modules/machine/rtcounter.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727

2828
#include "py/nlr.h"
2929
#include "py/runtime.h"
30+
#include "mphalport.h"
3031
#include "rtcounter.h"
3132
#include "nrfx_rtc.h"
3233
#include "nrf_clock.h"
@@ -182,9 +183,7 @@ STATIC mp_obj_t machine_rtc_make_new(const mp_obj_type_t *type, size_t n_args, s
182183
}
183184

184185
// Start the low-frequency clock (if it hasn't been started already)
185-
if (!nrf_clock_lf_is_running(NRF_CLOCK)) {
186-
nrf_clock_task_trigger(NRF_CLOCK, NRF_CLOCK_TASK_LFCLKSTART);
187-
}
186+
mp_nrf_start_lfclk();
188187

189188
// Make sure it's uninitialized.
190189
nrfx_rtc_uninit(self->p_rtc);

ports/nrf/mphalport.c

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,36 @@
4040
#include "nrf_clock.h"
4141
#endif
4242

43+
#if !defined(USE_WORKAROUND_FOR_ANOMALY_132) && \
44+
(defined(NRF52832_XXAA) || defined(NRF52832_XXAB))
45+
// ANOMALY 132 - LFCLK needs to avoid frame from 66us to 138us after LFCLK stop.
46+
#define USE_WORKAROUND_FOR_ANOMALY_132 1
47+
#endif
48+
49+
#if USE_WORKAROUND_FOR_ANOMALY_132
50+
#include "soc/nrfx_coredep.h"
51+
#endif
52+
53+
void mp_nrf_start_lfclk(void) {
54+
if (!nrf_clock_lf_start_task_status_get(NRF_CLOCK)) {
55+
// Check if the clock was recently stopped but is still running.
56+
#if USE_WORKAROUND_FOR_ANOMALY_132
57+
bool was_running = nrf_clock_lf_is_running(NRF_CLOCK);
58+
// If so, wait for it to stop. This ensures that the delay for anomaly 132 workaround does
59+
// not land us in the middle of the forbidden interval.
60+
while (nrf_clock_lf_is_running(NRF_CLOCK)) {
61+
}
62+
// If the clock just stopped, we can start it again right away as we are certainly before
63+
// the forbidden 66-138us interval. Otherwise, apply a delay of 138us to make sure we are
64+
// after the interval.
65+
if (!was_running) {
66+
nrfx_coredep_delay_us(138);
67+
}
68+
#endif
69+
nrf_clock_task_trigger(NRF_CLOCK, NRF_CLOCK_TASK_LFCLKSTART);
70+
}
71+
}
72+
4373
#if MICROPY_PY_TIME_TICKS
4474

4575
// Use RTC1 for time ticks generation (ms and us) with 32kHz tick resolution
@@ -99,9 +129,7 @@ STATIC void rtc_irq_time(nrfx_rtc_int_type_t event) {
99129

100130
void rtc1_init_time_ticks(void) {
101131
// Start the low-frequency clock (if it hasn't been started already)
102-
if (!nrf_clock_lf_is_running(NRF_CLOCK)) {
103-
nrf_clock_task_trigger(NRF_CLOCK, NRF_CLOCK_TASK_LFCLKSTART);
104-
}
132+
mp_nrf_start_lfclk();
105133
// Uninitialize first, then set overflow IRQ and first CC event
106134
nrfx_rtc_uninit(&rtc1);
107135
nrfx_rtc_init(&rtc1, &rtc_config_time_ticks, rtc_irq_time);

ports/nrf/mphalport.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ void mp_hal_delay_us(mp_uint_t us);
5454

5555
const char *nrfx_error_code_lookup(uint32_t err_code);
5656

57+
void mp_nrf_start_lfclk(void);
58+
5759
#define MP_HAL_PIN_FMT "%q"
5860
#define mp_hal_pin_obj_t const pin_obj_t *
5961
#define mp_hal_get_pin_obj(o) pin_find(o)

0 commit comments

Comments
 (0)
0