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

nRF52 simple SPI bootloader problems

Hi,

I've managed to code an app for nRF52382 (S132, SDK14) which works properly. Also, I've taken "bootloader_secure_serial" and removed a lot of stuff to code a simple SPI bootloader which reads data from external SPI data flash.

So in short, what I did... I know the addresses: MBR: 0x0 - 0x1000, SoftDevice: 0x1000 - 0x23000, Application: 0x23000 - 0x79000, Bootloader: 0x79000 - 0x7E000, MBR data(?): 0x7E000 - 0x7F000, Empty(not used): 0x7F000 - 0x8000

Windows app is coded which splits MBR from SoftDevice hex (removes data from 0x0 to 0x1000), takes that data, takes application and bootloader and merges it into one binary file. It also adds CRC checks to data so it can be verified later.

Using mobile device, data is transferred and copied via nRF52 application to SPI data flash. When all data is copied, bootloader flags are raised and NVIC_SystemReset() is called so bootloader is started. In bootloader flags are checked, and if stored data(crc check) is valid data is flashed: 1.) First SoftDevice is copied using nvmc functions. 2.) Second is Bootloader, it's copied using MBR, command SD_MBR_COMMAND_COPY_BL. 3.) Third and final, application is copied using nvmc.

All that is completed without errors.

But, when everything is flashed and default function "nrf_bootloader_app_start" is called, code hangs(stucks, freezes!) at "nrf_dfu_mbr_init_sd()" call. I've read that this is because SoftDevice is already initialized. According to that, removing the call to "nrf_dfu_mbr_init_sd()" function results in another error from "sd_softdevice_vector_table_base_set()" function. It returns NRF_ERROR_SVC_HANDLER_MISSING.

This concept works flawlessly on nRF51, so I guess I'm missing some information for it to work on nRF52.

How to start the app correctly? Is there some other data which must be preserved(which I missed implementing this)?

Thanks!

  • I do not see a reason why this should not work on the nRF52 as well, but I do not have a full overview of your bootloader (it seems you have made quite a few changes). Can you upload the code for your bootloader? If not, can you create a support case on My page and upload it there?

  • I've created a support case in My page since it has a lot of code changes, would be hard to copy everything here. Thanks!

  • Hello, I am having a very similar issue. I get NRF_ERROR_SVC_HANDLER_MISSING when calling nrf_dfu_mbr_init_sd.  Is there a solution for this problem?

  • Hi,

    Can you elaborate?

    Generally, you will get NRF_ERROR_SVC_HANDLER_MISSING if using an invalid SVC number (without a handler). The typical reason for this is building against SoftDevice header files for a different SoftDevice version (including MBR) than what is actually used.

  • I am creating a custom bootloader for NRF52832 that will update my application that uses S132 V3.1.  My bootloader project uses SDK 16.0, S132 V3.1 headers, and Segger Studio.  Here is sequence/intent:

    1.  Device boot into bootloader via uicr_bootloader_start_address set at bootloader vector @0x6C000.  This works perfectly.
    2.  Bootloader overwrite flash using NVMC. (Not yet implemented).
    3.  Bootloader verify flash. (Not yet implemented).
    4.  Bootloader calls SD_MBR_COMMAND_INIT_SD (the failure is that the return code is 1 (NRF_ERROR_SVC_HANDLER_MISSING).
    5.  Bootloader calls sd_softdevice_disable.
    6.  Bootloader calls sd_softdevice_vector_table_base_set (also, the failure is that the return code is 1 (NRF_ERROR_SVC_HANDLER_MISSING).
    7.  Bootloader calls nrf_bootloader_app_start_impl(0x1F000) from SDK 12.

    Currently, the bootloader does nothing other than jumping into the application that's preloaded via J-Link @0x1F000.  MBR and SoftDevice V3.1 is also preloaded. The problem seems to be calling SD_MBR_COMMAND_INIT_SD and sd_softdevice_vector_table_base_set.  Both function returns 1 for some reason.  And when nrf_bootloader_app_start_impl is called, it results in HardFault_Handler.

    #include <stdint.h>
    #include "app_error.h"
    #include "nrf_assert.h"
    #include "nrf_sdm.h"  //from s132nrf52310
    #include "nrf_mbr.h"  //from s132nrf52310
    
    
    volatile uint32_t m_uicr_bootloader_start_address  __attribute__ ((section(".uicr_bootloader_start_address"))) = 0x6C000;
    volatile uint32_t m_uicr_mbr_params_page  __attribute__ ((section(".uicr_mbr_params_page"))) = 0x7e000;
    
    static void __attribute__ ((noinline)) nrf_bootloader_app_start_impl(uint32_t start_addr)
    {
        __ASM volatile(
            "ldr   r0, [%0]\t\n"            // Get App initial MSP for bootloader.
            "msr   msp, r0\t\n"             // Set the main stack pointer to the applications MSP.
            "ldr   r0, [%0, #0x04]\t\n"     // Load Reset handler into R0.
    
            "movs  r4, #0xFF\t\n"           // Move ones to R4.
            "sxtb  r4, r4\t\n"              // Sign extend R4 to obtain 0xFFFFFFFF instead of 0xFF.
    
            "mrs   r5, IPSR\t\n"            // Load IPSR to R5 to check for handler or thread mode.
            "cmp   r5, #0x00\t\n"           // Compare, if 0 then we are in thread mode and can continue to reset handler of bootloader.
            "bne   isr_abort\t\n"           // If not zero we need to exit current ISR and jump to reset handler of bootloader.
    
            "mov   lr, r4\t\n"              // Clear the link register and set to ones to ensure no return.
            "bx    r0\t\n"                  // Branch to reset handler of bootloader.
    
            "isr_abort:  \t\n"
    
            "mov   r5, r4\t\n"              // Fill with ones before jumping to reset handling. Will be popped as LR when exiting ISR. Ensures no return to application.
            "mov   r6, r0\t\n"              // Move address of reset handler to R6. Will be popped as PC when exiting ISR. Ensures the reset handler will be executed when exist ISR.
            "movs  r7, #0x21\t\n"           // Move MSB reset value of xPSR to R7. Will be popped as xPSR when exiting ISR. xPSR is 0x21000000 thus MSB is 0x21.
            "rev   r7, r7\t\n"              // Reverse byte order to put 0x21 as MSB.
            "push  {r4-r7}\t\n"             // Push everything to new stack to allow interrupt handler to fetch it on exiting the ISR.
    
            "movs  r4, #0x00\t\n"           // Fill with zeros before jumping to reset handling. We be popped as R0 when exiting ISR (Cleaning up of the registers).
            "movs  r5, #0x00\t\n"           // Fill with zeros before jumping to reset handling. We be popped as R1 when exiting ISR (Cleaning up of the registers).
            "movs  r6, #0x00\t\n"           // Fill with zeros before jumping to reset handling. We be popped as R2 when exiting ISR (Cleaning up of the registers).
            "movs  r7, #0x00\t\n"           // Fill with zeros before jumping to reset handling. We be popped as R3 when exiting ISR (Cleaning up of the registers).
            "push  {r4-r7}\t\n"             // Push zeros (R4-R7) to stack to prepare for exiting the interrupt routine.
    
            "movs  r0, #0xF9\t\n"           // Move the execution return command into register, 0xFFFFFFF9.
            "sxtb  r0, r0\t\n"              // Sign extend R0 to obtain 0xFFFFFFF9 instead of 0xF9.
            "bx    r0\t\n"                  // No return - Handler mode will be exited. Stack will be popped and execution will continue in reset handler initializing other application.
            ".align\t\n"
            :: "r" (start_addr)             // Argument list for the gcc assembly. start_addr is %0.
            :  "r0", "r4", "r5", "r6", "r7" // List of register maintained manually.
        );
    }
    /*********************************************************************
    *
    *       main()
    *
    *  Function description
    *   Application entry point.
    */
    void main(void) {
      
        uint32_t         err_code;
        sd_mbr_command_t com;
        com.command = SD_MBR_COMMAND_INIT_SD;
        err_code = sd_mbr_command(&com);
    
        sd_softdevice_disable();
        err_code = sd_softdevice_vector_table_base_set(0x1F000);
    
        nrf_bootloader_app_start_impl(0x1F000);
    
      do {
      } while (1);
    }
    /*************************** End of file ****************************/
    

Related