Beware that this post is related to an SDK in maintenance mode
More Info: Consider nRF Connect SDK for new designs
This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

MBR jumps to application not bootloader

We have problems with the restart which the application does after receiving the DFU attribute is written.

Startup should work like this as I understand it: the reset vector resides at addr 4, and points to 0x8e9 in MBR. MBR checks if there is any copy command (for activating a new SD and/or bootloader). If not it jumps to the bootloader. The bootloader checks if the application has requested DFU entry, if not and crc is ok then it jumps to the application (using the vector at 0x26004).

Our problem is that MBR never jumps to the bootloader, it jumps to 0x24D39 in the SD which starts the application (via vector at 0x26004). This means that when I write the enter-DFU attribute in the application the bootloader is not started, it just restarts the application.

We use nRF52832, IAR 8.40 and Nordic SDK 15.3. We have removed compiler optimization from the bootlader and relocated it to 0x70000.

Notes:
1. IAR places the vector 0x0007E000 at address 0xFFC, which cause it to erase the rest of the MBR, which cause the CPU to load FFFFFFFF to SP and PC. I dont understand what this vector is for. To remedy this I added option "download extra image" with a hex file containing the MBR and this mystery vector. MBR was extracted from the SD hex file.
2. When starting the debugger with the bootloader IAR loads the vector base to 0x70000 skipping MBR. This is not a problem for now. Setting --drv_vector_table_base=0 forces start via MBR.

Parents
  • Hi Sven, 

    in SDK v15.3.0 and later we introduced a change in the way the MBR fetches the bootloader start address, i.e. the location of the bootloaders vector table. The MBR will now first try to fetch the bootloader and the MBR parameter page addresses from a specific location inside the MBR region(0x0000 to 0x1000), if these locations are blank( i.e. 0xFFFFFFFF) then it will check the UICR registers (i.e. 0x10001014 and 0x10001018) for the bootloader  and MBR parameter page addresses. The bootloader project will place the bootloader  and MBR parameter page addresses at 0xFFC and 0xFF8 respectivly. However, this will lead to some IDEs ( like Keil and IAR) to erase the flash page that the MBR is programmed to in order to write the two addresses to 0xFFC and 0xFF8. 

    If you flash the SoftDevice and MBR first and then the bootloader, then the MBR will be erased and the bootloader  and MBR parameter page addresses at 0xFFC and 0xFF8. If the bootloader is flashed first and then the SoftDevice and MBR is flashed, then the addresses at 0xFFC and 0xFF8 will be 0xFFFFFFFF and the 

    We solved this in SDK v16.0.0, were the bootloader will write the the bootloader  and MBR parameter page addresses to 0xFFC and 0xFF8 at first boot, instead of placing the addresses there in the compiled binary see nrf_bootloader_mbr_addrs_populate() in main.c in the bootloader project. 

    I also made a patch for Keil and SES in SDK v15.3.0, see https://devzone.nordicsemi.com/f/nordic-q-a/47823/sd_mbr_command_copy_sd-returns-nrf_error_internal-sdk-14-0#

    // In nrf_mbr.h
    /** @brief Location (in the flash memory) of the bootloader address. */
    #define MBR_BOOTLOADER_ADDR      (0xFF8)
    
    /** @brief Location (in UICR) of the bootloader address. */
    #define MBR_UICR_BOOTLOADER_ADDR  (0x10001014) // (&(NRF_UICR->NRFFW[0]))
    
    /** @brief Location (in the flash memory) of the address of the MBR parameter page. */
    #define MBR_PARAM_PAGE_ADDR      (0xFFC)
    
    /** @brief Location (in UICR) of the address of the MBR parameter page. */
    #define MBR_UICR_PARAM_PAGE_ADDR  (0x10001018)// (&(NRF_UICR->NRFFW[1]))
    
    //In app_util.h
    
    #if defined(MBR_PRESENT) || defined(SOFTDEVICE_PRESENT)
    #include "nrf_mbr.h"
    
    #define BOOTLOADER_ADDRESS      ((*(uint32_t *)MBR_BOOTLOADER_ADDR) == 0xFFFFFFFF ? MBR_UICR_BOOTLOADER_ADDR : MBR_BOOTLOADER_ADDR) /**< The currently configured start address of the bootloader. If 0xFFFFFFFF, no bootloader start address is configured. */
    #define MBR_PARAMS_PAGE_ADDRESS ((*(uint32_t *)MBR_PARAM_PAGE_ADDR) == 0xFFFFFFFF ? MBR_UICR_PARAM_PAGE_ADDR : MBR_PARAM_PAGE_ADDR) /**< The currently configured address of the MBR params page. If 0xFFFFFFFF, no MBR params page address is configured. */
    
    //#define BOOTLOADER_ADDRESS      ((*(uint32_t *)MBR_BOOTLOADER_ADDR) == 0xFFFFFFFF ? *MBR_UICR_BOOTLOADER_ADDR : *(uint32_t *)MBR_BOOTLOADER_ADDR) /**< The currently configured start address of the bootloader. If 0xFFFFFFFF, no bootloader start address is configured. */
    //#define MBR_PARAMS_PAGE_ADDRESS ((*(uint32_t *)MBR_PARAM_PAGE_ADDR) == 0xFFFFFFFF ? *MBR_UICR_PARAM_PAGE_ADDR : *(uint32_t *)MBR_PARAM_PAGE_ADDR) /**< The currently configured address of the MBR params page. If 0xFFFFFFFF, no MBR params page address is configured. */
    
    #else
    #define BOOTLOADER_ADDRESS      (NRF_UICR->NRFFW[0]) /**< Check UICR, just in case. */
    #define MBR_PARAMS_PAGE_ADDRESS (NRF_UICR->NRFFW[1]) /**< Check UICR, just in case. */
    #endif
    
    //In nrf_dfu_types.h 
    #define NRF_UICR_MBR_PARAMS_PAGE_ADDRESS    MBR_UICR_PARAM_PAGE_ADDR //(MBR_PARAM_PAGE_ADDR)
    
    // In nrf_bootoader_info.h
    #define NRF_UICR_BOOTLOADER_START_ADDRESS   MBR_UICR_BOOTLOADER_ADDR //(MBR_BOOTLOADER_ADDR)
    
    
    //in main.c 
    ret_code_t nrf_bootloader_write_bl_addr_to_mbr(void){
    
        if( (*(volatile uint32_t *)MBR_BOOTLOADER_ADDR != BOOTLOADER_START_ADDR) || 
         (*(volatile uint32_t *)MBR_PARAM_PAGE_ADDR != NRF_MBR_PARAMS_PAGE_ADDRESS))
         {
              // Enable Write with the NVMC
              NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Wen << NVMC_CONFIG_WEN_Pos;
              while (NRF_NVMC->READY == NVMC_READY_READY_Busy){}
    
              // Write Bootloader start address to MBR 
              *(volatile uint32_t *)MBR_BOOTLOADER_ADDR = BOOTLOADER_START_ADDR;
              // Write MBR parameter page address to MBR
              *(volatile uint32_t *)MBR_PARAM_PAGE_ADDR = NRF_MBR_PARAMS_PAGE_ADDRESS;
              // Revert NVMC to read-only
              NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Ren << NVMC_CONFIG_WEN_Pos;
              while (NRF_NVMC->READY == NVMC_READY_READY_Busy){}
          }
    
        return NRF_SUCCESS;
    }

    Best regards

    Bjørn

Reply
  • Hi Sven, 

    in SDK v15.3.0 and later we introduced a change in the way the MBR fetches the bootloader start address, i.e. the location of the bootloaders vector table. The MBR will now first try to fetch the bootloader and the MBR parameter page addresses from a specific location inside the MBR region(0x0000 to 0x1000), if these locations are blank( i.e. 0xFFFFFFFF) then it will check the UICR registers (i.e. 0x10001014 and 0x10001018) for the bootloader  and MBR parameter page addresses. The bootloader project will place the bootloader  and MBR parameter page addresses at 0xFFC and 0xFF8 respectivly. However, this will lead to some IDEs ( like Keil and IAR) to erase the flash page that the MBR is programmed to in order to write the two addresses to 0xFFC and 0xFF8. 

    If you flash the SoftDevice and MBR first and then the bootloader, then the MBR will be erased and the bootloader  and MBR parameter page addresses at 0xFFC and 0xFF8. If the bootloader is flashed first and then the SoftDevice and MBR is flashed, then the addresses at 0xFFC and 0xFF8 will be 0xFFFFFFFF and the 

    We solved this in SDK v16.0.0, were the bootloader will write the the bootloader  and MBR parameter page addresses to 0xFFC and 0xFF8 at first boot, instead of placing the addresses there in the compiled binary see nrf_bootloader_mbr_addrs_populate() in main.c in the bootloader project. 

    I also made a patch for Keil and SES in SDK v15.3.0, see https://devzone.nordicsemi.com/f/nordic-q-a/47823/sd_mbr_command_copy_sd-returns-nrf_error_internal-sdk-14-0#

    // In nrf_mbr.h
    /** @brief Location (in the flash memory) of the bootloader address. */
    #define MBR_BOOTLOADER_ADDR      (0xFF8)
    
    /** @brief Location (in UICR) of the bootloader address. */
    #define MBR_UICR_BOOTLOADER_ADDR  (0x10001014) // (&(NRF_UICR->NRFFW[0]))
    
    /** @brief Location (in the flash memory) of the address of the MBR parameter page. */
    #define MBR_PARAM_PAGE_ADDR      (0xFFC)
    
    /** @brief Location (in UICR) of the address of the MBR parameter page. */
    #define MBR_UICR_PARAM_PAGE_ADDR  (0x10001018)// (&(NRF_UICR->NRFFW[1]))
    
    //In app_util.h
    
    #if defined(MBR_PRESENT) || defined(SOFTDEVICE_PRESENT)
    #include "nrf_mbr.h"
    
    #define BOOTLOADER_ADDRESS      ((*(uint32_t *)MBR_BOOTLOADER_ADDR) == 0xFFFFFFFF ? MBR_UICR_BOOTLOADER_ADDR : MBR_BOOTLOADER_ADDR) /**< The currently configured start address of the bootloader. If 0xFFFFFFFF, no bootloader start address is configured. */
    #define MBR_PARAMS_PAGE_ADDRESS ((*(uint32_t *)MBR_PARAM_PAGE_ADDR) == 0xFFFFFFFF ? MBR_UICR_PARAM_PAGE_ADDR : MBR_PARAM_PAGE_ADDR) /**< The currently configured address of the MBR params page. If 0xFFFFFFFF, no MBR params page address is configured. */
    
    //#define BOOTLOADER_ADDRESS      ((*(uint32_t *)MBR_BOOTLOADER_ADDR) == 0xFFFFFFFF ? *MBR_UICR_BOOTLOADER_ADDR : *(uint32_t *)MBR_BOOTLOADER_ADDR) /**< The currently configured start address of the bootloader. If 0xFFFFFFFF, no bootloader start address is configured. */
    //#define MBR_PARAMS_PAGE_ADDRESS ((*(uint32_t *)MBR_PARAM_PAGE_ADDR) == 0xFFFFFFFF ? *MBR_UICR_PARAM_PAGE_ADDR : *(uint32_t *)MBR_PARAM_PAGE_ADDR) /**< The currently configured address of the MBR params page. If 0xFFFFFFFF, no MBR params page address is configured. */
    
    #else
    #define BOOTLOADER_ADDRESS      (NRF_UICR->NRFFW[0]) /**< Check UICR, just in case. */
    #define MBR_PARAMS_PAGE_ADDRESS (NRF_UICR->NRFFW[1]) /**< Check UICR, just in case. */
    #endif
    
    //In nrf_dfu_types.h 
    #define NRF_UICR_MBR_PARAMS_PAGE_ADDRESS    MBR_UICR_PARAM_PAGE_ADDR //(MBR_PARAM_PAGE_ADDR)
    
    // In nrf_bootoader_info.h
    #define NRF_UICR_BOOTLOADER_START_ADDRESS   MBR_UICR_BOOTLOADER_ADDR //(MBR_BOOTLOADER_ADDR)
    
    
    //in main.c 
    ret_code_t nrf_bootloader_write_bl_addr_to_mbr(void){
    
        if( (*(volatile uint32_t *)MBR_BOOTLOADER_ADDR != BOOTLOADER_START_ADDR) || 
         (*(volatile uint32_t *)MBR_PARAM_PAGE_ADDR != NRF_MBR_PARAMS_PAGE_ADDRESS))
         {
              // Enable Write with the NVMC
              NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Wen << NVMC_CONFIG_WEN_Pos;
              while (NRF_NVMC->READY == NVMC_READY_READY_Busy){}
    
              // Write Bootloader start address to MBR 
              *(volatile uint32_t *)MBR_BOOTLOADER_ADDR = BOOTLOADER_START_ADDR;
              // Write MBR parameter page address to MBR
              *(volatile uint32_t *)MBR_PARAM_PAGE_ADDR = NRF_MBR_PARAMS_PAGE_ADDRESS;
              // Revert NVMC to read-only
              NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Ren << NVMC_CONFIG_WEN_Pos;
              while (NRF_NVMC->READY == NVMC_READY_READY_Busy){}
          }
    
        return NRF_SUCCESS;
    }

    Best regards

    Bjørn

Children
No Data
Related