The Bluetooth SDK supports two developing modes, System-On-Chip (SoC) and Network Co-Processor (NCP). For SoC mode, all the application will run on a single EFR32 device. For NCP mode, a EFR32 device acts as the coprocessor, working together with a host controller. AN1042: Using the Silicon Labs Bluetooth® Stack in Network Co-Processor Mode has detailed description of the NCP mode. It’s recommended to read this application note before reading this article, which can give you a better understanding of NCP mode.
Figure 1. SoC Mode
Figure 2. NCP Mode
BGLib and BGAPI
BGAPI is a custom binary protocol used to externally control our chipset and modules. BGAPI is a protocol specification only.
BGLib is an ANSI C reference implementation of the BGAPI binary protocol. BGLib only runs outside of our chipset and modules. BGLib assumes the host MCU is little-endian.
When using SoC mode, it allows you to run an application right on the chipset or module and call the BGAPI directly. However, if using the NCP mode, the application runs on an external device – typically a microcontroller, everything can communicate over UART between the NCP host and NCP target.
BGLIB_DEFINE
BGLib uses a set of global variables that are defined using macro BGLIB_DEFINE(), found in gecko_bglib.h. The host application that uses BGLib must include BGLIB_DEFINE() in global scope (i.e. it must be placed outside any function implementation).
BGLIB_DEFINE() is used to declare variables used for BGLib, it must be define globally.
_gecko_cmd_msg – The instance to store the command message.
_gecko_rsp_msg – The instance to store the response message.
gecko_cmd_msg – Pointer to _gecko_cmd_msg instance.
gecko_rsp_msg – Pointer to _gecko_rsp_msg instance.
gecko_queue[BGLIB_QUEUE_LEN] – FIFO buffer to store the messages received from the NCP target.
gecko_queue_w – FIFO buffer write index, working with gecko_queue_r to indicate if there is new message stored in the queue, it offsets by one if a new message is received.
gecko_queue_r – FIFO buffer read index, working with gecko_queue_w to indicate if there is new message stored in the queue, it offsets by one if a new message is read out from the queue.
bglib_output, bglib_input, bglib_peek – Function pointers to writing to / reading from / peek UART.
The symbol BGLIB_QUEUE_LEN defines the length of queue, it’s 30 by default and depends on the real use cases and allowed host memory usage.
Operation Modes
Blocking mode – If this mode is used, BGLib will get blocked in waiting events from NCP target if there is no data to send nor events to handle. To use this mode, use gecko_wait_event() to check events and call the function BGLIB_INITIALIZE(OFUNC, IFUNC) in your initialization code.
Nonblocking mode – If this mode is used, BGLib will not get blocked if there is no data to send nor data to receive. To use this mode, use gecko_peek_event() to check events and call the function BGLIB_INITIALIZE_NONBLOCK(OFUNC, IFUNC, PFUNC) in your initialization code.
It depends on the real use case which mode should be used. If there are many tasks not related to Bluetooth, nonblocking mode should be a better choice, because it will bypass the BGLib functions if there are no Bluetooth events to be handled and allows the MCU to process other tasks. The reason BGLib supports blocking mode is for symmetry purpose that the same code should work in both SoC and NCP modes, it’s recommended to use nonblocking mode because it gives the user better control of their application in most of the use cases.
Figure 3. Blocking vs Nonblocking
Function Mapping
Below functions are used to read from and write to UART. BGLib accesses UART through function pointers so that the code is platform independent. User must map the function pointers to platform-specific UART transmit / receive routines when initializing BGLIb. This is done using macro BGLIB_INITIALIZE() or BGLIB_INITIALIZE_NONBLOCK(), depending if blocking or non-blocking mode is used.
Add “BGLIB_DEFINE();” to the macro definition area in your project.
Add BGLIB_INITIALIZE(user_output, user_input) or BGLIB_INITIALIZE_NONBLOCK(user_output, user_input, user_peek) to the initialization code, after that, it’s recommended to call gecko_cmd_system_reset(0); function to reset the NCP target.
Add below template to the while loop to handle all the events received from NCP target.
static void appHandleEvents(struct gecko_cmd_packet *evt) {
if (NULL == evt) {
return;
}
/* Handle events */
switch (BGLIB_MSG_ID(evt->header)) {
case xxx:
break;
case xxx:
break;
…
default:
break;
}
}
While(1){
...
/* Check for stack event. */
evt = gecko_peek_event();
/* Run application and event handler. */
appHandleEvents(evt);
...
}
This example uses the nonblocking mode. You can import them to your Simplicity Studio, compile and download to your devices. The example is a very simple one, which only provides the skeleton showing the usage of both NCP host and NCP target. You can verify the example using a smartphone to scan and connect to it. It will advertise after boot or disconnected.
Memory Usage
GBGLib needs RAM for the variables defined in BGLIB_DEFINE(); as well as flash, below is the detailed RAM and flash usage of the example, the compiler is IAR with “High size” optimization.
Module ro code ro data rw data
------ ------- ------- -------
C:\Users\zhfu\SimplicityStudio\v4_mesh_mcu\KBA_ncp_host_pg\IAR ARM - Debug\CMSIS\EFM32PG1B: [1]
startup_efm32pg1b.o 348
system_efm32pg1b.o 136 16 16
------------------------------------------------
Total: 484 16 16
C:\Users\zhfu\SimplicityStudio\v4_mesh_mcu\KBA_ncp_host_pg\IAR ARM - Debug\emlib: [2]
em_cmu.o 756 4 4
em_gpio.o 156
em_system.o 52
em_usart.o 340
------------------------------------------------
Total: 1 304 4 4
C:\Users\zhfu\SimplicityStudio\v4_mesh_mcu\KBA_ncp_host_pg\IAR ARM - Debug\src: [3]
app.o 400 20 8 348
gecko_bglib.o 336
main.o 116
------------------------------------------------
Total: 852 20 8 348
RAM
The RAM usage for the unit gecko_cmd_packet is 0x104. For 32-bit MCU, each point occupies 4-byte. The length of the queue is 30, so it takes 0x104 * 30 = 0x1e78.
The total flash of the example is 484+1304+852= 2640 bytes. They can be split by functionalities.
Basic part - It is required for any EFM32PG1 projects. startup_efm32pg1b.o, system_efm32pg1b.o and main.o and em_system.o, the flash occupation is 484+116+52 = 652 bytes. This part is platform-specific.
UART related part - Driver of UART. em_cmu.o, em_gpio.o and em_usart.o, the flash occupation is 756+156+340 = 1252 bytes. This part is platform-specific.
BGLib and application part – App.o has the basic skeleton of the Bluetooth event handler, which is the minimal requirement of application. The flash occupation is 400+336 = 736 bytes.
I don't think the second diagram is supported by the standard BGAPI. The number of ncp hosts running on a PC depends on the resource of the PC, including the serial ports and RAM etc.
KBA_BT_1602: NCP Host Implementation and Example
SoC Mode vs NCP Mode
The Bluetooth SDK supports two developing modes, System-On-Chip (SoC) and Network Co-Processor (NCP). For SoC mode, all the application will run on a single EFR32 device. For NCP mode, a EFR32 device acts as the coprocessor, working together with a host controller. AN1042: Using the Silicon Labs Bluetooth® Stack in Network Co-Processor Mode has detailed description of the NCP mode. It’s recommended to read this application note before reading this article, which can give you a better understanding of NCP mode.
Figure 1. SoC Mode
Figure 2. NCP Mode
BGLib and BGAPI
When using SoC mode, it allows you to run an application right on the chipset or module and call the BGAPI directly. However, if using the NCP mode, the application runs on an external device – typically a microcontroller, everything can communicate over UART between the NCP host and NCP target.
BGLIB_DEFINE
BGLib uses a set of global variables that are defined using macro BGLIB_DEFINE(), found in gecko_bglib.h. The host application that uses BGLib must include BGLIB_DEFINE() in global scope (i.e. it must be placed outside any function implementation).
BGLIB_DEFINE() is used to declare variables used for BGLib, it must be define globally.
The symbol BGLIB_QUEUE_LEN defines the length of queue, it’s 30 by default and depends on the real use cases and allowed host memory usage.
Operation Modes
It depends on the real use case which mode should be used. If there are many tasks not related to Bluetooth, nonblocking mode should be a better choice, because it will bypass the BGLib functions if there are no Bluetooth events to be handled and allows the MCU to process other tasks. The reason BGLib supports blocking mode is for symmetry purpose that the same code should work in both SoC and NCP modes, it’s recommended to use nonblocking mode because it gives the user better control of their application in most of the use cases.
Figure 3. Blocking vs Nonblocking
Function Mapping
Below functions are used to read from and write to UART. BGLib accesses UART through function pointers so that the code is platform independent. User must map the function pointers to platform-specific UART transmit / receive routines when initializing BGLIb. This is done using macro BGLIB_INITIALIZE() or BGLIB_INITIALIZE_NONBLOCK(), depending if blocking or non-blocking mode is used.
This is the callback function to send “len1” amount of data out via UART
This is the callback function to receive “len1” amount of data via UART
This is only required if using the nonblocking mode, this function is to peek the UART if there is any data valid.
How BGLib works?
Below 3 flowcharts show how BGLib works in details.
Figure 4. Flowchart of Nonblocking function calling
Figure 5. Flowchart of blocking function calling
Figure 6. Flowchart of API calling
Adding BGLib to Host MCU Project
Preparation
Below is the step by step guide to add BGLib to a host MCU project.
Example
Contents
Attachment is an example running on EFR32PG1 kit – BRD2500 Rev A01 (NCP host) and EFR32BG13 kit – BRD4104a Rev A00 (NCP target).
UART configuration
Connection between NCP host and NCP target is shown below, see figure 5.
NCP host expansion header NCP target expansion header
GND GND
PIN 9 (PD10) – UART TX PIN 14 (PA1) – UART RX
PIN 11 (PD11) – UART RX PIN 12 (PA0) – UART TX
Figure 7. Connection between NCP host and target
Verifying the example
This example uses the nonblocking mode. You can import them to your Simplicity Studio, compile and download to your devices. The example is a very simple one, which only provides the skeleton showing the usage of both NCP host and NCP target. You can verify the example using a smartphone to scan and connect to it. It will advertise after boot or disconnected.
Memory Usage
GBGLib needs RAM for the variables defined in BGLIB_DEFINE(); as well as flash, below is the detailed RAM and flash usage of the example, the compiler is IAR with “High size” optimization.
Module ro code ro data rw data
------ ------- ------- -------
C:\Users\zhfu\SimplicityStudio\v4_mesh_mcu\KBA_ncp_host_pg\IAR ARM - Debug\CMSIS\EFM32PG1B: [1]
startup_efm32pg1b.o 348
system_efm32pg1b.o 136 16 16
------------------------------------------------
Total: 484 16 16
C:\Users\zhfu\SimplicityStudio\v4_mesh_mcu\KBA_ncp_host_pg\IAR ARM - Debug\emlib: [2]
em_cmu.o 756 4 4
em_gpio.o 156
em_system.o 52
em_usart.o 340
------------------------------------------------
Total: 1 304 4 4
C:\Users\zhfu\SimplicityStudio\v4_mesh_mcu\KBA_ncp_host_pg\IAR ARM - Debug\src: [3]
app.o 400 20 8 348
gecko_bglib.o 336
main.o 116
------------------------------------------------
Total: 852 20 8 348
RAM
The RAM usage for the unit gecko_cmd_packet is 0x104. For 32-bit MCU, each point occupies 4-byte. The length of the queue is 30, so it takes 0x104 * 30 = 0x1e78.
Total = 0x104 * 2 + 0x4 * 7 + 0x1e78 = 0x209c = 8348 bytes
Flash
The total flash of the example is 484+1304+852= 2640 bytes. They can be split by functionalities.
I have one Question,
If I like to use the exansion header on the KIT PA1 and PA0 instead of the UART JLINK should I change the GPIO in NCP target source?
if yes, where?
thanks in advance
Hi,
You only need to set the symbol HAL_VCOM_ENABLE to 0 in hal_config.h.
Thanks,
Kevin
Hi Kevin,
1、A NCP Taget(EFR32BG) <<==>> B NCP Host(PC)。如果用 PC,作为 NCP Host,是否意味着 连接数可以无限制?
2、A NCP Taget(EFR32BG) <<==>> B NCP Host(EFR32BG) <<==>> C NCP Taget(EFR32BG) <<==>> D NCP Host(PC),这种链路是否可行?
Thanks,
Stephen
I am trying to connect two EFR32BG boards through uart by extention header pin ( RX,TX,PA3,PA2) .
I want to run NCP-host in one board and ncp-target on another one ...
but my ncp-target is not advertising...
can you help me out, what is the issue
Hi Stephen Feng,
I don't think the second diagram is supported by the standard BGAPI. The number of ncp hosts running on a PC depends on the resource of the PC, including the serial ports and RAM etc.
Thanks,
Kevin
Hi hemant sharma,
Did you get both of them working? Have you got the boot event on the host side?
Thanks,
Kevin
No.. i dont get boot event @host side..
I have connected (RX,TC,GND) first in both the boards..
after that i connected ( RX,TX,GND, RTS,CTS) in both board ...
can you help me to set exact configuration on which it works..
Hi Hemant,
i am interested about your application.
Did you solve your problem? Thanks.
Hi,
i'm using STM32L5 as Host MCU. I have some problems defining the receiving function user_input to pass to the BGLIB_INITIALIZE_NONBLOCK:
Hal library defines a non-blocking receiving function as follows:
Can idefine the user_input function in this way??
Thanks
Hi lidia moioli,
Yes, that's OK.
Thanks,
Kevin