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

NRF51822 DFU Problem

I built the GCC bootloader from source based on the suggestion of another user in this forum instead of using a precompiled hex file. The Softdevice is 7.1.

It shows DfuTarg. And using nRF Toolbox, I can send a zip package of a new application. It works 100% of the time.

The new application is using the same Softdevice and SDK. I added the Dfu service by using the reference code in ble hrs sample.

Once that new application is sent, I can select its device name in nRF Toolbox in the DFU menu, and send the same zip application just to try a firmware update.

However, with the application running, it fails 100% of the time. Upload failed : Gatt Error (133).

With nRF Master Control Panel, the log shows : Error (0x81) : GATT Internal Error, then Error (0x85) GATT Error.

I searched on google and this forum and I haven't found a problem similar to this.

Here is the parameters I used :

Linker script for bootloader : /* Linker script to configure memory regions. */

SEARCH_DIR(.)
GROUP(-lgcc -lc -lnosys)

MEMORY
{
  FLASH (rx) : ORIGIN = 0x00035000, LENGTH = 44K 
  RAM (rwx) :  ORIGIN = 0x20002000, LENGTH = 0x2000 
  BOOTLOADER_SETTINGS (rwx) : ORIGIN = 0x0003FC00, LENGTH = 0x400
}
SECTIONS
{
    .bootloaderSettings 0x0003FC00 :
  {
	
  } 
	.uicrBootStartAddress 0x10001014 :
	{
    
  } 
}	

INCLUDE "gcc_nrf51_common.ld"

Linker script for application :

/* Linker script to configure memory regions. */

SEARCH_DIR(.)
GROUP(-lgcc -lc -lnosys)

MEMORY
{
  FLASH (rx) : ORIGIN = 0x00016000, LENGTH = 0x2A000 
  RAM (rwx) :  ORIGIN = 0x20002000, LENGTH = 0x2000 
}

INCLUDE "gcc_nrf51_common.ld"

Modified dfu_types.h

#define BOOTLOADER_REGION_START         0x00035000 

To create the init packet :

nrf.exe dfu genpkg app.zip --application firmware.hex --application-version 0xffff --dev-revision 0xffff --dev-type 0xffff --sd-req 0x5a

At the end of ble_service_init:

    ble_dfu_init_t   dfus_init;

    // Initialize the Device Firmware Update Service.
    memset(&dfus_init, 0, sizeof(dfus_init));

    dfus_init.evt_handler    = dfu_app_on_dfu_evt;
    dfus_init.error_handler  = NULL; //service_error_handler - Not used as only the switch from app to DFU mode is required and not full dfu service.
    dfus_init.revision       = DFU_REVISION;

    err_code = ble_dfu_init(&m_dfus, &dfus_init);
    APP_ERROR_CHECK(err_code);
    
    dfu_app_reset_prepare_set(reset_prepare);

Function reset_prepare:

static void reset_prepare(void)
{
	uint8_t err_code;
    if(mConnectionHandle != BLE_CONN_HANDLE_INVALID)
    {
        err_code = sd_ble_gap_disconnect(mConnectionHandle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
        APP_ERROR_CHECK(err_code);
    }
    else
    {
        // If not connected, then the device will be advertising. Hence stop the advertising.
        sd_ble_gap_adv_stop();
    }
}

I tried hundreds of combination of differents parameters to try to understand what is going on... Anybody have an idea how could I fix this ?

Thank you very much again!

Simon

Parents
  • Hi,

    Based on your reporting I assume you are trying out the buttonless update procedure, where you jump from application into the bootloader. For this to work, the bootloader needs to know the LTK, IRK and Address of the device which triggered the DFU mode. Those are distributed from the app to bootloader through an SVC as described in: developer.nordicsemi.com/.../a00079.html

    This means that the SVC must be implemented in the bootloader, which I assume that you already do. However, the data will be located in RAM and it is therefore critical that this data is not zero initialized upon reset into bootloader.

    Look in the file: dfu_ble_svc.c and find the definition of m_peer_data and m_peer_data_crc. Ensure those are placed in no init section, for gcc:

    __attribute__((section(".noinit"))) static dfu_ble_peer_data_t m_peer_data; 
    __attribute__((section(".noinit"))) static uint16_t            m_peer_data_crc;
    

    And then ensure to define this section in the linker script:

    As example:

    MEMORY
    {
      /** Flash start address for the bootloader. This setting will also be stored in UICR to allow the
       *  MBR to init the bootloader when starting the system. This value must correspond to 
       *  BOOTLOADER_REGION_START found in dfu_types.h. The system is prevented from starting up if 
       *  those values do not match. The check is performed in main.c, see
       *  APP_ERROR_CHECK_BOOL(*((uint32_t *)NRF_UICR_BOOT_START_ADDRESS) == BOOTLOADER_REGION_START);
       */
      FLASH (rx) : ORIGIN = 0x3C000, LENGTH = 0x3C00
    
      /** RAM Region for bootloader. This setting is suitable when used with s110, s120, s130, s310. */
      RAM (rwx) :  ORIGIN = 0x20002c00, LENGTH = 0x5380
    
      /** Location of non initialized RAM. Non initialized RAM is used for exchanging bond information
       *  from application to bootloader when using buttonluss DFU OTA. 
       */
      NOINIT (rwx) :  ORIGIN = 0x20007f80, LENGTH = 0x80
    
      /** Location of bootloader setting in at the last flash page. */
      BOOTLOADER_SETTINGS (rw) : ORIGIN = 0x0003FC00, LENGTH = 0x0400
    
      /** Location in UICR where bootloader start address is stored. */
      UICR_BOOTLOADER (r) : ORIGIN = 0x10001014, LENGTH = 0x04
    }
    
    SECTIONS
    {
      /* Ensures the bootloader settings are placed at the last flash page. */
      .bootloaderSettings :
      {
    	
      } > BOOTLOADER_SETTINGS
    
      /* Ensures the Bootloader start address in flash is written to UICR when flashing the image. */
      .uicrBootStartAddress : 
      {
        KEEP(*(.uicrBootStartAddress))
      } > UICR_BOOTLOADER
    
      /* No init RAM section in bootloader. Used for bond information exchange. */
      .noinit :
      {
    
      } > NOINIT
      /* other placements follow here... */
    }
    

    Note that the memory layout here is for 32 kB RAM version. Adjust accordingly for the 16kB version.

    Try also to see if your device is advertising with another address (normal address + 1), as this will also indicate that the peer data has not been succesfully exchanged.

Reply
  • Hi,

    Based on your reporting I assume you are trying out the buttonless update procedure, where you jump from application into the bootloader. For this to work, the bootloader needs to know the LTK, IRK and Address of the device which triggered the DFU mode. Those are distributed from the app to bootloader through an SVC as described in: developer.nordicsemi.com/.../a00079.html

    This means that the SVC must be implemented in the bootloader, which I assume that you already do. However, the data will be located in RAM and it is therefore critical that this data is not zero initialized upon reset into bootloader.

    Look in the file: dfu_ble_svc.c and find the definition of m_peer_data and m_peer_data_crc. Ensure those are placed in no init section, for gcc:

    __attribute__((section(".noinit"))) static dfu_ble_peer_data_t m_peer_data; 
    __attribute__((section(".noinit"))) static uint16_t            m_peer_data_crc;
    

    And then ensure to define this section in the linker script:

    As example:

    MEMORY
    {
      /** Flash start address for the bootloader. This setting will also be stored in UICR to allow the
       *  MBR to init the bootloader when starting the system. This value must correspond to 
       *  BOOTLOADER_REGION_START found in dfu_types.h. The system is prevented from starting up if 
       *  those values do not match. The check is performed in main.c, see
       *  APP_ERROR_CHECK_BOOL(*((uint32_t *)NRF_UICR_BOOT_START_ADDRESS) == BOOTLOADER_REGION_START);
       */
      FLASH (rx) : ORIGIN = 0x3C000, LENGTH = 0x3C00
    
      /** RAM Region for bootloader. This setting is suitable when used with s110, s120, s130, s310. */
      RAM (rwx) :  ORIGIN = 0x20002c00, LENGTH = 0x5380
    
      /** Location of non initialized RAM. Non initialized RAM is used for exchanging bond information
       *  from application to bootloader when using buttonluss DFU OTA. 
       */
      NOINIT (rwx) :  ORIGIN = 0x20007f80, LENGTH = 0x80
    
      /** Location of bootloader setting in at the last flash page. */
      BOOTLOADER_SETTINGS (rw) : ORIGIN = 0x0003FC00, LENGTH = 0x0400
    
      /** Location in UICR where bootloader start address is stored. */
      UICR_BOOTLOADER (r) : ORIGIN = 0x10001014, LENGTH = 0x04
    }
    
    SECTIONS
    {
      /* Ensures the bootloader settings are placed at the last flash page. */
      .bootloaderSettings :
      {
    	
      } > BOOTLOADER_SETTINGS
    
      /* Ensures the Bootloader start address in flash is written to UICR when flashing the image. */
      .uicrBootStartAddress : 
      {
        KEEP(*(.uicrBootStartAddress))
      } > UICR_BOOTLOADER
    
      /* No init RAM section in bootloader. Used for bond information exchange. */
      .noinit :
      {
    
      } > NOINIT
      /* other placements follow here... */
    }
    

    Note that the memory layout here is for 32 kB RAM version. Adjust accordingly for the 16kB version.

    Try also to see if your device is advertising with another address (normal address + 1), as this will also indicate that the peer data has not been succesfully exchanged.

Children
  • Thank you for your detailed explanation.

    I updated the linker file and verified the dfu_ble_svc.c file according to your answer. I also ajusted the memory layout for 16 kB RAM version.

    However, I still have the same result.

    Here are the new files :

    Bootloader Linker file :

    /* Linker script to configure memory regions. */
    
    SEARCH_DIR(.)
    GROUP(-lgcc -lc -lnosys)
    
    MEMORY
    {
      FLASH (rx) : ORIGIN = 0x00035000, LENGTH = 0xB000
      RAM (rwx) :  ORIGIN = 0x20002000, LENGTH = 0x1F80
      NOINIT (rwx) :  ORIGIN = 0x20003F80, LENGTH = 0x80
      BOOTLOADER_SETTINGS (rwx) : ORIGIN = 0x0003FC00, LENGTH = 0x400
      UICR_BOOTLOADER (r) : ORIGIN = 0x10001014, LENGTH = 0x04
    }
    SECTIONS
    {
      .bootloaderSettings :
      {
    
      } > BOOTLOADER_SETTINGS
    
      /* Ensures the Bootloader start address in flash is written to UICR when flashing the image. */
      .uicrBootStartAddress : 
      {
        KEEP(*(.uicrBootStartAddress))
      } > UICR_BOOTLOADER
    
      /* No init RAM section in bootloader. Used for bond information exchange. */
      .NoInit :
      {
    
      } > NOINIT
    }	
    
    INCLUDE "gcc_nrf51_common.ld"
    

    Application linker file

    /* Linker script to configure memory regions. */
    
    SEARCH_DIR(.)
    GROUP(-lgcc -lc -lnosys)
    
    MEMORY
    {
      FLASH (rx) : ORIGIN = 0x00016000, LENGTH = 0x2A000 
      RAM (rwx) :  ORIGIN = 0x20002000, LENGTH = 0x2000
    }
    
    INCLUDE "gcc_nrf51_common.ld"
    

    dfu_ble_svc.c

    #if defined   ( __GNUC__ )
    static dfu_ble_peer_data_t m_peer_data __attribute__((section(".NoInit")))__attribute__((used));     /**< This variable should be placed in a non initialized RAM section in order to be valid upon soft reset from application into bootloader. */
    static uint16_t            m_peer_data_crc __attribute__((section(".NoInit")))__attribute__((used)); /**< CRC variable to ensure the integrity of the peer data provided. */
    
    #else
    static dfu_ble_peer_data_t m_peer_data __attribute__((section("NoInit"), zero_init));     /**< This variable should be placed in a non initialized RAM section in order to be valid upon soft reset from application into bootloader. */
    static uint16_t            m_peer_data_crc __attribute__((section("NoInit"), zero_init)); /**< CRC variable to ensure the integrity of the peer data provided. */
    #endif
    

    Bootloader map file

    .bootloaderSettings
                    0x0003fc00      0x400
     .bootloaderSettings
                    0x0003fc00      0x400 _build/bootloader_util_gcc.o
                    0x0003fc00                m_boot_settings
    
    .uicrBootStartAddress
                    0x10001014        0x4
     *(.uicrBootStartAddress)
     .uicrBootStartAddress
                    0x10001014        0x4 _build/bootloader_util_gcc.o
                    0x10001014                m_uicr_bootloader_start_address
    
    .NoInit         0x20003f80       0x30
     .NoInit        0x20003f80       0x30 _build/dfu_ble_svc.o
    

    Last part of Application Map file in the ending region of the ram allocation

                    0x20002700                m_ble_evt_handler.lto_priv.86
                    0x20002704                m_ble_evt_buffer_size.lto_priv.88
                    0x20002708                m_evt_buffer.lto_priv.87
     *(COMMON)
                    0x2000270c                . = ALIGN (0x4)
                    0x2000270c                __bss_end__ = .
    
    .heap           0x20002710      0x800
                    0x20002710                __end__ = .
                    0x20002710                end = __end__
     *(.heap*)
     .heap          0x20002710      0x800 _build/gcc_startup_nrf51.o
                    0x20002710                __HeapBase
                    0x20002f10                __HeapLimit = .
    
    .stack_dummy    0x20002710      0x800
     *(.stack*)
     .stack         0x20002710      0x800 _build/gcc_startup_nrf51.o
                    0x20004000                __StackTop = (ORIGIN (RAM) + 0x2000)
                    0x20003800                __StackLimit = (__StackTop - SIZEOF (.stack_dummy))
                    0x20004000                PROVIDE (__stack, __StackTop)
                    0x00000001                ASSERT ((__StackLimit >= __HeapLimit), region RAM overflowed with stack)
    

    Anybody see something wrong in these files ?

    Thank you,

    Simon

Related