Beware that this post is related to an SDK in maintenance mode
More Info: Consider nRF Connect SDK for new designs

NRF52840 issue getting from bootloader to application

Hello all,

Currently using an nRF52840-DK, GCC Makefile build tools including nrfjprog and nrfutil, Nordic SDK v15.0, SoftDevice s140 v6.0.0

I am currently trying to get a grasp on how the MBR, SoftDevice, DFU Bootloader, and Application all work together and I'm having a hard time combining some of the examples together cohesively. What I have done so far is the following:

  • Installed the SoftDevice (which includes the MBR)
  • Set the following debugging sdk_config.h elements for the bootloader example
    • NRF_LOG_BACKEND_UART_ENABLED to 1
    • NRF_LOG_ENABLED to 1
    • NRF_LOG_DEFERRED to 1
    • NRF_LOG_DEFAULT_LEVEL
  • Installed a slightly customized open_bootloader (pca10056_usb_debug) example (I've simply added a few extra debug messages)  
  • Installed the ble_app_blinky example application
  • Installed bootloader_settings generated using the nrfutil program

I am having an issue where the device gets stuck somewhere in the bootloader process. Based on some DEBUG messages that I've placed, it appears that it is having an issue in the nrf_dfu_mbr_irq_forward_address_set() function, called by the nrf_bootloader_app_start(). I am unable to get any DEBUG messages come out of the nrf_dfu_mbr_irq_forward_address_set() function, but right before this function is called is where I continue to get my last DEBUG message. The device gets here whenever it turns on from a power off/reset, and I want it to get past here and go to the blinky application which it cannot.

On the DK, I've got it set to where holding down Button 4 and turning the device on brings the device into DFU mode, where it gets stuck in the loop_forever() function found in nrf_bootloader.c and then I am unable to get to the application from here as well. Setting the NRF_BL_DFU_INACTIVITY_TIMEOUT_MS to 10000 will eventually cause it to exit loop_forever() and revert to the previously mentioned case, but again, not getting me to the application.

So I have two scenarios in which I am trying to get to the application from the bootloader:

  1. Whenever I turn the device on/restart via reset pin it gets stuck in the nrf_bootloader_app_start(), most likely the nrf_dfu_mbr_irq_forward_address_set() function.
  2. Whenever the device enters the DFU, I get stuck in the loop_forever() function and can't get to the application.

This is becoming a pretty big headache, so I appreciate any and all advice on the matter.

  • jspear said:
    Is this typically something that is taken into account with each projects Makefile and Linker Script?

    All linker scripts (if you use armgcc. In an IDE it is usually a project setting) will set the start address for that application. But please note that this is only something you need to consider if it is a bootloader project or if you add/remove the softdevice from an application.

    jspear said:
    To generate my bootloader settings, I use the following command:

    Why do you have the option nrf5sdk-tools? Is this a custom version of nrfutil? that is not something I have seen before. What does it print if you use the command "nrfutil version"

    jspear said:
    In terms of the dfu package, I am still working on getting kinks worked out with this, as I have an issue open here.

    I see. I see that in your other ticket you are using the UART bootloader with the blinky_mbr example, which is fine. Just make sure that you use the correct USB ports on the DK. The USB port on the short end is for the UART (through the debugger), while the USB port on the long side of the DK is for the nRF's USB port. 

    For a flying start, you can paste this file into the SDK15.0.0\examples\dfu\secure_bootloader\pca10056_usb_debug\armgcc folder:

    make -j9
    make -j9 -C ..\..\..\..\ble_peripheral\ble_app_buttonless_dfu\pca10056\s140\armgcc
    
    rm -rf files
    mkdir files
    
    copy ..\..\..\..\ble_peripheral\ble_app_buttonless_dfu\pca10056\s140\armgcc\_build\nrf52840_xxaa.hex files\app.hex
    nrfutil settings generate --family NRF52840 --application files\app.hex --application-version 1 --bootloader-version 1 --bl-settings-version 1 files\settings.hex
    nrfutil pkg generate --application files\app.hex --application-version 2 --hw-version 52 --sd-req 0x0100 --key-file ..\..\..\private.key files\dfu_img.zip
    
    nrfjprog -e
    nrfjprog --program ..\..\..\..\..\components\softdevice\s140\hex\s140_nrf52_7.2.0_softdevice.hex --verify
    nrfjprog --program _build\nrf52840_xxaa_s140.hex --verify
    nrfjprog --program files\app.hex --verify
    nrfjprog --program files\settings.hex --verify
    nrfjprog --reset

    It looks like you are using Linux or MacOS, so you have to convert it to an sh script, but you probably know how to do that. You also need to change the COM port to match the USB port of your device. Also, when you see the "timeout 10", this is where you need to reboot your DK while holding button 4 to put it in DFU mode. 

    As to why the application is hanging in serial_tx() -> while (m_async_mode && (m_xfer_done == false)), I believe this is a mismatch between the log backend (UART) and the bootloader. 

    The bootloader will go to: main() (which will log something) -> nrf_bootloader_init() -> nrf_bootloader_app_start() -> NRF_LOG_FLUSH(), but right before the NRF_LOG_FLUSH, it will forward all interrupts to the application, using nrf_dfu_mbr_irq_forward_address_set(). So when NRF_LOG_FLUSH is called, the UART will wait for the TX complete event (which will set m_xfer_done = true), but since this is forwarded, this will never happen. 

    To work around this, you can either just keep using the RTT backend (which doesn't require the UART peripheral), or you can set NRF_LOG_DEFERRED 0 in sdk_config.h.
    When NRF_LOG_DEFERRED is set to 1, all instances of NRF_LOG_...() will just queue the log, and the log will be processed at a later time. Typically in your main() loop. However, in the bootloader project, the log will not be processed before the NRF_LOG_FLUSH(), right before nrf_bootloader_app_start_final(), and at this point, the UART interrupts are forwarded to the application's start address (really the softdevice's/mbr's start address, which later will forward the to the application's start address), which is why you see it hanging waiting for m_xfer_done to be true.

    I hope this will clear up things a bit.

    Best regards,

    Edvin

  • Why do you have the option nrf5sdk-tools?

    So I've followed this guide in order to install the latest nrfutil program (it was last updates only a few weeks ago). The very first step was the one that caused me to open up the other ticket I mentioned. 

    I have two things I can output. When I do the command nrfutil -V I get: 

    nrfutil 7.0.1 (19248e3 2022-11-01)
    commit-hash: 19248e3210eb89a3e9f0c007cd4ba3080d3f392c
    commit-date: 2022-11-01
    host: x86_64-unknown-linux-gnu
    build-timestamp: 2022-11-01T07:41:25.668667032+00:00

    and when I do nrfutil nrf5sdk-tools -V I get: 

    nrfutil-nrf5sdk-tools 1.0.1 (c86ddc2 2022-11-29)
    commit-hash: c86ddc246ce42f669e82748f7eb2542caf0bf0fd
    commit-date: 2022-11-29
    host: x86_64-unknown-linux-gnu
    build-timestamp: 2022-11-29T09:27:03.011122071+00:00
    inner-executable-version: nrfutil version 6.1.7

    The USB port on the short end is for the UART (through the debugger), while the USB port on the long side of the DK is for the nRF's USB port.

    I actually did not know this, so this is going to be very helpful in preparation for our custom board, thank you!

    For a flying start, you can paste this file

    Thanks for this script, I was planning on making one myself, so it's nice to have one that was made by an expert. Gives me more confidence on this part of the building. 

    To work around this, you can either just keep using the RTT backend (which doesn't require the UART peripheral), or you can set NRF_LOG_DEFERRED 0 in sdk_config.h.

    I suppose I should ask then, which debugging methodology is better, RTT or UART? It seems that there are less issues coming from the RTT implementation, so it appears that this would be the better choice for debugging. If it's a subjective answer, what would be your recommendation? 

    I hope this will clear up things a bit.

    While the details behind this seem to be fairly complex, I believe I understand the general procedure going on and therefore the issue/solution, so thanks for the clarity!

    Joseph

  • jspear said:
    So I've followed this guide in order to install the latest nrfutil program

    Ah, thanks for sharing. I was not aware of this. I just tried uninstalling and re-installing using "pip uninstall nrfutil" and "pip install nrfutil", and it didn't allow me to use the command "nrfutil nrf5sdk-tools ...". I will look into this later.

    jspear said:
    I suppose I should ask then, which debugging methodology is better, RTT or UART? It seems that there are less issues coming from the RTT implementation, so it appears that this would be the better choice for debugging. If it's a subjective answer, what would be your recommendation? 

    It is indeed very much a subjective answer, and both have their pros and cons.

    I actually prefer UART as long as I don't need to output too much data too fast, because UART is slower, but I can open a UART terminal, and it will remain connected as long as the DK is powered, because the UART terminal is actually connecting to the debugger, and not the nRF chip itself (on the DK at least). RTT is a bit more flaky, because I usually need to reconnect it every time after flashing. At least if I am using Segger RTT Viewer. If I am using Segger Embedded Studio, however, it will do so automatically, so if you are using SES, the RTT backend is very (!) neat.

    Again, it depends on the situation. The UART backend actually requires some resources on the nRF. It requires a UART instance, so if you need to use your UART for something else, it is a blocker. The RTT is not a peripheral on the nRF in the same way. It is just the debugger reading some memory areas on the nRF, which doesn't affect the performance of the chip. It does require a debugger, though, which the UART strictly doesn't (if you have an external UART -> USB bridge). 

    So my go to is:

    1: If I use Segger Embedded Studio -> RTT.

    2: If I don't need too much output, my application doesn't use UART, and the nRF CPU is not throttled -> UART

    3: RTT.

    In addition, when you are working on a bootloader, remember that the pin configuration is carried over from the bootloader to the application, so when using GPIOs for UART or buttons, those will keep their configuration (input/output) in your application, unless you actively disable it before entering the application. Worth knowing for current consumption. This is something to keep in mind for UART, but not RTT, as it doesn't use any GPIOs.

    jspear said:
    While the details behind this seem to be fairly complex, I believe I understand the general procedure going on and therefore the issue/solution, so thanks for the clarity!

    Glad to help. Let me know if anything other nrfutil or bootloader questions pops up. (At least in the nRF5 SDK. I am still wrapping my head around the subject in the nRF Connect SDK).

    Best regards,

    Edvin

  • Edvin,

    Thanks for all of the information and advice! There's still a lot I have to learn with all of this, but I've definitely learned a bunch from this conversation. I'll be sure to come back around for more help if necessary!

    Thanks again!

    Joseph

Related