Software/Hardware reboot doesn't work when program loaded via bootloader

Windows 11 WSL2, NCS 2, VSCode

I want to be able to trigger a reboot from both hardware and software.

I am able to do this when I flash my code directly from VSCode to the chip, without a bootloader.

When I use a bootloader, however, both the physical reset button as well as software attempts to reboot seem to leave the device in a hung state.  I am software rebooting via sys_reboot(SYS_REBOOT_COLD) and NVIC_SystemReset().  I am hardware rebooting the regular way (pulling RESET low).

I am using an Adafruit nRF52840 Feather, which works, so not even a custom board or anything.

I looked at the UICR registers and they're the same when I use a bootloader or not.

PSELRESET[0]: 0x00000012
PSELRESET[1]: 0x00000012 Reset pin connected - port(0), pin(18)
APPROTECT : 0xFFFFFFFF Disabled
NFCPINS : 0xFFFFFFFE Disabled
DEBUGCTRL : 0xFFFFFFFF CPUNIDEN Enabled, CPUFPBEN Enabled
REGOUT0 : 0xFFFFFFFF REG0 VOUT Default 1.8 V

Can you help me work out what might be going on so I can fix it?

Thanks.

  • Hello,

    This was a bit vague for me. I am sorry. 

    Can you please specify what kind of bootloader that is present on your board? Is it the Adafruit bootloader?

    BR,

    Edvin

  • Hi yes it is the Adafruit bootloader.

    I realize you don't officially support the Adafruit bootloader, so I'm asking what even in principle can prevent the physical reset button from work, in addition to what else might prevent those function calls from working.

    Not a question about the Adafruit bootloader.

    Thanks!

  • That is correct. We do not officially support it, and in fact, I have no idea how it works. I think you would be better off askig Adafruit directly, as they actually have access to the source code of their bootloader. 

    A colleague of mine said that "I believe the Adafruit bootloader will enter DFU mode if you press the reset button twice", or something like that. 

    The bootloader is the first thing that will start up, so they can do anything they want with the normal buttons, and the reset buttons. There is no way for me to know how they have configured their devices. They can have disabled the reset button, and just use a normal gpio. But what the behavior of that button is, I don't know. 

    I think you should check your questions with Adafruit.

    Do you happen to know whether the bootloader is from the nRF5 SDK or from NCS? Or perhaps it is bare metal?

    Best regards,

    Edvin

  • Thanks for the reply.  I have independently correlated the issue to likely be related to a debug build of the bootloader behaving oddly (though still not sure how).

    A few points to your comments:

    • Adafruit doesn't give support, I've already tried
    • Their nRF52 bootloader code is open source (link)

    Do you happen to know whether the bootloader is from the nRF5 SDK or from NCS? Or perhaps it is bare metal?

    I'm not really sure, but I did find a comment (link) saying "This bootloader is based on the non-secure one in the SDK version 11.0.0_89a8197. It still has some dependency/code that is dropped in the later sdk". 

    I also see they're using some NRFX libs and have some softdevice versions in their code tree.

    I'm not really clear the meaning though.

    Please take note that in my question, I was explicitly not asking for you to know or support their bootloader, but instead for you to understand what I was seeing, how I was diagnosing it, and for you to help identify the mechanisms of the device that could lead to that (eg the RESET pin UICR registers indicating it should work).

    I expect the answer is to do with the specifics of the boot sequence for ARM/Nordic devices.

    Sharing some notes below that I gathered while researching this; for the general community if they're searching for something similar.

    Bootloader Sequence

    The adafruit nRF52 bootloader flow sequence of their program to boot the main application looks to be broadly:

    • (link) Do DFU stuff in main()
    • (link) Invoke bootloader_app_start() from main()
      • (link) Mess around with interrupt handling
      • (link) Use softdevice code to forward interrupts to the app addr (0x1000)
      • (link) Store the app addr in the first 4 bytes of SRAM
      • (link) call bootloader_util_app_start(app_addr)
        • (link) which just calls bootloader_util_reset(app_addr)
          • Assembly doing setup work for system reset to boot to main application
    • NVIC_SystemReset()

    Resources

    I am not familiar with the particular bootup sequence of nRF52 devices but a quick googling found some materials I will dig into more deeply:

    • AllThingsEmbedded
      • (link) Bootloaders and ARM Cortex-M microcontrollers: Design
      • (link) Bootloaders and ARM Cortex-M microcontrollers: Booting the target application
      • (link) ARM Cortex-M Startup code (for C and C++)
    • ARM
      • (link) How to Write a Bootloader
    • Memfault
      • (link) From Zero to main(): How to Write a Bootloader from Scratch

    Lastly

    UF2 bootloaders are common in Maker spaces, Microsoft supports them on MicroBit, circuit python, etc etc.

    Zephyr is behind the curve when it comes to supporting actually user-friendly bootloaders for products for regular people as users.

    I would recommend developing an understanding of those bootloaders (and bootloader sequences in general) and developing them within Zephyr.

    On the part of Adafruit, I posted some of my interoperability research notes to them (link) in the hopes of being able to get my applications to work properly with theirs (note, default Zephyr doesn't -- the flash partitioning is in conflict).

Related