This example shows how to implement transparent serial data connection between two BGMxxx modules. Functionally the example is very close to the BGScript example that is described in following article:


There is no standard SPP service in Bluetooth Smart and therefore we need to implement this as a custom service. The service is exactly same as the one used in the BGScript example (see link above) and it can be described using the XML notation as follows:



	<!-- Our custom accelerometer service is declared here -->	 
	<!-- UUID values generated with --> 
	<service uuid="4880c12c-fdcb-4077-8920-a450d7f9b907" advertise="true">
        <description>SPP Service</description>
		<characteristic uuid="fec26ec4-6d71-4442-9f81-55bc21d658d6" id="xgatt_spp_data">
            <description>SPP Data</description>
            <properties write_no_response="true" notify="true" />
			<value variable_length="true" length="20" type="hex"></value>


The basic idea of the SPP service is explained in the BGScript article linked above and therefore it is not covered here.


The zip file attached at the end of this article includes source code for one single application that implements both the server and client roles. The role is selected dynamically at power-up using pushbuttons, details are found later in the section Running the demo.  


Building the SPP project


This example has been tested with Bluetooth SDK 2.3.1 and GCC toolchain. The code should work without any changes at least with the following radio boards:

BGM111 (PCB4300A)
BGM121 (BRD4302A)


The zip file attached at the end of this article includes the source files for the C-based SPP example. It is not a complete project but a set of files that you can copy on top of a project created in Simplicity Studio. Follow these step-by-step instructions carefully:


Step 1: Create the SOC -Empty example project in Studio


After the project is created the BLE GATT Configurator is opened automatically and it shows the GATT database of the project. The project template includes a minimal GATT database that includes three services (Generic Access, Device Information and Silicon Labs OTA). Next you need to add the SPP service using the BLE GATT Configurator.


Step 2: add the SPP service


The details of the SPP service are:

Service UUID value  4880c12c-fdcb-4077-8920-a450d7f9b907

SPP data : UUID value  fec26ec4-6d71-4442-9f81-55bc21d658d6


For the SPP data characteristic, define the ID as “gatt_spp_data”.

The length of the characteristic is set to 20 bytes and type is hex. variable length checkbox selected.


Add and enable following properties: write without response and notify.



The following screenshots show how the SPP service should look like in the BLE GATT Configurator.


SPP service:




SPP_data characteristic:



After adding the service, save the *.isc file and press Generate button on the upper right corner of the GUI.


At this point, it is good to check that the project builds without any errors.


Step 3: add the C source files to the project


Unzip the attached zip file and add the included source files to the project.


Files can be added to the project simply by drag&drop. Studio will prompt you to either create a link to these files or create a copy. Select “copy” option. Note that the main.c that was created by Studio as part of the SOC – Empty example is overwritten.


Step 4: defined RETARGET_VCOM


Finally, in the project settings you need to define the precompiler directive RETARGET_VCOM so that the code uses the on-board USB-to-UART converter of the development kit. 


Following screenshot shows how to set this in the GCC build options:




After building the project, flash the firmware to two development kits. The same application supports both SPP server and client roles. The following section explains how to select the mode.


Running the demo


Simplest way to run the demo is to use two similar development kits (for example two BGM121 kits). In this case you can use the same binary for both boards.


When the application boots, it checks the state of pushbuttons PB0, PB1. If buttons are not pressed the application starts in SPP server role.


By keeping either PB0 or PB1 pressed during reboot the application starts in SPP client mode.


In server mode, the device advertises the custom SPP service and waits for incoming connections.


In client mode, the device starts scanning and searches for the custom SPP UUID in the scan responses. If match is found, the client connects to the target, discovers the SPP service and characteristics and then enables notifications for the SPP_data characteristic. At this point, any data that is input in the client side is sent over the air to the server and printed on the remote UART. Similarly, any data input to the server UART is transmitted back to the client.


To connect to the kit using terminal program use the following UART settings: baud rate 115200 , 8N1, no flow control.


The example can be also tested between two different kits (e.g. BGM121 and BGM111). As the SPP service is the same that was used in the BGScript SPP example, it is also possible to connect BGScript-based SPP client to C-based SPP server, or vice versa. 


Yet another option is to use BLED112 as the SPP client, see following article for more info:



Power management


USART peripheral is not accessible in EM2 sleep mode. For this reason, both the client and the server applications disable sleeping (EM2 mode) temporarily when the SPP mode is active. SPP mode in this context means that the client and server are connected and that the client has enabled notifications for the SPP_data characteristics.


When SPP mode is entered, the code calls SLEEP_SleepBlockBegin(sleepEM2) to temporarily disable sleeping. When connection is closed (or client disables notifications) then SLEEP_SleepBlockEnd(sleepEM2) is called to re-enable sleeping.


For more details on the power management details, see following article:


Known issues


The sample code uses printf() for sending data to UART. For this reason, the example does not well with binary data transfer. 




This example is a simple C-based SPP implementation for BGMxxx / EFR32BG products. It is not optimized for performance or low power. The code has been kept as simple as possible.


UART input/output is handled using stdio retarget functions (see following article for details: )


This is not the most efficient way to handle UART input/output but the benefit is that it is portable and allows the sample code to be used easily on several radio boards without any modifications.




  • Knowledge Base Articles
  • Bluetooth Low Energy
  • Bluetooth Classic
  • Hi


    This is what I'm looking for SPP implementation. 


    Why there is no SPP in Visual GATT for EFR32BG1 with EVAL Startup Board  PCB4100A Rev 3 ?


    What needed to make SPP work for this EFR32BG1 device?, I do not like package from BGMxxx series.

  • This SPP implementation is a custom service I made up just for demo purposes. It is not included in the Visual GATT editor at least for now.


    The example discussed in this article should work also with PCB4100A without any changes. You first need to create the Soc Empty for this specific board and then add the SPP source files as instructed above.

  • I have written this code into EFR32BG1 via EVAL board PCB4001 (which should be similar to BTExxx device).


    I cannot see VCOM appearing in device list in Window Laptop not my android phone.


    I like to make connection over SPP in bluetooth between Window Laptop or Andoid Phone and this device. What need to be done and how?

  • You should see device like JLink CDC Uart Driver in Device Manager (COMx), and this is the correct COM device to conect in this example. But this is GATT service not real SPP profile so you will not see any extra COM ports. 

  • Hi

    I found C_BASED_SPP_EXAMPLE very useful. I'd like to know which pheripheral must be enabled (RTC must be enabled for example?)because in the zip file there is no InitDevice.c file. 

    Best Regards


  • @Gio63 if you create the Soc Empty example for your target radio board in Studio you will get the InitDevice.c file that is suitable for that board.


  • Thank you JaakkoV. Just another question......I need to send data received from SPP client through UART but I need to send binary data as well so I think printf can't work. I thought to modify file spp_server_main.c (inside C_BASED_SPP_EXAMPLE) because my application behave only as a server in this way:


      switch (BGLIB_MSG_ID(evt->header)) {




                    case gecko_evt_gatt_server_attribute_value_id:

                              memcpy(printbuf, evt->, evt->data.evt_gatt_server_attribute_value.value.len);
                              TxBuf(printfbuf, evt->data.evt_gatt_server_attribute_value.value.len);





     int TxBuf(uint8_t *buffer, int nbytes)
     int i;

     for (i = 0; i < nbytes; i++)
      return nbytes;

    Do you think could it work? Thank you




  • @Gio63 the solution that you proposed looks good to me. You don't necessarily need to use memcpy to first copy the bytes into another buffer. You could simply just have one function call:


    TxBuf(evt->, evt->data.evt_gatt_server_attribute_value.value.len);
  • Thank you Jaakkov. In the file ssp_server_main.c I don't find any call to API Function "gecko_cmd_le_gap_set_adv_parameters" There is any reason ?

    Thank you

    Best Regards


  • The example uses default advertising parameters. You can add a call to gecko_cmd_le_gap_set_adv_parameters before starting advertisements if you want to use some other settings.