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

Nordic SDK boilerplate code size

I am still somewhat of a beginner to development with nRF51, but it seems to be that the SDK, specifically all the boilerplate code in the app_template example just to initialize the softdevice and so on generates almost 30 KB of code (using SDK v10, S110 and ARM's GCC 4.9.3 distribution with optimizing with -O3). It also consumes almost 2 KB of RAM already, leaving only 6 KB of RAM for the 16 KB RAM variant (xxaa I believe) of the chip.

Why is the boilerplate already so big? Were the older versions much smaller? This looks to me like one can only use the biggest 256 KB flash and 32 KB RAM variant with the current SDK.

Or are my GCC settings or something like that wrong?

Update: I checked the specific app_template code size. So when compiling the app_template in /nRF51_SDK_10.0.0/examples/ble_peripheral/ble_app_template/pca10028/s110/armgcc with gnu make and the makefile supplied by Nordic (i.e. I compile the exact app_template as it comes with the SDK distribution and with ARM GCC 4.9.3 installed on my system) I get the following output about the sizes (Nordic's makefile uses -O3):

  text    data     bss     dec     hex filename
  27120     112    1884   29116    71bc _build/nrf51422_xxac_s110.out

So we can clearly see that the "boilerplate", i.e. what I consider the least amount of setup code even without actually setting up the BLE services, but just calling ble_stack_init() and the other stuff from the app_template, you need 30 KB already.

Even when using -Os instead of -O3 it's still 20 KB, so 10 KB less, but still a lot:

text    data     bss     dec     hex filename
  17176     112    1876   19164    4adc _build/nrf51422_xxac_s110.out
  • (2/2)

    I'd never release app based on any of these templates but for newcomer or hobbyists it could be great starting point and help to shorten learning time. As I said once you know Soft Device API well it's quite easy to make BLE broadcaster (= beacon) app under 5kB with GCC compilation option -O3 (sometimes you can go even with -Os but I've seen still some unstable products so it could be risky for production if you don't have very good non-regression tests). As @monpetit said you can then go with Keil or IAR and get even better results (they are usually 5-20% better in code size optimization). Sure you are either limited by trial/evaluation license code size limit or time, but if you are doing this professionally and these things are key for your project you simply must pay for good tools, that's how business works;)

    Cheers Jan

  • I feel like this is going a bit off topic: My main question was why the Bluetooth app_template generates so much code. It is not surprising that you could have an app that does nothing interesting, especially not use Bluetooth, but that's not a very useful consideration for a Bluetooth SoC like nRF51. I am just wondering why the SoftDevice already eats up 96 KB - somewhat close to the 128 KB that the smaller variant has in flash and then I still need to do a lot of stuff in "my" app generating at least 20 KB of such code. So it's like you need 116 KB just for Bluetooth and setup.

    I also can't follow your argument that IAR and Keil generate more optimized code. This StackOverflow post suggests that this is a myth and that in reality a properly configured GCC comes very close.

  • You are right, let's stick to the topic and let the others research performance of different compilers (from my experience GCC for ARM did great job over past 2 years so I'm very happy with optimizations at -O3 and -Os levels). By looking into the main.c we get some answers:

    • It's using full device_manager module for storing and serving bonding&security (+ advertising and connection wrapper functions which are probably more convenient to use then calling SD calls directly).
    • It's using pstorage module which stores parts of the data/configuration persistently in flash (probably used by device manager but usually useful for business logic as well).
    • It's using BSP (board support package) including event dispatcher for LEDs and BUTTONs.
    • It's using app_timer package.

    If you then tweak makefile a little bit you can see sizes of all compiled modules as well as ELF dump (DMP) and LSS files. Together with MAP file you can see more details, such as GPIO/GPIOTE/UART functions and interrupt handlers being linked (not sure if these are ever used - UART might be for instance just left from app_trace and app_assert modules which helps in DEBUG mode to output some checkpoints into serial console). Here is one of such output examples for examples\ble_peripheral\ble_app_template project in discussion:

       text    data     bss     dec     hex filename
         92       0       0      92      5c _build/gcc_startup_nrf51.o
        972       6     529    1507     5e3 _build/main.o
        588       0      49     637     27d _build/app_button.o
         24       0       0      24      18 _build/app_error.o
       2392       0      29    2421     975 _build/app_timer.o
          0       0       0       0       0 _build/app_trace.o
          0       0       0       0       0 _build/nrf_assert.o
         48       0     208     256     100 _build/retarget.o
        372       0       7     379     17b _build/app_uart.o
         60       0       0      60      3c _build/nrf_delay.o
        128       0       0     128      80 _build/nrf_drv_common.o
       2732       0      72    2804     af4 _build/nrf_drv_gpiote.o
       1496       0      24    1520     5f0 _build/nrf_drv_uart.o
       5948       0     264    6212    1844 _build/pstorage.o
       3876       0     130    4006     fa6 _build/bsp.o
        368       0       8     376     178 _build/bsp_btn_ble.o
       3008       0       0    3008     bc0 _build/ble_advdata.o
       3024       2     284    3310     cee _build/ble_advertising.o
        696       0      80     776     308 _build/ble_conn_params.o
       1404       0       0    1404     57c _build/ble_srv_common.o
       6784       0     355    7139    1be3 _build/device_manager_peripheral.o
        172       4       0     176      b0 _build/system_nrf51.o
        480       0      19     499     1f3 _build/softdevice_handler.o
      34664      12    2058   36734    8f7e (TOTALS)
    
    Size of target .elf file:
    arm-none-eabi-size -B _build/ble_app_template_s110_pca10028.elf
       text    data     bss     dec     hex filename
      27432     112    1888   29432    72f8 _build/ble_app_template_s110_pca10028.elf
    
    Size of target .bin file:
    arm-none-eabi-size -B --target=binary _build/ble_app_template_s110_pca10028.bin
       text    data     bss     dec     hex filename
          0   27544       0   27544    6b98 _build/ble_app_template_s110_pca10028.bin
    

    As I've written in previous exchange I believe that this is great template for fully equipped BLE Peripheral application if you want to move development fast. It's definitely good place to learn for newcomers. Also resulting size isn't end of the world (I assume usage of 256kB nRF51 variants), you have still good chance to put nice business logic there are even integrate OTA DFU functionality.

    If you think there is a lot of unnecessary overhead I totally agree with you. I'd not go with this template for product of my own company, every skilled embedded (C) programmer can do better then this. However these SDK modules are written as generic to serve majority of use cases and they are tested and proven to work well. So maybe some of them might be good choice for your app in the end (you might be able to write something 10-20% more efficient in terms of code and RAM size but it's question if 1-2 weeks of your life are worth of these few hundreds of bytes). Optimized code for your particular use case (working directly on top of HW peripherals) will be of course always smaller and even device manager might be exchanged with your smaller manager of LE Security layer (especially if you are not using it or you have limited number of bonds&keys by design).

    This answer is just opinion of regular nRF51 SDK user, I hope that someone from Nordic team will give you better explanation of what this particular template project is targeting.

    Cheers Jan

  • I don't have much to add to Jan's excellent answer above. The generic template has grown in size over the releases of the SDKs, it used to be very small, but it didn't do very much, it advertised and had a hook for you to write a service handler, that was about it.

    That template now has everything you need to advertise, on a fast/slow/intermittent basis, connect, update connection parameters, perform bonding, store all the resulting keys for you and bring them back on reconnection with a bonded peripheral. It outputs debug information over the UART and has full support for the board including debounced button presses, blinking LEDs and some standard LED patterns for recognising errors. In fact the only thing it doesn't have is an actual service!

    The bonding/pairing stuff alone is big, because it's generically very complicated, that's 13kB of that image (including the pstorage module which it uses for persistence which you need for storing the keys). Nordic provides this very generic device management module which covers most of the use cases for bonding because, I think, many people either aren't able to write it themselves or just want a drop-in module which they can use to 'add bonding'. Can you do better? Of course you can if you don't need a generic bonding manager and have a simpler use-case, the code can be much smaller.

    Yes the reason that GPIOTE and UART code is linked is for the board support, the GPIOTE is for buttons (along with the timer module) and the UART code is for debugging, the fact that the IRQ handler is defined is enough to get a lot of the code linked even if it's never called, the compiler cannot know an interrupt handler is never called, so it has to put it in.

    If you want to see something smaller, try the beacon example, I think that's 12kB, and that also still has the board support package in it.

    I think you should look at that application template as an 'everything including the kitchen sink' template which you start with and then remove and comment out loads of things you don't need, or don't need a generic version of.

    Last point on the softdevice sizes. Yes they're not small, but that's the whole BTLE stack, and BTLE is getting fatter too with each revision of the spec. My feeling is that the release of the XXAC a couple of years ago and the nRF52 this year, was a recognition that 128k+16k was getting a bit skinny for the kind of BTLE devices people wanted to build. That said, if you have a simple peripheral it's easy to junk much of the boiler plate code and fit it on the smaller chips, even with the increased size of the S130 softdevice. That at least now has very configurable memory profiles to release more of the limited RAM when you're using the smaller chips.

  • One more note to the RAM size: latest Soft Device S130 V2 needs bellow 8kB for full-throughput peripheral role (actually less then 7,200B if you go without security layer) and if 8kB isn't enough for your app you then need to go with nRF51 XXAC chip variant. 32kB of RAM is max for ARM Cortex-M0 design so if you need even more then invest into nRF52 (which is anyway recommended because price difference is small and you can save some external components + have longer support and better power efficiency for most of the applications).

Related