Browse Source

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 we are not
using that because it also does other things and makes the code larger.

Signed-off-by: Christian Walther <cwalther@gmx.ch>
pull/13497/head
Christian Walther 10 months ago
committed by Damien George
parent
commit
b10182bbcc
  1. 5
      ports/nrf/modules/machine/rtcounter.c
  2. 34
      ports/nrf/mphalport.c
  3. 2
      ports/nrf/mphalport.h

5
ports/nrf/modules/machine/rtcounter.c

@ -27,6 +27,7 @@
#include "py/nlr.h"
#include "py/runtime.h"
#include "mphalport.h"
#include "rtcounter.h"
#include "nrfx_rtc.h"
#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
}
// Start the low-frequency clock (if it hasn't been started already)
if (!nrf_clock_lf_is_running(NRF_CLOCK)) {
nrf_clock_task_trigger(NRF_CLOCK, NRF_CLOCK_TASK_LFCLKSTART);
}
mp_nrf_start_lfclk();
// Make sure it's uninitialized.
nrfx_rtc_uninit(self->p_rtc);

34
ports/nrf/mphalport.c

@ -40,6 +40,36 @@
#include "nrf_clock.h"
#endif
#if !defined(USE_WORKAROUND_FOR_ANOMALY_132) && \
(defined(NRF52832_XXAA) || defined(NRF52832_XXAB))
// ANOMALY 132 - LFCLK needs to avoid frame from 66us to 138us after LFCLK stop.
#define USE_WORKAROUND_FOR_ANOMALY_132 1
#endif
#if USE_WORKAROUND_FOR_ANOMALY_132
#include "soc/nrfx_coredep.h"
#endif
void mp_nrf_start_lfclk(void) {
if (!nrf_clock_lf_start_task_status_get(NRF_CLOCK)) {
// Check if the clock was recently stopped but is still running.
#if USE_WORKAROUND_FOR_ANOMALY_132
bool was_running = nrf_clock_lf_is_running(NRF_CLOCK);
// If so, wait for it to stop. This ensures that the delay for anomaly 132 workaround does
// not land us in the middle of the forbidden interval.
while (nrf_clock_lf_is_running(NRF_CLOCK)) {
}
// If the clock just stopped, we can start it again right away as we are certainly before
// the forbidden 66-138us interval. Otherwise, apply a delay of 138us to make sure we are
// after the interval.
if (!was_running) {
nrfx_coredep_delay_us(138);
}
#endif
nrf_clock_task_trigger(NRF_CLOCK, NRF_CLOCK_TASK_LFCLKSTART);
}
}
#if MICROPY_PY_TIME_TICKS
// 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) {
void rtc1_init_time_ticks(void) {
// Start the low-frequency clock (if it hasn't been started already)
if (!nrf_clock_lf_is_running(NRF_CLOCK)) {
nrf_clock_task_trigger(NRF_CLOCK, NRF_CLOCK_TASK_LFCLKSTART);
}
mp_nrf_start_lfclk();
// Uninitialize first, then set overflow IRQ and first CC event
nrfx_rtc_uninit(&rtc1);
nrfx_rtc_init(&rtc1, &rtc_config_time_ticks, rtc_irq_time);

2
ports/nrf/mphalport.h

@ -54,6 +54,8 @@ void mp_hal_delay_us(mp_uint_t us);
const char *nrfx_error_code_lookup(uint32_t err_code);
void mp_nrf_start_lfclk(void);
#define MP_HAL_PIN_FMT "%q"
#define mp_hal_pin_obj_t const pin_obj_t *
#define mp_hal_get_pin_obj(o) pin_find(o)

Loading…
Cancel
Save