1. About this document
1.1. Purpose
This document describes to an application developer how to integrate the STM32WBAxx Bluetooth® LE stack library.
1.2. Scope
This document covers only the Bluetooth® LE stack library integration, and it does not include the Link Layer integration aspects.
1.3. Acronym definitions
Acronym definitions | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
|
1.4. References
- STM32WBA_BLE_Wireless_Interface.html
- RM0493 - Reference Manual - Multiprotocol wireless Bluetooth® Low-Energy and IEEE802.15.4, STM32WBA5xxx Arm®-based 32-bit MCUs
- PM0271 - Programming manual - Guidelines for Bluetooth® Low Energy stack programming on STM32WB/STM32WBA MCUs
2. BLE Stack Overview
2.1. Release contents
2.1.1. Folder structure
The BLE stack delivery contains 3 folders as follows:
BLE stack folder structure |
---|
- “doc” folder contains the current document and STM32WBA_BLE_Wireless_Interface.html which describes the BLE Application Commands Interface (ACI) and the Host Commands Interface (HCI).
- “include” folder contains the header files of the BLE stack library interface. These files contain some definitions of constants and types and the declarations of ACI and HCI functions. It also contains the declarations of some external modules functions used by the BLE stack. For more details, see section 4.2.
- “lib” folder contains the 6 BLE stack library variants described in the following section.
2.1.2. Library variants
The BLE stack library is delivered in 6 variants as follows:
The BLE stack library is delivered in 6 variants as follows:
- 4 variants containing the BLE Host Stack:
- Full Stack (stm32wba_ble_stack_full.a)
- Basic Plus Stack (stm32wba_ble_stack_basic_plus.a)
- Basic Stack (stm32wba_ble_stack_basic.a)
- Peripheral Only stack (stm32wba_ble_stack_po.a)
- 2 variants without the BLE Host Stack (they only contain the LE Controller):
- Link Layer Only Stack (stm32wba_ble_stack_llo.a)
- Link Layer Only Basic Stack (stm32wba_ble_stack_llobasic.a)
BLE stack variants |
---|
Here are the 6 BLE stack variants details:
- Full Stack (stm32wba_ble_stack_full.a) includes the LE Controller and the Host Stack, both with all the supported features. It contains all the legacy stack supported features plus the advertising extensions, GATT caching, Enhanced ATT, ACI HCI flow control, isochronous support for audio, L2CAP connection oriented channels.
See the parameter “options” of the initialization structure BleStack_init_t parameters in section 3.1 to enable/disable the controller only mode.
Please refer to PM0271 to know which command is available if controller only mode is enabled or not.
- Basic Plus Stack (stm32wba_ble_stack_basic_plus.a) includes the LE Controller and the Host Stack, both with the basic features along with additional features as Extended Advertising/Scanning, LE Power Control and Connection Subrating, Enhanced ATT, L2CAP connection oriented channels and GATT caching features.
- Basic Stack (stm32wba_ble_stack_basic.a) includes the LE Controller and the Host Stack, both with the basic features. It contains only BLE legacy features without extended advertising, neither GATT caching, nor Enhanced ATT, nor ACI HCI flow control, nor isochronous support, nor L2CAP connection oriented channels. The Host Stack is included, and it supports all the basic GATT, GAP and L2CAP features.
- Peripheral Only stack (stm32wba_ble_stack_po.a) includes only the LE Controller and the Host Stack, both with the basic features but only for peripheral role. The Host Stack is included, and it supports all the basic GATT, GAP and L2CAP features.
- Link Layer Only stack (stm32wba_ble_stack_llo.a) includes only the LE Controller with all the supported features. It contains all the features supported by the Full Stack but doesn’t include the Host Stack.
- Link Layer Only Basic Stack (stm32wba_ble_stack_llobasic.a) includes only the LE Controller with the basic features. It contains all the features supported by the Basic Stack but doesn’t include the Host Stack.
For more information, please refer to STM32WBA_BLE_Wireless_Interface.html to know which ACI and HCI command/event is supported by each stack configuration.
The table below details the supported features for each BLE stack variants:
Supported features of each BLE stack variants Updated (footprint) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
(1): These values were computed with STM32CubeWBA Firmware Package v1.6.0 using Keil® environment.
(2): It might be limited to 8 or 20 links depending on the Link Layer library used. (LinkLayer_BLE_Basic_20_links_lib for 20 links).
(3): In addition to the BLE Stack library RAM, the BLE Stack requires RAM memory from the application (see section 3.1)
2.2. Real-Time environment
The BLE stack library is independent from the real-time software environment as well as any real-time resource.
The functions of this library used during run time are:
- The BLE stack commands (HCI, ACI...),
- The BLE stack process,
- The BLE stack callback functions called by the link layer or the platform software (PKA, Timer...).
Note that these BLE stack functions are not reentrant. It is therefore recommended to prevent any reentrancy by construction. The wrapper described in the “BLE stack wrapper” section can help with this for the BLE stack commands. A straightforward approach would be to call all these functions from the same context of execution, i.e., from the same task when using a real-time operating system or from the main loop in a bare metal environment.
2.3. Library dependencies
The BLE stack library depends on (that is, must be linked with the following libraries):
- STM32WBAxx Link Layer libraries (refer to table BLE stack variants in section 2.1.2 for Link Layer library configuration dependency).
- Standard C library:
- Only basic memory functions are used (memcpy, memset, memmove, memcmp).
2.4. Library compilation options
The BLE stack library is compiled with the following options in Keil® environment:
- General options:
- Byte order: Little-endian
- FPU: VFPv5 single precision
- C/C++ Compilation options
- Compilation options:
- --library_interface=aeabi_clib: Used to generate AEABI-compliant object code
- --mno-unaligned-access: Used to enforce aligned memory access
- Plain 'char' is unsigned.
- Compilation options:
As mentioned above, the BLE stack library is AEABI compliant; The advantage of adhering to AEABI is that the BLE stack library can be linked with any other AEABI-compliant module, even modules produced by tools provided by other vendors than Keil®.
For the enum type, the Keil® C/C++ compiler will use the smallest type required to hold enum constants (-fshort-enums), preferring signed rather than unsigned.
2.5. Application compilation options
These compilation options are compulsory:
- Plain 'char' is unsigned
- Short enum:
- For IAR® compiler, this option is set by default
- Keil µvision® environment with ARM® CC compiler, the following option shall be added: -fshort-enums
In CubeIDE environment with GCC compiler, there is no need to add specific compiler options or linker options.
3. BLE Stack User Interface
In order to use the main functions of the BLE stack library, the user application code needs to include “blestack.h”.
In addition, to be able to directly call BLE commands (see section 3.3.2), the application needs to also include “blecore.h”.
3.1. BLE stack initialization
|
BleStack_Init: The BLE stack initialization routine. This function is used to define the memory and configure the BLE stack.
All BleStack_Init parameters are described below:
BleStack_Init function's parameters | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
The BLE Host Stack RAM memory must be allocated by the application. This RAM memory is composed of:
- the BLE stack and ACL buffers RAM (defined by the bleStartRamAddress and total_buffer_size parameters)
- the GATT database RAM (defined by the bleStartRamAddress_GATT and total_buffer_size_GATT parameters)
The size of this memory depends on several parameters, such as the maximum number of links, the maximum ATT MTU size, the maximum number of services, etc.
These RAM sizes can be computed using the BLE_TOTAL_BUFFER_SIZE and BLE_TOTAL_BUFFER_SIZE_GATT macros from ble_bufsize.h.
Here is an example of the RAM impact depending on the maximum number of connections, services and attributes.
RAM usages (Bytes) | |||
---|---|---|---|
Variant | Full & Basic Plus |
Basic | Peripheral only |
BLE Stack and ACL buffer RAM (*) (example config: 8 connections, ATT MTU set to 300, prep. write list size set to 30) |
9 996 | 9 164 | 8 684 |
RAM impact per connection (with ATT MTU set to 300) | 708 | 656 | 628 |
GATT database (example config: 8 services, 68 attributes, 1344 bytes allocated for attributes values) |
4 448 | 4 448 | 4 448 |
RAM impact per Service | 48 | 48 | 48 |
RAM impact per Attribute | 40 | 40 | 40 |
Total BLE Stack RAM (example config: 8 connections, ATT MTU set to 300, 8 services, 68 attributes, 1344 bytes allocated for attributes values) |
14 444 | 13 612 | 13 132 |
(*: This memory includes the memory required for the 8 connections)
Example:
BleStack_init_t pInitParams;
pInitParams.numAttrRecord = CFG_BLE_NUM_GATT_ATTRIBUTES;
pInitParams.numAttrServ = CFG_BLE_NUM_GATT_SERVICES;
pInitParams.attrValueArrSize = CFG_BLE_ATT_VALUE_ARRAY_SIZE;
pInitParams.prWriteListSize = CFG_BLE_ATTR_PREPARE_WRITE_VALUE_SIZE;
pInitParams.attMtu = CFG_BLE_MAX_ATT_MTU;
pInitParams.max_coc_nbr = CFG_BLE_MAX_COC_NUMBER;
pInitParams.max_coc_mps = CFG_BLE_MAX_COC_MPS;
pInitParams.max_coc_initiator_nbr = CFG_BLE_MAX_COC_INITIATOR_NBR;
pInitParams.numOfLinks = CFG_BLE_NUM_LINK;
pInitParams.mblockCount = CFG_BLE_MBLOCK_COUNT;
pInitParams.bleStartRamAddress = (uint8_t*)buffer;
pInitParams.total_buffer_size = BLE_DYN_ALLOC_SIZE;
pInitParams.bleStartRamAddress_GATT = (uint8_t*)gatt_buffer;
pInitParams.total_buffer_size_GATT = BLE_GATT_BUF_SIZE;
pInitParams.debug = 0x10; // static random address generation
pInitParams.options = 0x0000;
return_status = BleStack_Init(&pInitParams);
3.2. BLE stack process
The BleStack_Process function runs all Host stack layers’ dedicated processes.
BleStack_Process function | ||||||
---|---|---|---|---|---|---|
|
The BleStack_Process function shall be called in the following conditions:
- The Link Layer has been scheduled.
- An ACI/HCI command, ACL data or ISO data has been sent to the BLE stack (either by calling BleStack_Request or by direct call to a specific command).
- By the platform software at the timer expiry or the end of PKA activity.
- When the BleStack_Process function returns BLE_SLEEPMODE_RUNNING, it shall be re-called. If it returns BLE_SLEEPMODE_CPU_HALT, there is no need to call this function again and the MCU could go to sleep mode.
Example:
return_status = BleStack_Process();
if (return_status == BLE_SLEEPMODE_RUNNING)
// BleStack_Process shall be re-called again
else
// The MCU can go to sleep mode
3.3. BLE stack ACI/HCI interface
We have two ways to send commands and receive events in ST’s BLE Stack: Transparent Mode or Direct Mode.
3.3.1. Transparent Mode
To use BLE stack in Transparent Mode, a buffer that contains the ACI/HCI command or ACL data packet shall be passed as parameter to the function BleStack_Request.
The ACI/HCI command will be executed. The response event (command complete/ command status) is returned in the same buffer, and the size (in bytes) of the response event is given by the function’s return value.
BleStack_Request function | ||||||
---|---|---|---|---|---|---|
|
Example:
// It is recommended to initiate the buffer at maximum length that BLE stack supports.
uint8_t reset_cmd[255] = {0x01, 0x03, 0x0C, 0x00};
/* BLE stack will execute Reset command, the Command Complete Event will be returned in reset_cmd array,
the total length of event is returned in event_length. */
uint16_t event_length = BleStack_Request(reset_cmd);
// The response packet will be in BLE standard format.
uint8_t cmd_status = reset_cmd[6];
The ACI/HCI asynchronous events must be handled in the BLECB_Indication callback.
This function will be called by the BLE stack with the following parameters:
BLECB_Indication function | ||||||
---|---|---|---|---|---|---|
|
Example:
uint8_t BLECB_Indication(const uint8_t* data, uint16_t length,
const uint8_t* ext_data, uint16_t ext_length)
{
if (data[0] == HCI_LE_META_EVT_CODE)
{
// Check the subevent_code and the parameter length
if ((data[2] == HCI_LE_CONNECTION_COMPLETE_SUBEVT_CODE) && (data[1] == 0x13))
{
hci_le_connection_complete_event_rp0 *p_conn_complete;
p_conn_complete = (hci_le_connection_complete_event_rp0 *) (data + 3);
printf("Connection DONE - Connection handle: 0x%04X\n", p_conn_complete->Connection_Handle);
printf("Connection established with @:%02x:%02x:%02x:%02x:%02x:%02x\n",
p_conn_complete->Peer_Address[5],
p_conn_complete->Peer_Address[4],
p_conn_complete->Peer_Address[3],
p_conn_complete->Peer_Address[2],
p_conn_complete->Peer_Address[1],
p_conn_complete->Peer_Address[0]
);
printf("Connection parameters:\n- Connection Interval: %.2f ms\n- Connection latency: %d\n- Supervision Timeout: %d ms\n",
p_conn_complete->Conn_Interval * 1.25,
p_conn_complete->Conn_Latency,
p_conn_complete->Supervision_Timeout * 10
);
}
}
return 0;
}
3.3.2. Direct mode
The Direct Mode provides a dedicated API for each ACI/HCI command and event.
Instead of using BleStack_Request / BLECB_Indication like in transparent mode, the ACI/HCI commands/events can be used through the dedicated functions. Those functions are listed and detailed in the document STM32WBA_BLE_Wireless_Interface.html.
To use the direct mode, the BLE wrapper shall be compiled, that means “ble_wrap.c” needs to be included section 3.3.2.1.
3.3.2.1. BLE stack wrapper
The BLE stack includes a wrapper to execute user-defined pre and post processing for each BLE command.
The wrapper is implemented in the include/auto/ble_wrap.c file and defines each pre-processing and post-processing macro.
Each wrapper macro can be defined at the application level to execute dedicated code. By default all specific macros are defined to the generic macros : "BLE_WRAP_PREPROC" and "BLE_WRAP_POSTPROC".
The "BLE_WRAP_PREPROC" and "BLE_WRAP_POSTPROC" are empty macros; it is up to the user to redefine those macros to execute pre and post processing respectively for every command.
Wrapper implementation:
/* Generic BLE command pre-processing macro */
#ifndef BLE_WRAP_PREPROC
#define BLE_WRAP_PREPROC( )
#endif
/* Generic BLE command post-processing macro */
#ifndef BLE_WRAP_POSTPROC
#define BLE_WRAP_POSTPROC( )
#endif
/* HCI_DISCONNECT pre-processing macro */
#ifndef BLE_WRAP_HCI_DISCONNECT_PREPROC
#define BLE_WRAP_HCI_DISCONNECT_PREPROC BLE_WRAP_PREPROC
#endif
/* HCI_DISCONNECT post-processing macro */
#ifndef BLE_WRAP_HCI_DISCONNECT_POSTPROC
#define BLE_WRAP_HCI_DISCONNECT_POSTPROC BLE_WRAP_POSTPROC
#endif
…
/* HCI_DISCONNECT wrapper function */
tBleStatus hci_disconnect( uint16_t Connection_Handle,
uint8_t Reason )
{
BLE_WRAP_HCI_DISCONNECT_PREPROC( );
tBleStatus status = HCI_DISCONNECT( Connection_Handle,
Reason );
BLE_WRAP_HCI_DISCONNECT_POSTPROC( );
return status;
}
Application example:
/* User can define the specific macros to call their own functions */
/* HCI_DISCONNECT pre-processing macro */
#define BLE_WRAP_HCI_DISCONNECT_PREPROC user_disconnect_preproc()
/* HCI_DISCONNECT post-processing macro */
#define BLE_WRAP_HCI_DISCONNECT_POSTPROC user_disconnect_postproc()
[OR]
/* User can define the generic macros to call their own functions */
#define BLE_WRAP_PREPROC user_preproc()
#define BLE_WRAP_POSTPROC user_postproc()
3.3.2.2. Commands and data sending
Each ACI/HCI command has its own interface, e.g. the HCI Reset command can be called through the “hci_reset” interface.
The HCI commands functions can be found in include /auto/ble_hci_le.h file.
The ACI commands for GAP functions can be found in include /auto/ble_gap_le.h file.
The ACI commands for GATT functions can be found in include /auto/ble_gatt_le.h file.
The ACI commands for HAL functions can be found in include /auto/ble_hal_aci.h file.
The ACI commands for L2CAP functions can be found in include /auto/ble_l2cap_le.h file.
Also, it exists a way to use the ACI/HCI commands without using the BLE Wrapper. Those interfaces have the same name as the one listed before, but in uppercase: e.g. HCI Reset command is “HCI_RESET” instead of “hci_reset”.
Those functions can be found in include /auto/ble_raw_api.h file.
Example:
// Send HCI Reset command
tBleStatus reset_status = hci_reset();
// Send HCI Reset command without using the BLE Wrapper
tBleStatus reset_status = HCI_RESET();
// Send ACI GATT delete include service command
uint16_t Serv_Handle = 0x2456;
uint16_t Include_Handle = 0x8795;
tBleStatus gatt_status = aci_gatt_del_include_service(Serv_Handle, Include_Handle);
3.3.2.3. Asynchronous events and data reception
To handle ACI/HCI events in its application, the user can choose between two different methods:
1- “FIFO event handling”
Handle the ACI/HCI events through the BLE Wrapper callback functions (listed in include/auto/ble_events.h file).In the “BLECB_Indication” function, it is required to push the event data into a FIFO. Then, it is possible to call the “BLE_EventProcess” function each time an event is popped from the FIFO.The BLE_EventProcess” function calls the dedicated event callback. To handle the event, its dedicated callback needs to be redefined
(e.g., "hci_disconnection_complete_event” callback)
2- “Raw event handling”
Handle the ACI/HCI event directly when the BLE Stack raises it without using the BLE Wrapper. It requires to redefine the dedicated event callbacks (e.g.“HCI_DISCONNECTION_COMPLETE_EVENT” callback).If an event is handled in its dedicated callback, the event cannot be handled in the BLECB_Indication callback anymore. Note: No ACI/HCI command should be called from the Raw event callback.
Based on its own application scenario, the user should identify the required BLE events to be detected and handled and the application ‘s specific actions as a response to such events.
When implementing a BLE application, the most common and widely used BLE events are the ones related to the discovery, connection, terminate procedures, services and characteristics discovery procedures, attribute modified events on a GATT server and attribute notification/ indication events on a GATT client.
There is one callback per event. All callback functions can be found in include/auto/ble_events.h (for method 1) and include /auto/ble_raw_api.h (for method 2).
Example:
tBleStatus hci_disconnection_complete_event(uint8_t Status, uint16_t Connection_Handle, uint8_t Reason)
{
/* USER CODE BEGIN */
// What to do when the device is disconnected.
/* USER CODE END */
}
Known limitation: In “LL only” mode or when using Direct Mode for the event callback, the RAM containing the reported data doesn’t support unaligned access. In these cases, it is advised to use the ble_memcpy/ble_memset/ble_memcmp functions (declared in "mem_intf.h" from link layer libraries) instead of memcpy/memset/memcmp functions when accessing those data.
4. BLE Stack Porting
The BLE stack uses some generic HW features but lets the application define them by using HW drivers or emulating some of them by SW code.
All the porting interfaces required by the BLE stack are defined in the bleplat.h
The following features are used and need to be implemented on the application side:
- NVM: Non-Volatile Memory used by the security database of the BLE stack.(required only for variants including the Host Stack)
- Timer: used by several components of the BLE stack.(required only for variants including the Host Stack)
- AES: Advanced Encryption Standard used by the security manager layer of the BLE stack.
- PKA: Public Key Accelerator used by the controller in the BLE stack.
- RNG: Random Number Generation used by the controller in the BLE stack.
4.1. BLE platform initialization
BLEPLAT_Init function | ||||||
---|---|---|---|---|---|---|
|
This function is called by the BLE stack when it is initialized or reset (via hci_reset). The user shall call here the functions to reset the Timer, AES, PKA, NVM and RNG needed for the BLE stack.
The user must implement the functions mentioned below that are called by the BLE stack at runtime.
4.2. BLE platform functions
All the BLEPLAT functions are called from the BLE stack process or commands. Those functions shall return one of the following status values:
BLEPLAT functions' returns | |||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
4.2.1. NVM functions
The NVM functions are used to store security database information (security and GATT records) in the NVM, read from the NVM, compare data with the stored data in the NVM and clear the security database or some of it.
BLEPLAT NVM functions | |||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
4.2.2. Timer functions
The timer functions are used by the BLE stack to handle all procedures which are time dependent.
The timer should have an accuracy of 1 ms and it is recommended to be able to count up to 24 hours.
BLEPLAT Timer functions | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
|
The number of timers required by the BLE stack depends on the variants used.
Here is the formula to compute the maximum number of timers needed per variants:
- For the Full and Basic Plus, Basic variants: Maximum Number of timers = (6 x numOfLinks) + 5
- For the Peripheral Only variant: Maximum Number of timers = (4 x numOfLinks) + 4
- For the LL_Only, LL_Only_Basic variants (no Host Stack): Maximum Number of timers = 0
4.2.3. AES functions
The AES functions are used by the BLE stack to encrypt a 128-bit single block or to compute CMAC which is needed by BLE security manager.
BLE PLAT AES functions | |||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
4.2.4. PKA functions
The PKA functions are used by the BLE stack to compute the P-256 public key and the DH key used for BLE secure connections.
BLEPLAT PKA functions | ||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
4.2.5. RNG functions
This function is called by the BLE stack to retrieve “n” x 32*bit words of random values.
BLEPLAT RNG function | ||||||
---|---|---|---|---|---|---|
|
5. References
STM32WBA_BLE_Wireless_Interface.html