Jump from SoftDevice to Application A or B

We have an existing application for the NRF52840 using SDKv15. This application will handle writing a new application to a free bank.  I need to add the ability to jump from SoftDevice to the new Application (A or B).  Can I specify what address to jump to from SoftDevice?  If not, then would the SoftDevice jump to a small main application, then jump to either application A or B?

Example flash layout

- Application B

- Application A

- Soft Device

- MBR

~~~~~

Or would it go like this: Bootloader -> Softdevice->Application A or B:

- Bootloader

- Application B

- Application A

- Soft Device

- MBR

  •  , a few questions I would like to ask:

    1) How should I set IAR to debug this while it jumps from bootloader to app A or AppB?

    • Combine both projects under the same Workspace
    • Tell IAR that vector table is at the bootloader starting address: drv_vector_table_base=0x000E0000
    • Download the .out file as an extra image under Debugger?  (Perhaps this is just needed when using two separate workspaces)

    2) Why does the bootloader code have data at 0x0000'0000, which conflicts with the MBR/SoftDevices S140 code?

    3) Where is the best place to put generic application data? 

    4) If I wanted to use CRC checking, I assume I would need to generate bootloader settings and update the CRC there.  What other settings do I need to change in the code?

    5) I'm a bit confused about the bootloader start address.  With my SDK, it seems that it is defined here: 

    #define NRF_UICR_BOOTLOADER_START_ADDRESS       (NRF_UICR_BASE + 0x14)
    

    and it provides a symbol for IAR to write it to ICIR:

    #if defined (__CC_ARM )
        #pragma push
        #pragma diag_suppress 1296
        uint32_t  m_uicr_bootloader_start_address __attribute__((at(NRF_UICR_BOOTLOADER_START_ADDRESS)))
                                                        = BOOTLOADER_START_ADDR;
        #pragma pop
    #elif defined ( __GNUC__ ) || defined ( __SES_ARM )
        volatile uint32_t m_uicr_bootloader_start_address  __attribute__ ((section(".uicr_bootloader_start_address")))
                                                = BOOTLOADER_START_ADDR;
    #elif defined ( __ICCARM__ )
        __root    const uint32_t m_uicr_bootloader_start_address @ NRF_UICR_BOOTLOADER_START_ADDRESS
                                                = BOOTLOADER_START_ADDR;
    #endif

    However, others have advised to write this start address using NRF tools:

    nrfjprog --memwr 0xff8 --val 0x78000 // An example that does not use the correct address and value

  • Hi,

    I am glad to hear you got it working!

    erk1313 said:
    1) How should I set IAR to debug this while it jumps from bootloader to app A or AppB?

    I must admit we don't use IAR much, but generally most debuggers will start executing from the start address of the binary that is running, and that will not work when you have a bootloader (and not even a SoftDevice). As long as execution starts at 0 (starting with the MBR), I would assume it should be OK in that regard? (You have also the issue that the bootloader will check the hash of the application, so if you changed the application you must also update the bootloader settings or modify the bootloader to not check the CRC, but this is regardless of the debugging environment you are using).

    erk1313 said:
    2) Why does the bootloader code have data at 0x0000'0000, which conflicts with the MBR/SoftDevices S140 code?

    This data is the bootloader start address, that the MBR check to know if there is a bootloader, and if so, where it is. In recent SDK versions, the bootloader hex file will contain the bootloader start address in the UICR 0x10001014, and on first boot, the, the MBR will copy it to address 0xFF8, which is in the end of the MBR page. However, a few SDK 15 minor versions had this in the MBR page itself in the hex file instead of the UICR. This caused problems, as if you for instance program the MBR (typically with the SoftDevice) first, and then program the bootloader, the MBR would typical be erase with the most common programing method, which is to do an erase of all sectors that are to be written to. 

    erk1313 said:
    3) Where is the best place to put generic application data? 

    That is right before (lower address) the bootlaoder. This is also where the FDS pages are located if you use FDS. The bootlaoder can be configured to never touch a specified amount of pages in this area, to prevent corrupting this data during DFU updates (when the area above the application can be used as a second slot to temporarily hold a new image. The relevant define here is NRF_DFU_APP_DATA_AREA_SIZE in the bootloader's sdk_config.h.

    erk1313 said:
    4) If I wanted to use CRC checking, I assume I would need to generate bootloader settings and update the CRC there.  What other settings do I need to change in the code?

    Yes, that is correct. CRC checking is the default so that is in use without you having to change anything.

    erk1313 said:
    5) I'm a bit confused about the bootloader start address.  With my SDK, it seems that it is defined here: 

    This goes back to my answer in 2). This is the bootloader start address.

  • Einar, thank you for being so responsive and thorough with your answers.  It helps considerably in understanding how the boot process works.  This is MUCH appreciated! Glad Nordic has experienced folks like you on the support team!!!

  • Hi...

    I am in a similar situation...I have to jump not to sd 0x1000 start address, but to a specific address..

    I understand that basically I have to call this function:

    sd_softdevice_vector_table_base_set(startAddress) 

    with startaddress being my app address...

    I saw you commented 0x1000 in 

    nrf_dfu_mbr_irq_forward_address_set(MBR_SIZE)

    Did I understand right? 

    Thanks for the useful thread!

    void nrf_bootloader_app_start(uint32_t startAddress)
    {
        nrf_dfu_mbr_init_sd();
    
        // Disable and clear interrupts
        NVIC->ICER[0] = 0xFFFFFFFF;
        NVIC->ICPR[0] = 0xFFFFFFFF;
        NVIC->ICER[1] = 0xFFFFFFFF;
        NVIC->ICPR[1] = 0xFFFFFFFF;
    
        sd_softdevice_vector_table_base_set(startAddress);
        nrf_dfu_mbr_irq_forward_address_set(MBR_SIZE);
        nrf_bootloader_app_start_final(startAddress);
    }

  • Hi marklander,

    If you want to understand the change to make nrf_dfu_mbr_irq_forward_address_set() support an "address" parameter, you will need to look into the thread that Einar linked in his very first reply here. It gives the necessary context.

    Hieu

Related