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

nRF51822 over the air bootloader with gcc

For my current project, I need to compile the »over the air bootloader« with gcc (because our buildserver runs on linux, developers using Mac … no Windows and no Keil so far).

But unfortunaly, the bootloader example from the sdk (5.1) examples won't compile with gcc. It's missing gcc makefile and even there are at least 2 Keil specific files in the project (arm_startup_nrf51.s and bootloader_util_arm.c).

Could you provide support to help me on this topic?

I'd also checked:- devzone.nordicsemi.com/index.php/nrf51822-bootloader-with-gcc

  • I'm in a similar situation and very interested in that thread. What about a little more officially gcc support for the sdk examples in general?

  • Ok, after staying without any response for a week, I do it myself.

    My development & testing environment

    • Linux Host (Kubuntu 12.04, 32 Bit)
    • Nordic nRF51 Sdk version 5.1.0
    • SoftDevice S110 version 6.0.0
    • nRFgo starterkit (nRF6700 motherboard)
    • nRFgo nRF51822 cpu board (PCA10004, Rev. 2.2.0)
    • Segger JLink lite
    • Arm gcc 4.8 (gcc-arm-none-eabi-4_8-2013q4-20131204)
    • Also using Ole Morten's pure-gcc setup
    • For testing ota update, I use »nRF Mcp« and »nRF Toolkit« on an Android 4.3 tablet (Samsung Note SM-P605) and also »nRF Loader« on an iPhone 4s This refers to the bootloader example from the Nordic Sdk. Makefiles and all other changes are in the attached archive. Within my tests using the pure-gcc setup, the bootloader works well. But using the Sdk's gcc setup, I'll often got a hardfault. → Update: After modifying the assemblercode in bootloader_util (added .ALIGN) it seems also to work.

    Build using Ole Morten's pure-gcc setup For pure-gcc, just enter into directory pure-gcc and call »make« or »make flash«. You may have to adjust the path settings for your gcc installation et cetera:- SDK_PATH

    • TEMPLATE_PATH
    • TOOLCHAIN_PATH You can either edit pure-gcc/Makefile or pass them when calling make (e.g. »make SDK_PATH=…«).

    Build using the Sdk's gcc setup

    For using the Sdk's original gcc setup, you have to set the make variables:- SDK_PATH

    • GNU_INSTALL_ROOT
    • GNU_VERSION Because of the Sdk lack regarding linux host support (no Makefile.posix) and the unflattering definition of that variable in Makefile.windows (it's not defined using ?=), GNU_INSTALL_ROOT could not be set in the project's Makefile but must e.g. passed as a parameter when calling make (or you're going to modify the Sdk's makefiles), e.g.: $ make release GNU_INSTALL_ROOT=…

    Linkerscripts

    When compiling with armcc, the bootloader seems to need something about 14k flash (13k code and 1k for persistent data). With gcc, we need more space for code (about 15k when using gcc 4.8; gcc 4.7 needs a bit more). Within the linkerscripts, I'd set the flash size for the bootloader from 14k to 24k (but it can be reduced to 16k). Take note, that the UICR must be correctly set up to match the bootloaders flash address, which is 3C800 for the 14k bootloader but 3A000 for the 24k sized:

    J-Link>mem 10001014 4
    10001014 = 00 A0 03 00
    
    

    The »gcc_nrf51_s110_bootloader.ld« ist for the »pure-gcc« setup and the »gcc_nrf51_s110_xxaa_bootloader.ld« is for the sdk gcc. Yep, the naming could be better and maybe both files could put into one.

    In »dfu_types.h«, the bootloader's flash address must be adjusted to match the value in the linkerscript:

    #define BOOTLOADER_REGION_START         0x0003A000
    
    

    bootloader_util

    I'd made a bootloader_util_gcc.c as a substitute for bootloader_util_arm.c But see also this post

    Bootloader's persistent config in flash

    The bootloader saves some persistent data into the most upper flash page (1k at address 3FC00) and uses 16 byte (from the 1k) for storing informations e.g. about the application.

    J-Link>mem 3FC00 10
    0003FC00= 01 00 00 00 32 43 00 00 FF 00 00 00 E4 3D 00 00
    
    

    The regarding data structure is found in »bootloader_types.h« and named »bootloader_settings_t«. There is a problem with the »enum bootloader_bank_code_t« because the size of this enum is 32 bit in armcc but 16 bit in gcc. I'd modified that slightly so that it is also 32 bit for gcc.

    Bootloader's Codesize

    Using Ole Morten's pure-gcc setup:

    arm-none-eabi-size _build/Blebl_s110.elf
       text   data    bss    dec    hex filename
      14248   1108   2096  17452   442c _build/Blebl_s110.elf
    → 15.356 byte flash size (plus 1k persistent config)
    
    

    Using the Sdk's gcc setup:

    arm-none-eabi-size _build/BleblSdk.out
       text   data    bss    dec    hex filename
      14200   1108   2096  17404   43fc _build/BleblSdk.out
    → 15.308 byte flash size (plus 1k persistent config)
    
    

    Edit: Using Sdk 5.2.0, the codesize has grown a bit (about 604 byte).

    arm-none-eabi-size _build/Blebl_s110.elf
       text   data    bss    dec    hex filename
      14880   1100   2076  18056   4688 _build/Blebl_s110.elf
    → 15.960 byte flash size (plus 1k persistent config)
    
    

    But when using NewLib-nano (by specifying »LDFLAGS = --specs=nano.specs« in your Makefile), the code size can be reduced by 1.804 byte:

    arm-none-eabi-size _build/Blebl_s110.elf
       text   data    bss    dec    hex filename
      14052    124   2076  16252   3f7c _build/Blebl_s110.elf
    → 14.176 byte flash size (plus 1k persistent config)
    
    

    Edit: When using gcc link time optimization (-flto), the codesize again shrinks significantly (by about 3k):

    arm-none-eabi-size _build/Blebl_s110.elf
       text   data    bss    dec    hex filename
      11056    124   2048  13228   33ac _build/Blebl_s110.elf
    → 11.180 byte flash size (plus 1k persistent config)
    
    

    Feedback is welcome. @Nordic: Feel free to use that work in further sdk versions.

    Edit 2015-04-20: Don't know why the devzone lost the attachments such often. Here is BleblGcc-V3.zip again. Please note, that this work is done for Softdevice 6.0.0 and actually not ported to SoftDevice 7 and 8.

  • I also made some BLE DFU OTA code for gcc just today and I made this changes to nrf6310\device_firmware_updates\bootloader project:

    1. Linker scripts:

    1.1. gcc_nrf51_common.ld

    Add sections:

    SECTIONS
    {
        .bootloader_settings_block 0x0003FC00 :
        {
            KEEP(*(.bootloader_settings_sect))
        } > bootloader_settings
      
        .NRF_UICR_BOOT_START_BLOCK 0x10001014 :
        {
            KEEP(*(.NRF_UICR_BOOT_START_SECT))
        } > NRF_UICR_BOOT_START
    ...
    }
    

    1.2. gcc_nrf51_s110_xxaa.ld

    MEMORY
    {
      FLASH (rx) : ORIGIN = 0x3C000, LENGTH = 0x3C00 /* bootloader */
      bootloader_settings (rwx) : ORIGIN = 0x3FC00, LENGTH = 0x400 /* bootloader specific settings */
      NRF_UICR_BOOT_START (rwx) : ORIGIN = 0x10001014, LENGTH = 0x4 /* bootloader start address in UICR register */
      RAM (rwx) : ORIGIN = 0x20002000, LENGTH = 0x2000 /* 8 kB, 8 kB is taken by S110. */
    }
    
    1. bootloader_util_arm.c

       uint8_t __attribute__((section (".bootloader_settings_sect"))) m_boot_settings[CODE_PAGE_SIZE] __attribute__((used));
       uint32_t __attribute__((section (".NRF_UICR_BOOT_START_SECT"))) m_uicr_bootloader_start_address = BOOTLOADER_REGION_START;
      
      
       inline void StartApplication(uint32_t start_addr)
       {
           asm volatile("LDR   R2, [R0]               \n\t" // Get App MSP.
                        "MSR   MSP, R2                \n\t" //Set the main stack pointer to the applications MSP.
                        "LDR   R3, [R0, #0x00000004]  \n\t" //Get application reset vector address.
                        "BX    R3                     \n\t" //No return - stack code is now activated only through SVC and plain interrupts.
                        ".ALIGN"
                       );
       }
      
    2. dfu_types.h

       #define BOOTLOADER_REGION_START         0x0003C000
      
    3. pstorage_platform.h I had error from some check in pstorage, so I had to change PSTORAGE_MIN_BLOCK_SIZE value from 0x0010 to 0x000C:

       #define PSTORAGE_MIN_BLOCK_SIZE     0x000C
      

    UPD: But I think additional padding word for bootloader_settings_t is better solution for PSTORAGE_MIN_BLOCK_SIZE problem. UPD2: And with -Os optimization I have:

    'Invoking: Cross ARM GNU Print Size'
    arm-none-eabi-size  --format=berkeley "nRF51822_BLE_DFU.elf"
       text	   data	    bss	    dec	    hex	filename
      13988	   2128	   2096	  18212	   4724	nRF51822_BLE_DFU.elf
    'Finished building: nRF51822_BLE_DFU.siz'
    ' '
    

    Compiled with gcc version 4.8.3 20131129 (release) [ARM/embedded-4_8-branch revision 205641] (GNU Tools for ARM Embedded Processors).

    UPD3: I forgot that I deleted DFU start from button push and replaced it with NRF_POWER->GPREGRET check so code size was a bit smaller. With button usage:

    'Invoking: Cross ARM GNU Print Size'
    arm-none-eabi-size  --format=berkeley "nRF51822_BLE_DFU.elf"
       text	   data	    bss	    dec	    hex	filename
      14128	   2136	   2096	  18360	   47b8	nRF51822_BLE_DFU.elf
    'Finished building: nRF51822_BLE_DFU.siz'
    ' '
    

    UPD4: I attached eclipse project for bootloader.

    UPD 2014.06.26:

    I attached updated eclipse project for bootloader:

    C:\fakepath\Eclipse_workspace_2.rar

    Changes:

    • Added the function of simultaneous flashing bootloader and application via J-Link from this question: devzone.nordicsemi.com/.../

    • Added additional optimization as Joe Merten suggested: --specs=nano.specs -flto For -flto optimization you need to change your SDK files and add attribute ((used, section(".Vectors"))) to the IRQ handlers (GPIOTE_IRQHandler, RTC1_IRQHandler, SWI0_IRQHandler, SWI2_IRQHandler) like this:

       void __attribute__ ((used, section(".Vectors"))) GPIOTE_IRQHandler(void)
       {
       ...
       }
      

    in files:

    app_common/app_gpiote.c
    app_timer/app_gpiote.c
    sd_common/softdevice_handler.c
    

    To tim, I don't use makefile, but you can find makefile autogenerated by Eclipse in attached Eclipse_workspace_2.rar in this folder:

    nRF51822_BLE_DFU_flashing_with_app\Debug

    But if you want to use pure Makefile project then I would suggest you use the Joe Merten's project.

  • Very thanx for your reply. Yes, I forgot to describe dfu_types.h / BOOTLOADER_REGION_START in my post. And I'd also reworked about ".ALIGN". Are you using the makefiles & startup code from the sdk or from https://github.com/hlnd ? Are you developing on a Linux, OSX or Windows machine?

  • I attached eclipse project for bootloader. I work in Windows and use the makefiles & startup code from the sdk.

Related