Weird LFCLK Behavior With nRF Connect SDK v2.6.1 On nRF52805 Without External LFCLK Oscillator

I ran across this issue while troubleshooting a separate issue, in which I have an nRF52810-based board with no external LFCLK oscillator that is rock-solid with nRF5 SDK but is behaving weirdly with nRF Connect SDK, and I suspected this was due to having misconfigured the SDK to specify the use of the external LFCLK oscillator . While looking at this, I tried the same code and configuration on an nRF52805-based board which works fine with the nRF Connect SDK, but which I think also lacks an external LFCLK oscillator (for reasons surpassing understanding, I haven't been given a schematic for this nRF52805-based board).

Here's what's weird: with the nRF Connect SDK LFCLK configuration like this:

CONFIG_CLOCK_CONTROL_NRF_K32SRC_XTAL=y
CONFIG_CLOCK_CONTROL_NRF_K32SRC_50PPM=y

I see the following on the nRF52805 LFCLK regs when I check them at the top of main():

LFCLKSRC 0x00000001 LFCLKSTAT 0x00010001 LFCLKRUN 0x00000001 CTIV 0x00000000

I understand why LFCLKSRC is 1, but if there's no external LFCLK oscillator on this nRF52805 board, how on Earth is LFCLKSTAT is 0x00010001? It seems like that should only be possible of there is an external LFCLK oscillator, right?

But the problem is that, if I check this with nRF5 SDK firmware on the same board, it consistently shows there is is no external LFCLK oscillator. For instance, if I configure the nRF5 SDK using:

#define NRF_SDH_CLOCK_LF_SRC 0

then everything works fine (SoftDevice initializes without problem, etc). But if I configure the nRF5 SDK using:

#define NRF_SDH_CLOCK_LF_SRC 1

I get an error 7 (NRF_ERROR_INVALID_PARAM) returned from nrf_sdh_enable_request(). And if, before I make that call, I manually configure and enable the LFCLK on the nRF52805 using this code from Errata 3.2 [20], it never exits the loop checking EVENTS_LFCLKSTARTED:

static void lfclock_init(void)
{

NRF_CLOCK->EVENTS_LFCLKSTARTED = 0;
NRF_CLOCK->LFCLKSRC = 1;
NRF_CLOCK->TASKS_LFCLKSTART = 1;

while (NRF_CLOCK->EVENTS_LFCLKSTARTED == 0)
{
}

NRF_RTC0->TASKS_STOP = 0;
NRF_RTC1->TASKS_STOP = 0;

}

Finally, if I replace the wait loop in lfclock_init() above with an nrf_delay_us(500000),and then check the LFCLK registers, they are set exactly like you'd expect if there was no external LFCLK oscillator (they show the LFCLK is running, but not from the external oscillator):

LFCLKSRC 0x00000001 LFCLKSTAT 0x00010000 LFCLKRUN 0x00000001 CTIV 0x00000000

So that's my question. Why does nRF5 SDK and the LFCLK registers themselves tell me it is impossible to configure an external LFCLK oscillator on this nRF52805-based board, but when I run nRF Connect SDK firmware configured for external LFCLK oscillator on the same board, LFCLKSTAT is 0x00010001, which clearly indicates that it is running on an external LFCLK oscillator?

What am I missing here?

Thank you!

Parents
  • When you're using the nRF Connect SDK, configuring the low-frequency clock (LFCLK) to use an external crystal oscillator is done with settings like:

    CONFIG_CLOCK_CONTROL_NRF_K32SRC_XTAL=y
    CONFIG_CLOCK_CONTROL_NRF_K32SRC_50PPM=y

    These settings tell the system to use the external crystal oscillator for the LFCLK. But if your board doesn’t have an external LFCLK crystal, you might see some unexpected behavior. The way the nRF Connect SDK manages this is a bit different from the older nRF5 SDK.

    With the above configuration, the SDK tries to start the external crystal oscillator. If it doesn’t detect a crystal (such as on a board without one), it’s likely the SDK will automatically switch to the internal RC oscillator. However, you may still see values in the LFCLKSTAT register that suggest it’s using the external crystal (like 0x00010001), even though it’s actually using the internal RC oscillator instead.

    nRF5 SDK: In the nRF5 SDK, if you configure the LFCLK to use a crystal that isn’t present, the SoftDevice initialization fails with an error (NRF_ERROR_INVALID_PARAM). This error gives immediate feedback, showing that the configuration doesn’t match the hardware.

    nRF Connect SDK: Using Zephyr’s clock management system, the nRF Connect SDK is more flexible in this situation. Instead of raising an error, it falls back to using the internal RC oscillator if no external clock is detected. This lets the LFCLK source keep running, even though it’s using the internal oscillator.

    One main reason for this difference is how the Zephyr clock management subsystem in the nRF Connect SDK handles things. The nRF5 SDK, being more of a bare-metal solution, explicitly checks for an external crystal if configured as the LFCLK source and stops if it isn’t found. In contrast, the nRF Connect SDK, with Zephyr’s clock management, assumes a more flexible approach. Without an external crystal, it can automatically switch to the internal RC oscillator to continue running without errors. As a result, you might still see the LFCLK source as “active,” even though it’s running off a different oscillator.

    In essence, Zephyr’s clock management in the nRF Connect SDK takes a “graceful fallback” approach, which differs from the nRF5 SDK’s strict, bare-metal checks. This makes for smoother operation when external components aren’t available, though it may lead to different status indicators than you’d expect based on the nRF5 SDK’s behavior.

Reply
  • When you're using the nRF Connect SDK, configuring the low-frequency clock (LFCLK) to use an external crystal oscillator is done with settings like:

    CONFIG_CLOCK_CONTROL_NRF_K32SRC_XTAL=y
    CONFIG_CLOCK_CONTROL_NRF_K32SRC_50PPM=y

    These settings tell the system to use the external crystal oscillator for the LFCLK. But if your board doesn’t have an external LFCLK crystal, you might see some unexpected behavior. The way the nRF Connect SDK manages this is a bit different from the older nRF5 SDK.

    With the above configuration, the SDK tries to start the external crystal oscillator. If it doesn’t detect a crystal (such as on a board without one), it’s likely the SDK will automatically switch to the internal RC oscillator. However, you may still see values in the LFCLKSTAT register that suggest it’s using the external crystal (like 0x00010001), even though it’s actually using the internal RC oscillator instead.

    nRF5 SDK: In the nRF5 SDK, if you configure the LFCLK to use a crystal that isn’t present, the SoftDevice initialization fails with an error (NRF_ERROR_INVALID_PARAM). This error gives immediate feedback, showing that the configuration doesn’t match the hardware.

    nRF Connect SDK: Using Zephyr’s clock management system, the nRF Connect SDK is more flexible in this situation. Instead of raising an error, it falls back to using the internal RC oscillator if no external clock is detected. This lets the LFCLK source keep running, even though it’s using the internal oscillator.

    One main reason for this difference is how the Zephyr clock management subsystem in the nRF Connect SDK handles things. The nRF5 SDK, being more of a bare-metal solution, explicitly checks for an external crystal if configured as the LFCLK source and stops if it isn’t found. In contrast, the nRF Connect SDK, with Zephyr’s clock management, assumes a more flexible approach. Without an external crystal, it can automatically switch to the internal RC oscillator to continue running without errors. As a result, you might still see the LFCLK source as “active,” even though it’s running off a different oscillator.

    In essence, Zephyr’s clock management in the nRF Connect SDK takes a “graceful fallback” approach, which differs from the nRF5 SDK’s strict, bare-metal checks. This makes for smoother operation when external components aren’t available, though it may lead to different status indicators than you’d expect based on the nRF5 SDK’s behavior.

Children
  • Susheel, thank you for your response. I certainly can understand that nRF Connect SDK might take a more graceful fallback approach than the nRF5 SDK in this case. But this does not entirely answer my question, which also has to do with the behavior of hardware in this case.

    The LFCLKSTAT register is a read-only register controlled by MCU hardware, so its underlying behavior should not be affected by a change in firmware, and obviously firmware cannot force arbitrary bits to be set in that register.

    As I mention above, if I initialize the LFCLK for external oscillator (XTAL) on a board without one using the code shown above, but wait 500ms instead of looping forever, LFCLKSTAT ends up being 0x00010000, so LFCLKSTAT.STATE shows "Running" and LFCLKSTAT.SRC shows "RC". It would appear that this represents a "graceful fallback" at the hardware level; LFCLKSTAT is telling us that the LFCLK is "Running" but that it has fallen back on "RC" because the requested "XTAL" is not available.

    So, my  questions are:

    1) How is it possible LFCLKSTAT could ever be 0x00010001 on the same board, since that value is produced by hardware? Given what I just stated, what inputs to the CLOCK controller is the nRF Connect SDK performing to produce such a value on LFCLKSTAT, somehow forcing LFCLKSTAT.SRC to 1 (XTAL) even though the board lacks one?

    2) If the nRF Connect SDK was actually "falling back to using the internal RC oscillator if no external clock is detected" as you say — in other words, if after a timeout attempting to start LFCLK on XTAL, it instead started LFCLK on RC — wouldn't we still expect to see LFCLKSTAT report 0x00010000 in this case? How does LFCLKSTAT = 0x00010001 represent the outcome of a graceful fallback to RC by firmware?

    3) Given that my code above is showing that 0x00010000 is the normal LFCLKSTAT state when an attempt is made to start it on XTAL on a board without one, doesn't having LFCLKSTAT show 0x00010001 on a board with no XTAL indicate that there's something wrong with the state of the hardware, that the read-only LFCLKSTAT register is telling us that it thinks LFCLK is running on XTAL not on RC, even though no XTAL is present?

Related