NRF51 SDK 9.0.0 S110 Buttonless DFU Issue (Segger Embedded Studio)

Hi there,

I am working with an application that uses the NRF51 chip (through the Taiyo Yuden EYSGCNZWY BLE module) and am trying to implement buttonless DFU. I am having issues starting DFU when enabling through the Legacy DFU Service from the application. The application thus far is functional without the DFU feature using SDK9.

Setup details:

  • S110 softdevice
  • BLE module EYSGCNZWY using NRF51822_xxAC
  • SDK 9.0.0
  • Bootloader in Keil
  • Application in Segger Embedded Studio v5.44

Application was modified to include DFU features from example project ble_app_hrs_s110_with_dfu_pca10028 from Keil. When simply using the ble_app_hrs_s110_with_dfu_pca10028 project the buttonless DFU works without an issue. The Legacy DFU Service comes up correctly on nrf Connect and The application is based on the HID desktop_keyboard example, and requires the central to pair with the device upon connection. The function 'bootloader_start' in 'dfu_app_handler' is used to re-enter bootloader upon receiving a BLE_DFU_START event from the DFU service. What I have noticed is the GPREGRET register (which is set to 0xB1 before jumping to bootloader) is not set to 0xB1 when the bootloader starts (found by debugging the bootloader). It shows 0x04 as its value, and thus tries to jump back into the application. At that point the application does not start up correctly (and the DFU times out). See attached for the DFU log messages as well. 

The application was likely imported to SES from a Keil project (before my time) and includes the "Internal Files" 'flash_placement.xml', 'ses_nrf51_startup.s', 'thumb_crt0.s' and 'system_nrf51.c'. I have attached these files. I also tried replacing them with what I could find from SDK 12 (this link) but there was a build error: 'undefined reference to __SRAM_segment_end__'.
The application Linker relevant settings are:
Memory Segments: FLASH RX 0x00000000 0x00040000; RAM RWX 0x200000000 0x00008000
Section Placement File: flash_placement.xml
Section Placement Macros: FLASH_START=0x18000; FLASH_SIZE=0x24000; SRAM_START=0x20002000; SRAM_SIZE=0x2000

The sequence of events is as follows:

  • After erasing chip, the S110 softdevice and bootloader are loaded to the device successfully. The bootloader is a slightly modified version of the dual_bank_ble_s110 project from SDK 9. The minor changes to the bootloader include changing clock frequency for compatibility with the EYSGCNZWY module, replacing dfu_dual_bank.c with dfu_single_bank.c and removal of button for entering DFU. The bootloader is built in Keil. Memory map is as follows:
    IROM1: Start->0x3C000, Size->0x3C00
    IRAM1: Start->0x20002000, Size->0x3F80
    IRAM2 (NoInit): Start->0x20005F80, Size->0x80

  • Once S110 and bootloader are loaded to device, it starts advertising as DfuTarg. Using nRF Connect I am able to connect to DfuTarg and upload the application successfully.
  • From nRF connect I re-connect to the device (now advertising with the application specific device name), and the device asks to pair the device. Once device pairing is confirmed, the application runs normally (if DFU is not used). If a DFU upload is initiated from nRF connect the process starts, jumps to the bootloader, then restarts the DFU, jumps to bootloader again, and eventually the connection times out. The nRF connect logs are also attached.

My gut tells me the issue is with the memory placements of the application and bootloader and their interaction, but I'm really not sure about the solution or what to try next. Any debugging support would be greatly appreciated!   

  

0753.thumb_crt0.s0257.ses_nrf51_startup.s

<!DOCTYPE Linker_Placement_File>
<Root name="Flash Section Placement">
  <MemorySegment name="$(FLASH_NAME:FLASH)">
    <ProgramSection alignment="0x100" load="Yes" name=".vectors" start="$(FLASH_START:)" />
    <ProgramSection alignment="4" keep="Yes" load="Yes" name=".gzp_params" start="0x00020000" size="1024" />
    <ProgramSection alignment="4" keep="Yes" load="Yes" name=".hummingbird_params" start="0x00020400" size="1024" />
    <ProgramSection alignment="4" load="Yes" name=".init" />
    <ProgramSection alignment="4" load="Yes" name=".init_rodata" />
    <ProgramSection alignment="4" load="Yes" name=".text" />
    <ProgramSection alignment="4" load="Yes" name=".dtors" />
    <ProgramSection alignment="4" load="Yes" name=".ctors" />
    <ProgramSection alignment="4" load="Yes" name=".rodata" />
    <ProgramSection alignment="4" load="Yes" name=".ARM.exidx" address_symbol="__exidx_start" end_symbol="__exidx_end" />
    <ProgramSection alignment="4" load="Yes" runin=".fast_run" name=".fast" />
    <ProgramSection alignment="4" load="Yes" runin=".data_run" name=".data" />
    <ProgramSection alignment="4" load="Yes" runin=".tdata_run" name=".tdata" />
    <ProgramSection alignment="4" keep="Yes" load="Yes" name=".dfu_trans" inputsections="*(SORT(.dfu_trans*))" address_symbol="__start_dfu_trans" end_symbol="__stop_dfu_trans" />
    <ProgramSection alignment="4" keep="Yes" load="Yes" name=".log_const_data" inputsections="*(.log_const_data*)" address_symbol="__start_log_const_data" end_symbol="__stop_log_const_data" />
    <ProgramSection alignment="4" keep="Yes" load="Yes" name=".svc_data" inputsections="*(.svc_data*)" address_symbol="__start_svc_data" end_symbol="__stop_svc_data" />
    <ProgramSection alignment="4" keep="Yes" load="Yes" name=".sdh_ble_observers" inputsections="*(SORT(.sdh_ble_observers*))" address_symbol="__start_sdh_ble_observers" end_symbol="__stop_sdh_ble_observers" />
    <ProgramSection alignment="4" keep="Yes" load="Yes" name=".sdh_req_observers" inputsections="*(SORT(.sdh_req_observers*))" address_symbol="__start_sdh_req_observers" end_symbol="__stop_sdh_req_observers" />
    <ProgramSection alignment="4" keep="Yes" load="Yes" name=".sdh_state_observers" inputsections="*(SORT(.sdh_state_observers*))" address_symbol="__start_sdh_state_observers" end_symbol="__stop_sdh_state_observers" />
    <ProgramSection alignment="4" keep="Yes" load="Yes" name=".sdh_stack_observers" inputsections="*(SORT(.sdh_stack_observers*))" address_symbol="__start_sdh_stack_observers" end_symbol="__stop_sdh_stack_observers" />
    <ProgramSection alignment="4" keep="Yes" load="Yes" name=".sdh_soc_observers" inputsections="*(SORT(.sdh_soc_observers*))" address_symbol="__start_sdh_soc_observers" end_symbol="__stop_sdh_soc_observers" />
    <ProgramSection alignment="4" keep="Yes" load="Yes" name=".nrf_sections" address_symbol="__start_nrf_sections" />
    <ProgramSection alignment="4" keep="Yes" load="Yes" name=".log_dynamic_data" inputsections="*(.log_dynamic_data*)" runin=".log_dynamic_data_run" />
    <ProgramSection alignment="4" keep="Yes" load="Yes" name=".fs_data" inputsections="*(.fs_data*)" runin=".fs_data_run" />
  </MemorySegment>
  <MemorySegment name="$(RAM_NAME:RAM);SRAM">
    <ProgramSection alignment="0x100" load="No" name=".vectors_ram" start="$(RAM_START:$(SRAM_START:))" />
    <ProgramSection alignment="4" load="No" name=".fast_run" />
    <ProgramSection alignment="4" load="No" name=".data_run" />
    <ProgramSection alignment="4" load="No" name=".tdata_run" />
    <ProgramSection alignment="4" keep="Yes" load="No" name=".nrf_sections_run" address_symbol="__start_nrf_sections_run" />
    <ProgramSection alignment="4" keep="Yes" load="No" name=".log_dynamic_data_run" address_symbol="__start_log_dynamic_data" end_symbol="__stop_log_dynamic_data" />
    <ProgramSection alignment="4" keep="Yes" load="No" name=".fs_data_run" address_symbol="__start_fs_data" end_symbol="__stop_fs_data" />
    <ProgramSection alignment="4" keep="Yes" load="No" name=".nrf_sections_run_end" address_symbol="__end_nrf_sections_run" />
    <ProgramSection alignment="4" load="No" name=".bss" />
    <ProgramSection alignment="4" load="No" name=".tbss" />
    <ProgramSection alignment="4" load="No" name=".non_init"/>
    <ProgramSection alignment="4" size="__HEAPSIZE__" load="No" name=".heap" />
    <ProgramSection alignment="8" size="__STACKSIZE__" load="No" place_from_segment_end="Yes" name=".stack" address_symbol="__StackLimit" end_symbol="__StackTop" />
    <ProgramSection alignment="8" size="__STACKSIZE_PROCESS__" load="No" name=".stack_process" />
  </MemorySegment>
  <MemorySegment name="FLASH2">
    <ProgramSection alignment="4" load="Yes" name=".text2" />
    <ProgramSection alignment="4" load="Yes" name=".rodata2" />
    <ProgramSection alignment="4" load="Yes" runin=".data2_run" name=".data2" />
  </MemorySegment>
  <MemorySegment name="SRAM2">
    <ProgramSection alignment="4" load="No" name=".data2_run" />
    <ProgramSection alignment="4" load="No" name=".bss2" />
  </MemorySegment>
</Root>
/* Copyright (c) 2015, Nordic Semiconductor ASA
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *   * Redistributions of source code must retain the above copyright notice, this
 *     list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright notice,
 *     this list of conditions and the following disclaimer in the documentation
 *     and/or other materials provided with the distribution.
 *
 *   * Neither the name of Nordic Semiconductor ASA nor the names of its
 *     contributors may be used to endorse or promote products derived from
 *     this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

/* NOTE: Template files (including this one) are application specific and therefore expected to 
   be copied into the application project folder prior to its use! */

#include <stdint.h>
#include <stdbool.h>
#include "nrf.h"
#include "system_nrf51.h"

/*lint ++flb "Enter library region" */

#if defined ( TAIYO_YUDEN_EBSGCN )
#define __SYSTEM_CLOCK      (32000000UL)     /*!< Taiyo Yuden [nRF51822] module has a System Clock Frequency of 32MHz */
#else
#define __SYSTEM_CLOCK      (16000000UL)     /*!< nRF51422 devices use a fixed System Clock Frequency of 16MHz */
#endif

static bool is_manual_peripheral_setup_needed(void);
static bool is_disabled_in_debug_needed(void);


#if defined ( __CC_ARM )
    uint32_t SystemCoreClock __attribute__((used)) = __SYSTEM_CLOCK;  
#elif defined ( __ICCARM__ )
    __root uint32_t SystemCoreClock = __SYSTEM_CLOCK;
#elif defined   ( __GNUC__ )
    uint32_t SystemCoreClock __attribute__((used)) = __SYSTEM_CLOCK;
#endif

void SystemCoreClockUpdate(void)
{
    SystemCoreClock = __SYSTEM_CLOCK;
}

void SystemInit(void)
{
#if defined ( TAIYO_YUDEN_EBSGCN )
if( *((uint32_t *)0x10001008) == 0xFFFFFFFF )
{
  NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Wen << NVMC_CONFIG_WEN_Pos;
  while( NRF_NVMC->READY == NVMC_READY_READY_Busy ) {}
  *((uint32_t *)0x10001008) = 0xFFFFFF00;
  NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Ren << NVMC_CONFIG_WEN_Pos;
  while( NRF_NVMC->READY == NVMC_READY_READY_Busy ) {}
  NVIC_SystemReset();
  while( true ) {}
}
#endif

    /* If desired, switch off the unused RAM to lower consumption by the use of RAMON register.
       It can also be done in the application main() function. */

    /* Prepare the peripherals for use as indicated by the PAN 26 "System: Manual setup is required
       to enable the use of peripherals" found at Product Anomaly document for your device found at
       https://www.nordicsemi.com/. The side effect of executing these instructions in the devices 
       that do not need it is that the new peripherals in the second generation devices (LPCOMP for
       example) will not be available. */
    if (is_manual_peripheral_setup_needed())
    {
        *(uint32_t volatile *)0x40000504 = 0xC007FFDF;
        *(uint32_t volatile *)0x40006C18 = 0x00008000;
    }
    
    /* Disable PROTENSET registers under debug, as indicated by PAN 59 "MPU: Reset value of DISABLEINDEBUG
       register is incorrect" found at Product Anomaly document four your device found at 
       https://www.nordicsemi.com/. There is no side effect of using these instruction if not needed. */
    if (is_disabled_in_debug_needed())
    {
        NRF_MPU->DISABLEINDEBUG = MPU_DISABLEINDEBUG_DISABLEINDEBUG_Disabled << MPU_DISABLEINDEBUG_DISABLEINDEBUG_Pos;
    }
}


static bool is_manual_peripheral_setup_needed(void) 
{
    if ((((*(uint32_t *)0xF0000FE0) & 0x000000FF) == 0x1) && (((*(uint32_t *)0xF0000FE4) & 0x0000000F) == 0x0))
    {
        if ((((*(uint32_t *)0xF0000FE8) & 0x000000F0) == 0x00) && (((*(uint32_t *)0xF0000FEC) & 0x000000F0) == 0x0))
        {
            return true;
        }
        if ((((*(uint32_t *)0xF0000FE8) & 0x000000F0) == 0x10) && (((*(uint32_t *)0xF0000FEC) & 0x000000F0) == 0x0))
        {
            return true;
        }
        if ((((*(uint32_t *)0xF0000FE8) & 0x000000F0) == 0x30) && (((*(uint32_t *)0xF0000FEC) & 0x000000F0) == 0x0))
        {
            return true;
        }
    }
    
    return false;
}

static bool is_disabled_in_debug_needed(void) 
{
    if ((((*(uint32_t *)0xF0000FE0) & 0x000000FF) == 0x1) && (((*(uint32_t *)0xF0000FE4) & 0x0000000F) == 0x0))
    {
        if ((((*(uint32_t *)0xF0000FE8) & 0x000000F0) == 0x40) && (((*(uint32_t *)0xF0000FEC) & 0x000000F0) == 0x0))
        {
            return true;
        }
    }
    
    return false;
}

/*lint --flb "Leave library region" */

Parents
  • Hello,

    Since the peer manager (or perhaps it was called device manager in the old SDKs) stores the bonding data in flash, make sure that the bootloader has set aside some pages for "application persistent storage". Look in your bootloaders sdk_config.h for any parameters/definitions that could resemble this. 

    Also make sure that your application is aware of the bootloader, so that it sets the flash pages used by the device manager beneath the bootloader.

    Due to holiday season in Norway we are a bit short staffed from now until the beginning of January. Please expect some delay in answers during this period.

    Best regards,

    Edvin

  • Hi Edvin,

    Thanks for addressing my question. I have done quite a bit more digging and have some more details.

    The project that our application is based on is the nrfreadydesktop2v310 project 'desktop_keyboard' which is a reference design developed by Nordic. In our application the pairing was changed to not require a passkey entry by using BLE_GAP_IO_CAPS_NONE. Beyond that, the DFU handling in our application is very similar to (if not exactly copied from) the desktop_keyboard project.

    Using the bootloader provided in the desktop_keyboard example project I observed the following:

    1. Upload softdevice and bootloader (with modified clock frequency for the Taiyo Yuden EYSGCNZWY BLE module, and single bank rather than dual bank).
    2. Device starts advertising as DfuTarg and I can upload the application using nRF Connect successfully. 
    3. Application starts normally and I can pair with it using nRF Connect. 
    4. Initiate DFU using nRF Connect, but bootloader does not start the DFU process and instead jumps right to the application. This process repeats indefinitely. 

    This is the bootloader_start function in the application (directly copied from desktop_keyboard project):

    static void bootloader_start(uint16_t conn_handle)
    {
        uint32_t err_code;
        uint16_t sys_serv_attr_len = sizeof(m_peer_data.sys_serv_attr);
    
        err_code = sd_ble_gatts_sys_attr_get(conn_handle,
                                             m_peer_data.sys_serv_attr,
                                             &sys_serv_attr_len,
                                             BLE_GATTS_SYS_ATTR_FLAG_SYS_SRVCS);
          
        if (err_code != NRF_SUCCESS)
        {
            // This means the service changed indication cannot be sent in DFU mode, but connection
            // is still possible to establish.
        }
    
        m_reset_prepare();
        
        err_code = sd_power_gpregret_set(BOOTLOADER_DFU_START);
        APP_ERROR_CHECK(err_code);
    
        err_code = sd_softdevice_disable();
        APP_ERROR_CHECK(err_code);
    
        err_code = sd_softdevice_vector_table_base_set(NRF_UICR->BOOTLOADERADDR);
        APP_ERROR_CHECK(err_code);
    
        NVIC_ClearPendingIRQ(SWI2_IRQn);
        interrupts_disable();
        bootloader_util_app_start(NRF_UICR->BOOTLOADERADDR);
    }

    Another test I did was using the bootloader and ble_app_hrs_s110_with_dfu_pca10028 example from SDK9. To check if the segger import was the issue, I moved the ble_app_hrs_s110_with_dfu_pca10028 application to Segger. I uploaded the bootloader and application via DFU, and am also able to perform DFU initiated by the application. This is the desired result.

    The last test I ran was using the desktop_keyboard reference project with as limited changes as possible since this is likely the closest relation to the custom application. The main changes involved disabling the keyboard matrix and key scanning as well as using BLE_GAP_IO_CAPS_NONE. I can pair with the device and initiate the DFU process. The device then disconnects and starts advertising as DfuTarg. At that point I am able to connect to the DfuTarg device and re-initiate the DFU process which then completes. This isn't the exact behaviour I am looking for, however, it is different than what I am observing with the custom application. 

    Once again, any help would be greatly appreciated!

  • Have you tried to debug the bootloader to find out why it starts the application, and doesn't start in DFU mode? From your bootloader_start() function, there is a function that is called: sd_power_gpregret_set(BOOTLOADER_DFU_START);

    Is this register read in your bootloader? Is it searching for the same value that you set in your application (BOOTLOADER_DFU_START), and does this parameter (definition) have the same hexadecimal value in the bootloader and in your application?

    I am not in detail familiar with these old bootloaders (the generation before the secure_bootloader from SDK ~12). If you can't find where your bootloader reads the gpregret register, perhaps you can zip the bootloader and upload it here on DevZone?

    Best regards,

    Edvin

  • Hi Edvin,

    Thanks for the suggestion - I had been debugging the bootloader but through continued debugging with the desktop_keyboard bootloader I was able to see the DFU upload wasn't getting past the wait_for_events() function and more specifically the sd_app_evt_wait() function in bootloader.c. Doing further research into this issue I found an article that discussed the cause of this issue in SDK9 (https://www.programmerall.com/article/8197885958/).

    To summarize, I had the watchdog initialized in my application. By adding the watchdog feeding the DFU was not halted which was the cause of the continuous reset while in the bootloader. Now my custom application based on the desktop_keyboard project performs DFU the same was as the desktop_keyboard reference project. The challenge is still that the desktop_keyboard reference project does not perform DFU in the way I would like. As I explained previously, the desktop_keyboard reference initiates the DFU process from the application, then the device disconnects and advertises as DfuTarg. Then I can connect to DfuTarg and re-initiate the DFU process which completes successfully.

    The ble_app_hrs_s110_with_dfu_pca10028 example has a more desirable DFU process that doesn't require reconnecting, however, making the watchdog changes to this example bootloader didn't solve it for the custom application. Using the same custom application with the single_bank_ble_s110 bootloader and the watchdog feeding the DFU works the same as the desktop_keyboard example - not like the ble_app_hrs_s110_with_dfu_pca10028 example. When debugging the custom application it makes it to the bootloader_start() function, but halts before getting to bootloader_util_app_start(). When using the bootloader from the ble_app_hrs_s110_with_dfu_pca10028 bootloader (aka single_bank_ble_s110) I did implement a few changes in the application:

    • Added a reset_prepare() function (see below)
    • Added dfu_app_peer_data_set() call in bootloader_start() function

    static void reset_prepare(void)
    {
        uint32_t err_code;
    
        if (s_conn_handle != BLE_CONN_HANDLE_INVALID)
        {
            // Disconnect from peer.
            err_code = sd_ble_gap_disconnect(s_conn_handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
            APP_ERROR_CHECK(err_code);
        }
        else
        {
            // If not connected, the device will be advertising. Hence stop the advertising.
            advertising_stop();
        }
    
        err_code = ble_conn_params_stop();
        APP_ERROR_CHECK(err_code);
    
        nrf_delay_ms(500);
    }

    static void bootloader_start(uint16_t conn_handle)
    {
        uint32_t err_code;
        uint16_t sys_serv_attr_len = sizeof(m_peer_data.sys_serv_attr);
    
        err_code = sd_ble_gatts_sys_attr_get(conn_handle,
                                             m_peer_data.sys_serv_attr,
                                             &sys_serv_attr_len,
                                             BLE_GATTS_SYS_ATTR_FLAG_SYS_SRVCS);
          
        if (err_code != NRF_SUCCESS)
        {
            // Any error at this stage means the system service attributes could not be fetched.
            // This means the service changed indication cannot be sent in DFU mode, but connection
            // is still possible to establish.
        }
    
        m_reset_prepare();
        
        err_code = sd_power_gpregret_set(BOOTLOADER_DFU_START);
        APP_ERROR_CHECK(err_code);
    
        err_code = sd_softdevice_disable();
        APP_ERROR_CHECK(err_code);
    
        err_code = sd_softdevice_vector_table_base_set(NRF_UICR->BOOTLOADERADDR);
        APP_ERROR_CHECK(err_code);
    
        dfu_app_peer_data_set(conn_handle);
        NVIC_ClearPendingIRQ(SWI2_IRQn);
        interrupts_disable();
        
        bootloader_util_app_start(NRF_UICR->BOOTLOADERADDR);
    }

    The watchdog appears to timeout and the bootloader does start, but since it wasn't entered via the application (and setting GPREGRET = 0xB1), the DFU process doesn't start and a reconnection loop starts.

Reply
  • Hi Edvin,

    Thanks for the suggestion - I had been debugging the bootloader but through continued debugging with the desktop_keyboard bootloader I was able to see the DFU upload wasn't getting past the wait_for_events() function and more specifically the sd_app_evt_wait() function in bootloader.c. Doing further research into this issue I found an article that discussed the cause of this issue in SDK9 (https://www.programmerall.com/article/8197885958/).

    To summarize, I had the watchdog initialized in my application. By adding the watchdog feeding the DFU was not halted which was the cause of the continuous reset while in the bootloader. Now my custom application based on the desktop_keyboard project performs DFU the same was as the desktop_keyboard reference project. The challenge is still that the desktop_keyboard reference project does not perform DFU in the way I would like. As I explained previously, the desktop_keyboard reference initiates the DFU process from the application, then the device disconnects and advertises as DfuTarg. Then I can connect to DfuTarg and re-initiate the DFU process which completes successfully.

    The ble_app_hrs_s110_with_dfu_pca10028 example has a more desirable DFU process that doesn't require reconnecting, however, making the watchdog changes to this example bootloader didn't solve it for the custom application. Using the same custom application with the single_bank_ble_s110 bootloader and the watchdog feeding the DFU works the same as the desktop_keyboard example - not like the ble_app_hrs_s110_with_dfu_pca10028 example. When debugging the custom application it makes it to the bootloader_start() function, but halts before getting to bootloader_util_app_start(). When using the bootloader from the ble_app_hrs_s110_with_dfu_pca10028 bootloader (aka single_bank_ble_s110) I did implement a few changes in the application:

    • Added a reset_prepare() function (see below)
    • Added dfu_app_peer_data_set() call in bootloader_start() function

    static void reset_prepare(void)
    {
        uint32_t err_code;
    
        if (s_conn_handle != BLE_CONN_HANDLE_INVALID)
        {
            // Disconnect from peer.
            err_code = sd_ble_gap_disconnect(s_conn_handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
            APP_ERROR_CHECK(err_code);
        }
        else
        {
            // If not connected, the device will be advertising. Hence stop the advertising.
            advertising_stop();
        }
    
        err_code = ble_conn_params_stop();
        APP_ERROR_CHECK(err_code);
    
        nrf_delay_ms(500);
    }

    static void bootloader_start(uint16_t conn_handle)
    {
        uint32_t err_code;
        uint16_t sys_serv_attr_len = sizeof(m_peer_data.sys_serv_attr);
    
        err_code = sd_ble_gatts_sys_attr_get(conn_handle,
                                             m_peer_data.sys_serv_attr,
                                             &sys_serv_attr_len,
                                             BLE_GATTS_SYS_ATTR_FLAG_SYS_SRVCS);
          
        if (err_code != NRF_SUCCESS)
        {
            // Any error at this stage means the system service attributes could not be fetched.
            // This means the service changed indication cannot be sent in DFU mode, but connection
            // is still possible to establish.
        }
    
        m_reset_prepare();
        
        err_code = sd_power_gpregret_set(BOOTLOADER_DFU_START);
        APP_ERROR_CHECK(err_code);
    
        err_code = sd_softdevice_disable();
        APP_ERROR_CHECK(err_code);
    
        err_code = sd_softdevice_vector_table_base_set(NRF_UICR->BOOTLOADERADDR);
        APP_ERROR_CHECK(err_code);
    
        dfu_app_peer_data_set(conn_handle);
        NVIC_ClearPendingIRQ(SWI2_IRQn);
        interrupts_disable();
        
        bootloader_util_app_start(NRF_UICR->BOOTLOADERADDR);
    }

    The watchdog appears to timeout and the bootloader does start, but since it wasn't entered via the application (and setting GPREGRET = 0xB1), the DFU process doesn't start and a reconnection loop starts.

Children
  • If you are using a watchdog timer in your application, you must add that in the bootloader as well, if it isn't there already (the later SDKs does this automatically). So what is the reason that the DFU is not starting? Is it because GPREGRET != 0xB1? Have you tried setting it to 0xB1 from your application, then?

    I am sorry, but I struggle to see the difference between your bootloader and the one that you refer to as "ble_app_hrs_s110_with_dfu_pca10028 bootloader".

    Best regards,

    Edvin

Related