This chapter discusses some important topics that are critical to use SDK efficiently.
There are mainly three type of memory management methods:
- Statically allocated global variables
- Dynamically allocated and freed on stack
- Manually allocated and freed on heap
RAM is shared between platform and user applications. When a new project is created by
ingWizard, RAM settings is configured properly. Developers are not suggested to modify these settings.
This is the recommended way to define variables that have a full lift span in the app. They are allocated in the fixed location and their content can be checked easily in debugger.
For variables that are only used within a limited scope, such as a function, we can allocated them on stack.
Cares must be taken that size of stack is limited, and it might overflow if too much memory is allocated.
app_mainfunction & interrupts serving routines shares the same global stack with platform’s
For RTOS bundles, this stack is defined in platform binaries as
1024bytes, and can be replaced by a user defined one with the help of
For “NoOS” bundles, this stack is defined in app binariy as usual.
Callback functions registered into Bluetooth stack shares the same task stack with the stack task, whose size is defined as
1024bytes, and about half is left to be used by app.
Developers can create new tasks by calling RTOS APIs. In these cases, stack size should be carefully examined.
Use tools to check required stack maximum depth of functions.
Generally, heap is not a recommended way for memory management in embedded applications. There are several cons included but not limited to:
Some bytes are wasted to store extra information and extra program.
It costs cycles to allocate and free memory blocks.
Based on these considerations, the heap used by
free has been totally disabled by setting
its size to
0. If such heap is TRULY required, it can be re-enabled by changing its size to a
proper value when creating projects.
Be sure to check follow alternatives before using
Use global variables
Use memory pool15
This is probably the choice for most cases.
FreeRTOS’s heap and memory functions,
Note that this heap is used by platform &
FreeRTOSitself, and it may not have too much free space left for apps. The standard
freecan be configured to be overridden and backed by
pvPortFreewhen setting up heap in
ingWizard. Once overridden, the allocator from libc is omitted, and
freeare implemented by
It is recommend to have a check on Mastering the FreeRTOS™ Real Time Kernel. Some tips:
Do not do too much processing in interrupt handlers, but defer it to tasks as soon as possible
Callback functions registered into Bluetooth stack are executed in the context of the stack task, so do not do too much processing in these functions either
To create traditional ISR for interrupts, apps only need to register callback functions through a platform
Apps can use following APIs to modify interrupts configuration and states:
Note that the highest allowed priority is
configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY + 2, i.e. that priority parameter must be larger than or equal to this value, indicating a lower or equal priority.
In most case, platform manages the power saving feature of ING918xx/ING9186xx SoC automatically and tries the minimize the power consumption in all circumstances, with only one exception, deep sleep.
In deep sleep, all components, except those required for power saving control and real-time clocks, are powered down. Some peripherals may be used by apps, and platform does not know how to configure them. So, apps have to get involved in the waking up process after deep sleep. Platform will also check with app if deep sleep is allowed, and fall back to less aggressive power saving modes when deep sleep is not allowed.
Besides the above automatic power management schema, apps can also shutdown the whole system
and reboot after a specified duration. In shutdown state the whole system has the least
power consumption. See
In shutdown state, a portion of data can
be kept optionally at the cost of a little more power consumption.
In case of only a little piece of data needs to be kept, for example no more than
four bits, SDK
provides a pair of APIs for this,
SDK tries to encapsulate CMSIS APIs to ease the development. Be careful when calling these APIs in apps as it may affect the platform program.
Following operations are strictly forbidden:
- Changing the vector table offset register
- Modify configurations of internal interrupts, i.e. those not listed in Table 6.1.
Besides online debugging, SDK provides two methods to assist debugging.
printfis the most convenient way to check program’s behaviour.
ingWizardcan generate necessary code to use
Internal state & HCI messages can be recorded through this trace machenism.
ingWizardcan generate necessary code to use trace, too. There are several types of trace data, which are predefined and can’t be changed. Which types of trace data are going to be recorded is programmable. Use
ingTracer to view the recorded trace data.
|Trace||Binary data, fast||Data types are predefined|
|UART||Universal, easy to use||Slower, consume more CPU cycles|
|SEGGER RTT||Fast||J-Link is required, hard to capture power up log|
J-LINK RTT Viewerto view
printfoutputs in real-time.
J-LINK RTT Loggerto record trace outputs to files.
This logger will ask for the settings of RTT. Device name is “CORTEX-M3”. Target interface is “SWD”. RTT Control Block address is the address of a variable named
_SEGGER_RTT, which can be found in
.mapfile. RTT channel index is
0. Blow is a sample session.
------------------------------------------------------------ Device name. Default: CORTEX-M3 > Target interface. > SWD Interface speed [kHz]. Default: 4000 kHz > RTT Control Block address. Default: auto-detection > 0x2000xxxx RTT Channel name or index. Default: channel 1 > 0 Output file. Default: RTT_<ChannelName>_<Time>.log > ------------------------------------------------------------ Connected to: J-Link ... S/N: ... Searching for RTT Control Block...OK. 1 up-channels found. RTT Channel description: Index: 0 Name: Terminal Size: 500 bytes. Output file: .....log Getting RTT data from target. Press any key to quit.
Alternativaly, this tool can be called from command line. Address of
_SEGGER_RTTcan be specified by a range, and the tool will search for it automatically. For examples,
JLinkRTTLogger.exe -If SWD -Device CORTEX-M3 -Speed 4000 -RTTSearchRanges "0x20005000 0x8000" -RTTChannel 0 file_name
We are committed to delivery high quality platform binary. If an assertion had occurred in platform binary, it is suggested to create a full memory dump and save all registers, then contact for further support. There are two memory regions (Table 5.3).
|Region||Start Address||Size (Bytes)|
|#1||0x20000000||0x10000 (for 128kB RAM chip series)|
|0x08000 (for 64kB RAM chip series)|
|#2||0x400A0000||0x10000 (for 128kB RAM chip series)|
|0x08000 (for 64kB RAM chip series)|
Memory can be dumped through debuggers:
In debug session, open the Command Window, use
saveto save each memory region. For example:
save sysm.hex 0x20000000,0x2000FFFF save share.hex 0x400A0000,0x400AFFFF
Once connected, use
regsto shows all current register values, and
savebinto save target memory into binary file. For example:
savebin sysm.bin 0x20000000 0x10000 savebin share.bin 0x400A0000 0x10000
IAR Embedded Workbench
In debug session, open a Memory window, and select “Memory Save …” from popup menu.
Rowley Crossworks for ARM & SEGGER Embedded Studio for ARM
In debug session, open a Memory window, for each memory region:
- Fill in the start address and size;
- Use “Memory Save …” from popup menu.
GDB (GNU Arm Embedded Toolchain and Nim)
In GDB debug session, use
dumpcommand to save each memory region.
Memory can be also dumped by a piece of specific code. For example, in the event handler of
PLATFORM_CB_EVT_ASSERTION, dump all memory data to UART.
btstack_push_user_runnable. See Thread Safety in Developer’s Guide for Bluetooth LE.↩︎