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

buttonless DFU - bootloader hangs

hi,

I am trying to integrate buttonless switch to boot loader as explained in the documentation and the hrs experimental example.

I am working on SDK7.2.0 and using the nrf51DK so far - later on I will port everything to my own hardware, but the DK is convenient for now.

Here is what I did:

I have compiled the boot loader project in the SDK7.2 with Keil, and programmed it to my nrf51dk together with the soft device. Then I also compiled the experimental hrs example, generated a zip file to flash with the nrf toolbox from my iphone, and that all worked fine. Also was able to flash my own application when switching to boot loader via the button+reset. So far so good.

Then, i integrated the dfu service as described in the documentation of the experimental example:

  • Add DFU related files to BLE example project: bootloader_util_arm.c,ble_dfu.c,dfu_app_handler.c
  • Implement the reset_prepare() function
  • Initialize the DFU Service
  • Propagate SoftDevice BLE events to the DFU Service.

Now, when my own application is running, I can see the DFU service, and can make the application switch to boot loader by enabling notifications and writing 0x0104 to the control point, or at least I have the impression it switched to boot loader, as LED1 and LED3 are lit, just like when I switch to boot loader. When I then go to nRF Toolbox > DFU, I can select my device, can select my file and so on, and tap 'Upload', and then nothing seems to happen: progress bar appears but stays at 0.

One thing I need to note: I commented out the content of du_app_set_peer_data, as it uses a function from the device_manager, but I do not use any security, so I do not use the device manager. Could this cause the behavior I am seeing? Or is there something else that could cause this?

Update: added the device_manager and all necessary files, and that does not make any difference.

Can the fact that I compiled the boot loader with Keil and my application with GCC be the cause? I checked everything else again, and do not really see any difference between how I integrated it and how it was done in the example.

  • @wim: Could you check if you use our experimental ble_app_hrs with dfu it would work for you ? That you can set the device in bootloader mode by writing to the DFU characteristic and can overwrite the hrs firmware with something else ?

    You should also check if your initdata is prepared correctly. But I assume that it's correct since you mentioned that you managed to update your application using button+reset.

    Have you made sure you enabled IS_SRVC_CHANGED_CHARACT_PRESENT = 1 in your application main.c ?

  • ble_app_hrs with dfu does work when I compile it with Keil. But when I compile it with gcc then it doesn't work.

  • In the side note a reference is made to bootloader_util_reset() in bootloader_util.c. In SDK7.2 I only have a bootloader_util_gcc.c, and there is no bootloader_util_reset function in there, only a 'StartApplication'. Is it that function I need to replace withbootloader_util_reset of 9.0.0? Do i need some change to the linker script too? Because after replacing the code with the code of sdk9, I get following linker error: /.../myproject/src/dfu/bootloader_util_gcc.c: In function 'bootloader_util_reset': /.../myproject/src/dfu/bootloader_util_gcc.c:73:1: error: r7 cannot be used in asm here } ^ lto-wrapper: /Applications/gcc-arm-none-eabi-4_9-2015q1/bin/arm-none-eabi-g++ returned 1 exit status /Applications/gcc-arm-none-eabi-4_9-2015q1/bin/../lib/gcc/arm-none-eabi/4.9.3/../../../../arm-none-eabi/bin/ld: lto-wrapper failed collect2: error: ld returned 1 exit status

  • @wim: I'm sorry, you were correct, in the bootloader_util_gcc.c we called the function "StartApplication()"

    But the principle is the same, you replace the code you found in side bootloader_util_reset() in bootloader_util.c in SDK 9.0 to the code in bootloader_util_gcc.c in StartApplication() in SDK v7.2.

    Your function should look like this:

    static inline void StartApplication(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.
        );
    }
    

    bootloader_util_gcc.c

Related