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" */