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

DFU with sd_power_system_off

Is it possible for an app after having gone to sd_power_system_off to reset by button without triggering DFU?

The app seems to need CONFIG_GPIO_AS_PINRESET to be set so that button p0.21 can get the app to advertise again, but when DFU is loaded, the advertise becomes DfuTarg. I was looking at invoking DfuTarg only when button p0.21 is pressed as power is being applied.

For DFU I tried enter_method_button 1 with enter_method_button_pin 21 (the app after system_off, button pressed goes to DfuTarg) , and separately enter_method_pinreset 0 (the app after system_off, no response with button pressed, but advertises app after power toggle but then no DFU).

-thank-you.

Parents
  • Hi,

    You can check the RESETREAS register in the dfu_enter_check() function in the bootloader to see if the reset was caused by pin reset or power on reset. Note that you have to use sd_power_reset_reason_get() and sd_power_reset_reason_clr() instead of accessing the registers directly if you are using the SoftDevice (as is the case for the BLE bootloader). The RESETREAS value will be all 0 (0x00000000) if a power on reset occurred.

  • An available example would better help to understand if there is one.

    -thank-you

  • Hi,

    The following diff is for SDK 15 and demonstrates how it can be done. Please note that I have not tested it.

    diff --git a/components/libraries/bootloader/nrf_bootloader.c b/components/libraries/bootloader/nrf_bootloader.c
    index 3e62e47..d209ebf 100644
    --- a/components/libraries/bootloader/nrf_bootloader.c
    +++ b/components/libraries/bootloader/nrf_bootloader.c
    @@ -58,6 +58,7 @@
     #include "nrf_bootloader_dfu_timers.h"
     #include "app_scheduler.h"
     #include "app_timer.h"
    +#include "nrf_soc.h"
     
     static nrf_dfu_observer_t m_user_observer; //<! Observer callback set by the user.
     
    @@ -272,8 +273,18 @@ static bool dfu_enter_check(void)
         if (NRF_BL_DFU_ENTER_METHOD_BUTTON &&
            (nrf_gpio_pin_read(NRF_BL_DFU_ENTER_METHOD_BUTTON_PIN) == 0))
         {
    -        NRF_LOG_DEBUG("DFU mode requested via button.");
    -        return true;
    +        uint32_t reset_reason;
    +        sd_power_reset_reason_get(&reset_reason);
    +        sd_power_reset_reason_clr(~0);
    +        if (reset_reason > 0)
    +        {
    +            NRF_LOG_DEBUG("Ignoring DFU button as device is not power cycled.");
    +        }
    +        else
    +        {
    +            NRF_LOG_DEBUG("DFU mode requested via button after power on reset.");
    +            return true;
    +        }
         }
     
         if (NRF_BL_DFU_ENTER_METHOD_PINRESET &&
    

     

  • By all accounts this should be working. The button on the custom is a tactile between p0.21 and GND. After flashing the bootloader and selecting FW, I toggle the power which makes reset_reason = 0. The FW is now advertising and by pressing the button, DfuTarg should now be advertising. But FW is still advertising. Maybe not understanding the sequence correctly.

  • There was a bug in the snippet, as I forgot to clear the RESETREAS register. I have updated the previous post so that it is cleared. Does it work with that update?

Reply Children
  • If the sequence is correct and updated to add sd_power_reset_reason_clr(~0);, it does not seem to want to return true, button pressed second time, FW advertises, power toggled, FW advertises then button pressed FW still advertises.
    If I keep the original code in place, almost exact opposite to what is required is happening, with original when button pressed second time, DfuTarg advertises, when power toggled, FW advertises, and then button press, back to DfuTarg.
    Maybe one other still detail missing in the dfu_enter_check?

  • Hi,

    Now i see a sentence in your question that I overlooked before. The mechanism I have described only works with a normal GPIO pin as wake-up source, not P0.21 if it is configured as a reset pin. The wake-up pin must be configured with sense capability (essentially allows it to be a wake-up source from system off).

    I have attached a simple test program that demonstrates that the low-level mechanism work by configuring a pin as wakeup pin, and checking the reset reason and pin state, setting LED's to indicate the state.

    #include <stdbool.h>
    #include <stdint.h>
    #include "nrf_delay.h"
    #include "boards.h"
    
    
    int main(void)
    {
        /* Configure board. */
        bsp_board_init(BSP_INIT_LEDS);
        bsp_board_leds_off();
    
        /* Configure wakeup pin */
        nrf_gpio_cfg_sense_input(BSP_BUTTON_0, NRF_GPIO_PIN_PULLUP, NRF_GPIO_PIN_SENSE_LOW);
    
        if (NRF_POWER->RESETREAS & POWER_RESETREAS_RESETPIN_Msk)
        {
            NRF_POWER->RESETREAS = ~POWER_RESETREAS_RESETPIN_Msk;
        }
    
        if(NRF_POWER->RESETREAS & POWER_RESETREAS_RESETPIN_Msk)
        {
            // Light LED 1 to indicate pin reset
            bsp_board_led_on(0);
        }
        else if (NRF_POWER->RESETREAS == 0)
        {
            // Light LED 2 to indicate power on or brown out reset
            bsp_board_led_on(1);
    
            // Check if wake-up button is also pressed (even if we woke up due to power on reset)
            if(nrf_gpio_pin_read(BSP_BUTTON_0) == 0)
            {
                // Wake up from power on reset *AND* wakeup button is pushed. This is were we enter DFU mdoe!
                // Light LED 3 as well to indicate GPIO pin is pressed.
                bsp_board_led_on(2);
            }
        }
        else if (NRF_POWER->RESETREAS & POWER_RESETREAS_OFF_Msk)
        {
            // Light LED 3 to indicate wakeup from GPIO (without power cycle)
            bsp_board_led_on(2);
        }
        else
        {
            // Light LED 4 to indicate other wakeup reason
            bsp_board_led_on(3);
        }
    
        // Clear RESETREAS
        NRF_POWER->RESETREAS = ~0;
    
        // Wait 2 seconds before entering system off.
        // Press reset button or power cycle DK to test different behaviour after that point.
        nrf_delay_ms(2000);
        NRF_POWER->SYSTEMOFF = 1;
    
        while (true)
        {
            // Should never arrive here
        }
    }
    
    

    You can verify the following scenarios using the test program:

    • Wake up from power on reset: LED 2 is lit
    • Wake up from system OFF with GPIO pin (Button 1): LED 3 is lit
    • Wake up from power on reset with wake-up pin asserted: LED 2 and LED 3 is lit
    • (Wake up from pin reset: LED 1 is lit)
    • (Wake up from other reason: LED 4 is lit)
  • Almost there. The power cycle and button pushed together work fine now and get into BL mode, and subsequent button pushes will wake and have the FW advertising. The one condition that remains is to cycle power, advertise FW, timeout, and press again to advertise FW.

    But after the press again, it now advertises DfuTarg and not FW. Then when DfuTarg timesout, it returns to normal and button wakes FW to advertise.

    It seemed that this line, else if (NRF_POWER->RESETREAS & POWER_RESETREAS_OFF_Msk) would solve that remaining condition, but does not, instead a press again seems to visit (nrf_gpio_pin_read(BSP_BUTTON_0) == 0), (button & power together still works).

    -thank-you.

  • Hi,

    Are you able to reproduce this with the code snippet I posted in my previous answer? There, a RESETREAS register of all zeros is a requirement for entering DFU mode. Could it be that you clear the REASEREAS too early in some cases, before you read it? Can you upload your code (at least the decision making part of it, as well as any other code that uses RESETREAS)?

  • I have been using your code snippets for the custom which have been very helpful.
    Using sdk15.0 standard SES examples I've been able to reproduce on the DK.
    Attached are slightly modified ble_app_template and dfu examples (removed in both examples CONFIG_GPIO_AS_PINRESET, and added code snippet to dfu example, in dfu example file root directory is the FW zip file).
    To reproduce:
    - flash dfu example to DK, press and hold button 1 while cycle power, upload FW template by nRFconnect
    - press button 1, template advertises, timeout, repeat press and still ok
    - cycle power, template advertises, timeout, press button 1 and DfuTarg advertises (should be template).

    -thank-you.

    ble_app_template_case-1.zip        dfu_case-1.zip

Related