Introduction
Here are some tips and tricks to manage your application size.
RAM and ROM usage
The total RAM usage is:
ZI-data + RW-data
The total flash usage is:
Code + RO-data + RW-data
-
ZI-data - Zero initialized data, data variables set to 0
-
RW-data - Data variables that are different from 0
-
RO-data - Constants placed in flash
This means that if you have a variable defined globally with the const flag it will most likely end up in flash, while a variable that is prone to change will end up either in RW-data or ZI-data.
These values should be listed when you compile your project (atleast in Keil, use 'arm-none-eabi-size myapplication.out' for GCC) or located in the .map file generated by the compiler/linker.
Why is RW-data listed in RAM and code? This is because this section holds the non-zero initialized values. for instance:
static int g_test = 0xFF1234FF;
This will consume 4 bytes of RAM, and 4 bytes of flash to store it's initial value (0xFF1234FF).
More details about RAM usage:
The total RAM consumption also holds the application stack for auto-variables, which variables inside a scope, such as int func(){int a; int b;}, where 'a' and 'b' here are auto-variables. The default stack_size set in your arm_startup.s file is set to 2048 bytes.
If the stack grows outside it's area (2048 bytes in this case), meaning that your auto-variables in scope is greater than the stack_size set, you will run into a stack overflow. if you google "stack usage monitoring" or similar you'll find methods for evaluating the stack usage for a given application. Note that the overall stack usage must be evaluated run-time, with the application running in all corner-cases.
Monitoring usage using Keil
Keil will put a .map file in the _build folder as long as the "Linker listing" options are on on the "Listing" tab of the target options.
The file arm_startup_nrf51.s contains the definitions of the heap and the stack, each being 2 kB by default, and this is therefore the reason it shows up with 4 kB in your map file. If you know that you don't use 2 kB of heap, feel free to reduce the heap size. The memory usage of S110 itself is given in the Softdevice Specification (1.5 kB of stack, no heap), and no heap is used by the SDK.
Some of the initalization macros used in main.c contains a static buffer for data storage. This applies for for example BLE_STACK_INIT, APP_TIMER_INIT, APP_BUTTON_INIT and friends, and this is most likely the cause of the 972 bytes used in main. You can for example take a look at the timer queue size, as explained here and the maximum number of timers, since this is usually a big part of the main memory.
Apart from this, your map file should contain a listing of the symbols defined in main, and how much memory each consumes, like this:
.bss 0x200020f0 Section 776 main.o(.bss)
APP_TIMER_BUF 0x200020f0 Data 576 main.o(.bss)
EVT_BUFFER 0x20002330 Data 80 main.o(.bss)
app_gpiote_buf 0x20002380 Data 20 main.o(.bss)
m_tps 0x20002394 Data 10 main.o(.bss)
m_ias 0x200023a0 Data 16 main.o(.bss)
m_lls 0x200023b0 Data 20 main.o(.bss)
m_bas 0x200023c4 Data 24 main.o(.bss)
m_ias_c 0x200023dc Data 12 main.o(.bss)
m_battery_sim_cfg 0x200023e8 Data 16 main.o(.bss)
For this application, the timer buffer is the biggest consumer in main, with the event buffer for the softdevice being second. Also the app_gpiote structure consumes a bit, as well as the different services.
Reducing usage
MicroLIB is a library that is made for ARM-based embedded platforms, it uses less memory than the normal C library, see this page from ARM for more information. Enabling MicroLIB will remove the HEAP, giving you >4kB for your application. To enable MicroLIB in Keil, check the box "Use MicroLIB" as shown below.
SEGGERs Real Time Terminal that was introduced in this tutorial has a heavy strain on RAM. If you find yourself short on RAM you can try configuring the up and down buffers and their sizes. These are the default settings(found in SEGGER_RTT_Conf.h):
#define SEGGER_RTT_MAX_NUM_UP_BUFFERS (2) // Max. number of up-buffers (T->H) available on this target (Default: 2)
#define SEGGER_RTT_MAX_NUM_DOWN_BUFFERS (2) // Max. number of down-buffers (H->T) available on this target (Default: 2)
#define BUFFER_SIZE_UP (1024) // Size of the buffer for terminal output of target, up to host (Default: 1k)
#define BUFFER_SIZE_DOWN (16) // Size of the buffer for terminal input to target from host (Usually keyboard input) (Default: 16)
#define SEGGER_RTT_PRINTF_BUFFER_SIZE (64) // Size of buffer for RTT printf to bulk-send chars via RTT (Default: 64)
Try reducing the number of up and down buffers as well as reducing their size to ensure that they don't use too much memory. If this does not work you will have to consider alternatives to RTT.
Another module that might easily consume some RAM is the bond manager. It needs to fit all bond information in RAM before writing to flash, so by reducing the max number of bonds you can store, you can reduce its RAM consumption.
Resource requirements
As a rule of thumb 0x1000 in hex corresponds to 4kB of RAM. For the nRF51 series there are two available RAM sizes(16 kB and 32 kB) and two available flash sizes(128 kB and 256 kB), to see which combination of the two you have, please see the compatibility matrix. For the nRF52 there is one size available(64kB RAM 512 kB flash).
RAM
-
16 kB - Corresponds to 0x4000
-
32 kB - Corresponds to 0x8000
-
64 kB - Corresponds to 0x10000
Flash
-
128 kB - Corresponds to 0x20000
-
256 kB - Corresponds to 0x40000
-
512 kB - Corresponds to 0x80000
The call stack is by default set to 2K, which is shared between the softdevice and the application. As an example S110 v.7.0.1 uses a maximum of 1536 bytes of the stack. You can modify arm_startup_nrf51.s if you wish to change stack or heap size(Note that MicroLIB will remove the heap entirely).
Heap memory can safely be set to zero as long as you don't use dynamic memory allocation (malloc/free). Note that heap is generally not used in our SDK examples.
Common IRAM and IROM settings
Here is an example of how to calculate the IRAM and IROM settings for a QFAA-chip(256kB Flash and 16kB RAM) with version 1.0 of the S130 SoftDevice:
According to section 13 of the SoftDevice Specification for S130 the IRAM base should be a minimum of 0x200022D8, and might be larger depending on the requirements of your application. Use the default 0x20002800.
The IRAM size consumption is dependent on the attribute table size(see section 13.1 of the SDS) with the default value of 0x600 bytes you would end up having an IRAM size of 0x4000 - 0x2800 = 0x1800.
The IROM base should be 0x0001C000 which is the same as 0x1C000. The size should be 0x40000 - 0x1C000 = 0x24000.
Finally here are some common values for different combinations of SoftDevices and chips.
S110 v8.0 from SDS v2.0
-
IRAM base - 0x20002000
-
IRAM size(16 kB RAM) - 0x2000
-
IRAM size(32 kB RAM) - 0x6000
-
IROM base - 0x18000
-
IROM size(128 kB Flash) - 0x8000
-
IROM size(256 kB Flash) - 0x28000
S120 v2.1 from SDS v2.1
-
IRAM base - 0x20002800
-
IRAM size(16 kB RAM) - 0x1800
-
IRAM size(32 kB RAM) - 0x5800
-
IROM base - 0x1D000
-
IROM size(128 kB Flash) - 0x3000
-
IROM size(256 kB Flash) - 0x23000
S130 v1.0 from SDS v1.0
-
IRAM base - 0x20002800
-
IRAM size(16 kB RAM) - 0x1800
-
IRAM size(32 kB RAM) - 0x5800
-
IROM base - 0x1C000
-
IROM size(128 kB Flash) - 0x4000
-
IROM size(256 kB Flash) - 0x24000
S130 v2.0 from SDS v2.0
-
IRAM base - 0x20001870
-
IRAM size(16 kB RAM) - 0x2790
-
IRAM size(32 kB RAM) - 0x6790
-
IROM base - 0x1B000
-
IROM size(128 kB Flash) - 0x5000
-
IROM size(256 kB Flash) - 0x25000
S210 v5.0 from SDS v3.0
-
IRAM base - 0x20000900
-
IRAM size(16 kB RAM) - 0x3700
-
IRAM size(32 kB RAM) - 0x7700
-
IROM base - 0xD000
-
IROM size(128 kB Flash) - 0x13000
-
IROM size(256 kB Flash) - 0x33000
S310 v3.0 from SDS v3.0
-
IRAM base - 0x20002200
-
IRAM size(16 kB RAM) - 0x1E00
-
IRAM size(32 kB RAM) - 0x5E00
-
IROM base - 0x1D000
-
IROM size(128 kB Flash) - 0x3000
-
IROM size(256 kB Flash) - 0x23000
S132 v0.9 from SDS v0.5
-
IRAM base - 0x20002800
-
IRAM size(64 kB RAM) - 0xD800
-
IROM base - 0x1C000
-
IROM size(512 kB Flash) - 0x64000
S132 v2.0 from SDS v2.0
-
IRAM base - 0x20001870
-
IRAM size(64 kB RAM) - 0xE790
-
IROM base - 0x1C000
-
IROM size(512 kB Flash) - 0x64000
Final notes and further reading
Please leave any feedback, questions or comments below.
- https://devzone.nordicsemi.com/question/21787/available-ram-for-the-application/
- https://devzone.nordicsemi.com/question/30765/nrf_error_no_mem/?answer=31098#post-id-31098
- https://devzone.nordicsemi.com/question/12524/ram-usage-with-s110-support/
- https://devzone.nordicsemi.com/question/23059/how-to-monitor-flash-and-ram-usage-after-compilation/
- https://devzone.nordicsemi.com/question/1088/putting-my-app-on-a-ram-memory-diet/