This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

sd_nvic_SystemReset() leaves some state behind?

I am experiencing a problem where behaviour after an sd_nvic_SystemReset() differs from behaviour after a power-on reset, and this difference causes failures in the softdevice when restarting throigh sd_nvic_SystemReset.

The device in question uses an nRF52811 with a custom boot loader, which normally simply confirms the loaded main app with an attached microprocessor and then jumps into it, without touching any hardware other than the UART and some GPIO. The main app, compiled against SDK 15.3.0, brings up the softdevice and BLE stack, with the only unusual aspect being that the LFCLK is provided as an external full-swing signal --- this requires manually getting the LFCLK started before calling nrf_sdh_enable_request().

The bootloader also supports a separate DFU mode, in which it brings up the BLE stack and allows a variety of (largely device-specific) operations to be performed through a bluetooth connection. Because the external 32kHz clock is not available yet at that point in the boot process (and to simplify things), the bootloader configures the LFCLK to be synthesised from the HFCLK:

static MBRCONST nrf_clock_lf_cfg_t clock_config = {
    .source = NRF_CLOCK_LF_SRC_SYNTH,
    .rc_ctiv = 0,
    .rc_temp_ctiv = 0,
    .accuracy = 0,
};
[...]

    int res=sd_softdevice_enable(&clock_config,softdevice_assert_handler);
    if (res!=NRF_SUCCESS  && ERROR_REPORTING)
        ELOG_NUM("sd_enable",res);

This works perfectly if run directly after power-up (i.e. if entering the DFU mode due to a button being pressed at startup time).

However, the main app can request a restart into DFU mode by (a) setting a specific flag, (b) disabling the softdevice, and (c) calling NVIC_SystemReset(). The expectation is that such a restart behaves identical to a power-up restart, with the exception of the flag having been set.

In reality, the bootloader's call to sd_softdevice_enable() hangs, which from both personal experience and research on the DevZone, suggests the LFCLK is not starting up?!?

If the main app does not shut down the softdevice before resetting (and using sd_nvic_SystemReset() to do so), sd_softdevice_enable() returns successfully, but soon afterwards, nrf_sdh_ble_enable() returns 8, "INVALID STATE".

 

I have tried resetting the CLOCK registers listed in 52811 erratum 36 at the start of the bootloader, but that made no difference to the behaviour.

We would like to understand why this is happening, because even in normal use, the main app may need to do a soft reset after an OTA firmware upgrade, and we need to be confident that the BLE stack will perform as expected after such a restart.

Parents
  • Hi umisef, 

    Because the external 32kHz clock is not available yet at that point in the boot process (and to simplify things), the bootloader configures the LFCLK to be synthesised from the HFCLK:

     Can you elaborate on this? Isnt the 32kHz connected directly to the nRF? Is the external 32KHz clock by the other MCU in your design?

    If you set the LFCLK source to NRF_CLOCK_LF_SRC_SYNTH, then you need manually start the HFXO prior do calling sd_softdevice_enable(). You also get the added constant current consumption from the HFCLK running all the time. 

    If you want to keep it simple I would rather just set the LFCLK source to NRF_CLOCK_LF_SRC_RC, i.e. 

    nrf_clock_lf_cfg_t clock_lf_cfg = 
    {
        .source = 0, // <0=> NRF_CLOCK_LF_SRC_RC, <1=> NRF_CLOCK_LF_SRC_XTAL, <2=> NRF_CLOCK_LF_SRC_SYNTH 
        .rc_ctiv = 16, // Interval in 0.25 s, 16 * 0.25 = 4 sec
        .rc_temp_ctiv = 2, // Check temperature every .rc_ctiv, but calibrate every .rc_temp_ctiv 
        .xtal_accuracy = 0, // xtal_accuracy is ignored when using NRF_CLOCK_LF_SRC_RC 
    };

    Best regards

    Bjørn

Reply
  • Hi umisef, 

    Because the external 32kHz clock is not available yet at that point in the boot process (and to simplify things), the bootloader configures the LFCLK to be synthesised from the HFCLK:

     Can you elaborate on this? Isnt the 32kHz connected directly to the nRF? Is the external 32KHz clock by the other MCU in your design?

    If you set the LFCLK source to NRF_CLOCK_LF_SRC_SYNTH, then you need manually start the HFXO prior do calling sd_softdevice_enable(). You also get the added constant current consumption from the HFCLK running all the time. 

    If you want to keep it simple I would rather just set the LFCLK source to NRF_CLOCK_LF_SRC_RC, i.e. 

    nrf_clock_lf_cfg_t clock_lf_cfg = 
    {
        .source = 0, // <0=> NRF_CLOCK_LF_SRC_RC, <1=> NRF_CLOCK_LF_SRC_XTAL, <2=> NRF_CLOCK_LF_SRC_SYNTH 
        .rc_ctiv = 16, // Interval in 0.25 s, 16 * 0.25 = 4 sec
        .rc_temp_ctiv = 2, // Check temperature every .rc_ctiv, but calibrate every .rc_temp_ctiv 
        .xtal_accuracy = 0, // xtal_accuracy is ignored when using NRF_CLOCK_LF_SRC_RC 
    };

    Best regards

    Bjørn

Children
  • Can you elaborate on this? Isnt the 32kHz connected directly to the nRF? Is the external 32KHz clock by the other MCU in your design?

    Correct. In normal operations, we need to share the 32kHz clock (both for cost reasons and to ensure a common view of time between the two processors), and unlike the nRF52, the other processor can output its 32kHz clock on a GPIO. So it gets the crystal, and the nRF52 is fed a full-swing clock from that GPIO.

    If you set the LFCLK source to NRF_CLOCK_LF_SRC_SYNTH, then you need manually start the HFXO prior do calling sd_softdevice_enable(). You also get the added constant current consumption from the HFCLK running all the time. 

    Good point about making sure HFCLK is derived from the HFXO, to get the required accuracy. The extra power is no problem at that point, because it's a DFU recovery mode, not the device's normal operation.

    If you want to keep it simple I would rather just set the LFCLK source to NRF_CLOCK_LF_SRC_RC, i.e. 

    I tried that (or rather, pass NULL as the clock config, which uses those same settings as default, according to the documentation), and it makes no difference --- after rebooting via NVIC_SystemReset(), the sd_softdevice_enable() still hangs if the softdevice was disabled before the reboot, and nrf_sdh_ble_enable() still fails if rebooted without disabling the softdevice first (and rebooting via sd_nvic_SystemReset()).

    Basically, the question remains --- why is the behavior after an NVIC system reset different from that after a power-on reset?

  • HI umisef, 

    umisef said:
    Correct. In normal operations, we need to share the 32kHz clock (both for cost reasons and to ensure a common view of time between the two processors), and unlike the nRF52, the other processor can output its 32kHz clock on a GPIO. So it gets the crystal, and the nRF52 is fed a full-swing clock from that GPIO.

    Ok, Understood. 

    umisef said:
    I tried that (or rather, pass NULL as the clock config, which uses those same settings as default, according to the documentation), and it makes no difference --- after rebooting via NVIC_SystemReset(), the sd_softdevice_enable() still hangs if the softdevice was disabled before the reboot, and nrf_sdh_ble_enable() still fails if rebooted without disabling the softdevice first (and rebooting via sd_nvic_SystemReset()).

    Just to clarify the SoftDevice is disabled by calling sd_softdevice_disable() in the application prior to calling NVIC_SystemReset()/sd_nvic_SystemReset()?  Does  sd_softdevice_enable() call in the bootloader hang, i.e. never return, if you provide NRF_CLOCK_LF_SRC_RC as the LFCLK source when disabling the SD in the application prior to resetting? 

    NVIC_SystemReset/sd_nvic_SystemReset() will result in the reset handler of the MBR and the Bootloader being called so there should not be any issues with with enabling the SD after a SoftReset.

    If nrf_sdh_ble_enable()  in the BL returns NRF_ERROR_INVALID_STATE , this means that its sd_ble_enable() that returns that error code and according to the documentation it is due to the following:

    NRF_ERROR_INVALID_STATE  - The BLE stack had already been initialized and cannot be reinitialized.

    Are you calling sd_ble_enable any where else in the BL code?

    Best regards

    Bjørn

Related