4.1.1.5 Bluetooth®LE Transparent UART

This section explains how to create a central device and send/receive characters between two connected BLE devices over Microchip proprietary Transparent UART Profile. The central and peripheral devices in this tutorial are two PIC32WM-BW1 devices. The following instructions are applicable for a BLE Central device.

Users can choose to either run the precompiled Application Example hex file provided on the PIC32WM-BW1 Curiosity Board or follow the steps to develop the application from scratch.

It is recommended to follow the examples in sequence to understand the basic concepts before progressing to the advanced topics.

Hardware Requirement

Table 4-7. Hardware Prerequisites
S. No. Tool Quantity
1PIC32WM-BW1 Curiosity Board2
2USB Type-C cable2

Software Requirement

  • To install Tera Term tool, refer to the Tera Term web page listed in the Reference Documentation from Related Links.

Programming the Precompiled Hex File or Application Example

Using MPLAB® X IPE:

  1. Central Device – Precompiled .hex file is located in “<Harmony Content Path>\wireless_apps_pic32_bw1\apps\ble\central\central_trp_uart\hex” folder.
  2. Peripheral Device – Precompiled .hex file is located in “<Harmony Content Path>\wireless_apps_pic32_bw1\apps\ble\peripheral\peripheral_trp_uart\hex” folder.
  3. For detailed steps, refer to Programming a Device in MPLAB® IPE in Reference Documentation from Related Links.
    Note: Ensure to choose the correct Device and Tool information.

Using MPLAB® X IDE:

  1. Perform the following the steps mentioned in Running a Precompiled Example. For more information, refer to Running a Precompiled Application Example from Related Links.
  2. Central Device – Open and program the application central_trp_uart.X located in “<Harmony Content Path>\wireless_apps_pic32_bw1\apps\ble\central\central_trp_uart\firmware”.
  3. Peripheral Device – Open and program the application peripheral_trp_uart.X located in “<Harmony Content Path>\wireless_apps_pic32_bw1\apps\ble\peripheral\peripheral_trp_uart\firmware”.
  4. For more details on finding the Harmony content path, refer to Installing the MCC Plugin from Related Links.

Testing

  1. Users must use two PIC32WM-BW1 Curiosity Board configured as Peripheral and Central device, to experience this demo.
  2. Board 1 – PIC32WM-BW1 Curiosity Board Programmed with “peripheral_trp_uart”. Open TeraTerm and configure as mentioned below:

    Terminal Settings:

    • Baud Rate/Speed – 115200
    • Parity – None
    • Data Bits – 8
    • Stop Bits – 1
    • Flow Control – None
  3. Reset the board, Upon reset, “BW1-Advertising” message is displayed on the Tera Term.
  4. Board 2 – PIC32WM-BW1 Curiosity Board Programmed with “central_trp_uart”. Open Tera Term and configure as mentioned below:
    Terminal Settings:
    • Baud Rate/Speed – 115200
    • Parity – None
    • Data Bits – 8
    • Stop Bits – 1
    • Flow Control – None
  5. Reset the board. Upon reset, “Scanning” message is displayed on the Tera Term.
  6. Central device (Board 2) will start scanning for nearby peripheral devices to connect. Upon finding peripheral device with public address {0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6} message “Found Peer Node” will be displayed and a connection request will be initiated “Initiating connection”.
  7. After connection establishment, both the peripheral device (Board 1) and central device (Board 2) displays “Connected!” message on respective terminal windows.
    Figure 4-37. Tera Term
  8. Users can now start sending data back and forth between the central and peripheral device using the terminal emulator. Characters entered on either terminals will immediately be sent to the peer devices
  9. The Central device (Board 2) scans for approximately 1 minute 40 seconds and displays “Scan Completed” message on terminal window when it finishes.

Project Graph

This section explains how MCC Project graph must look like and component configurations.
  1. Verify if the Project Graph window has all the expected configuration as illustrated in the following figure.
    Figure 4-38. Project Graph

Verifying Scan, Connection and Transparent Profile Configuration

  1. Select BLE Stack component in project graph, to open component configuration and configure as illustrated in the following figure.

    Figure 4-39. BLE Stack Configuration
  2. Select Transparent Profile component in project graph, to open component configuration and configure as illustrated in the following figure.

    Figure 4-40. Transparent Profile Configuration

Files and Routines Automatically generated by the MCC

After generating the program source from MCC interface by clicking Generate Code, the BLE configuration can be found in the following project directories
Figure 4-41. Project File

The OSAL, RF System and BLE System initialization routine executed during program initialization can be found in the project file. This initialization routine is automatically generated by the MCC.

Figure 4-42. initialization.c
The BLE stack initialization routine executed during Application Initialization can be found in project files. This initialization routine is automatically generated by the MCC. This call initializes and configures the GAP, GATT, SMP, L2CAP and BLE middleware layers.
Figure 4-43. app_ble.c
Table 4-8. Source Files
Source Files Usage
app.cApplication State machine, includes calls for Initialization of all BLE stack (GAP,GATT, SMP, L2CAP) related component configurations
app_ble\app_ble.cSource code for the BLE stack related component configurations, code related to function calls from app.c
app_ble\app_ble_handler.cGAP, GATT, SMP and L2CAP event handlers
app_ble\app_trspc_handler.cAll transparent UART client related event handlers
ble_trspc.cAll transparent client functions for user application
Note: app.c is auto generated and has a state machine based Application code sample. Users can use this template to develop their application.

Header Files

  • ble_gap.h: This header file contains BLE GAP functions and is automatically included in the app.c file

  • ble_trspc.h: This header file associated with API’s and structures related to BLE Transparent Client functions for application user.

Function Calls

MCC generates and adds the code to initialize the BLE Stack GAP, GATT, L2CAP and SMP in APP_BleStackInit() function.

  • APP_BleStackInit() is the API that will be called inside the Applications Initial State (APP_STATE_INIT) in app.c

User Application Development

  1. Include

    1. Include the user action. For more information, refer to User Action from Related Links.
    2. ble_trspc.h in app.c, BLE Transparent UART Server related API's are available here

    3. osal/osal_freertos_extend.h in app_trsps_handler.c, OSAL related API's are available here

    4. definitions.h in all the files where UART will be used to print debug information
      Note: definitions.h is not specific to just UART peripheral, instead it must be included in all application source files where peripheral functionality will be exercised.
  2. In app_ble_handler.c, Scan Results and initiating a BLE Connection

    1. BLE_GAP_EVT_ADV_REPORT event is generated upon finding Advertisements on legacy channels
    2. BLE connection can be initiated by using the API BLE_GAP_CreateConnection(&createConnParam_t;

      // Filter Devices based of Address, for this example address checking only 2 bytes
    
    if ((p_event->eventField.evtAdvReport.addr.addr[0] == 0xA1 && p_event->eventField.evtAdvReport.addr.addr[1] == 0xA2) ||
     (p_event->eventField.evtAdvReport.addr.addr[0] == 0xB1 && p_event->eventField.evtAdvReport.addr.addr[1] == 0xB2) ||
     (p_event->eventField.evtAdvReport.addr.addr[0] == 0xC1 && p_event->eventField.evtAdvReport.addr.addr[1] == 0xC2))
    {
    SERCOM0_USART_Write((uint8_t *)"Found Peer Node\r\n", 17);
         BLE_GAP_CreateConnParams_T createConnParam_t;
         createConnParam_t.scanInterval = 0x3C; // 37.5 ms 
         createConnParam_t.scanWindow = 0x1E; // 18.75 ms
         createConnParam_t.filterPolicy = BLE_GAP_SCAN_FP_ACCEPT_ALL;
         createConnParam_t.peerAddr.addrType = p_event->eventField.evtAdvReport.addr.addrType;
         memcpy(createConnParam_t.peerAddr.addr, p_event->eventField.evtAdvReport.addr.addr, GAP_MAX_BD_ADDRESS_LEN);
         createConnParam_t.connParams.intervalMin = 0x10; 
         createConnParam_t.connParams.intervalMax = 0x10; 
         createConnParam_t.connParams.latency = 0;
         createConnParam_t.connParams.supervisionTimeout = 0x48; 
         SERCOM0_USART_Write((uint8_t *)"Initiating Connection\r\n", 23);
         BLE_GAP_CreateConnection(&createConnParam_t);
    }
    Figure 4-44. app_ble_handler.c
  3. Scan Timeout Event
    1. In app_ble_handler.c BLE_GAP_EVT_SCAN_TIMEOUT” event is generated when BLE Scan duration expires.

      SERCOM0_USART_Write((uint8_t *)"Scan Completed \r\n", 17);	
    Figure 4-45. Scan Timeout
  4. Connected and Disconnected Events
    1. In app_ble_handler.c "BLE_GAP_EVT_CONNECTED" event will be generated when a BLE connection is completed.

  5. Connection Handler
    1. Connection handle associated with the peer peripheral device needs to be saved for data exchange after a BLE connection

    2. p_event->eventField.evtConnect.connHandle has this information
      #include "peripheral/sercom/usart/plib_sercom0_usart.h"
      extern uint16_t conn_hdl;
    3. In APP_BleGapEvtHandler() case BLE_GAP_EVT_CONNECTED:

      SERCOM0_USART_Write((uint8_t *)"Connected\r\n",11);
      conn_hdl = p_event->eventField.evtConnect.connHandle;
    4. In case BLE_GAP_EVT_DISCONNECTED.

      SERCOM0_USART_Write((uint8_t *)"Disconnected\r\n",14);
      Figure 4-46. app_ble_handler.c
    5. In app.c

      #include "peripheral/sercom/usart/plib_sercom0_usart.h"
      #include "ble_trspc/ble_trspc.h"

      Add following code snippet in app.c to implement Transmitting the received data over UART using BLE_TRSPC_SendData()API:

      uint16_t conn_hdl;// connection handle info captured @BLE_GAP_EVT_CONNECTED event
      uint8_t uart_data;
      void uart_cb(SERCOM_USART_EVENT event, uintptr_t context)
      {
        APP_Msg_T   appMsg;   
      // If RX data from UART reached threshold (previously set to 1)
        if( event == SERCOM_USART_EVENT_READ_THRESHOLD_REACHED )
        {
          // Read 1 byte data from UART
          SERCOM0_USART_Read(&uart_data, 1);
      
          appMsg.msgId = APP_MSG_UART_CB;
          OSAL_QUEUE_Send(&appData.appQueue, &appMsg, 0);     
        }
      }
      
      void APP_UartCBHandler()
      {
      // Send the data from UART to connected device through Transparent service
          BLE_TRSPC_SendData(conn_hdl, 1, &uart_data);     
      }
      This API is called in the Applications initial state – APP_STATE_INIT in app.c and scan duration is 100 seconds.
      // Scanning Enabled
      BLE_GAP_SetScanningEnable(true, BLE_GAP_SCAN_FD_ENABLE, BLE_GAP_SCAN_MODE_OBSERVER, 1000);
      // Output the status string to UART
      SERCOM0_USART_Write((uint8_t *)"Scanning \r\n", 11);
    6. In case APP_STATE_INIT, add following:
      // Enable UART Read
      SERCOM0_USART_ReadNotificationEnable(true, true);
      // Set UART RX notification threshold to be 1
      SERCOM0_USART_ReadThresholdSet(1);
      // Register the UART RX callback function
      SERCOM0_USART_ReadCallbackRegister(uart_cb, (uintptr_t)NULL);
    7. In case APP_STATE_SERVICE_TASKS, add following:
      else if(p_appMsg->msgId==APP_MSG_UART_CB)
      {
      // Transparent UART Client Data transfer Event
      APP_UartCBHandler();
      }
      Example implementation:
      Figure 4-47. app.c
      Figure 4-48. app.c
    8. In app.h

      Add APP_MSG_UART_CB in APP_MsgId_T enum. BLE_TRSPC_SendDat(conn_hdl,1,&data) is the API used to send data forward towards the central device.
      Figure 4-49. Transmit Data
    9. In app_trspc_handler.c, Receive Data

      1. BLE_TRSPC_EVT_RECEIVE_DATA is the event generated when data is sent from central device
      2. Users need to use the BLE_TRSPC_GetDataLength(&data_len) API to extract the length of application data received
      3. BLE_TRSPC_GetData(&conn_hdl, data); API is used to retrieve the data, conn_hdl is the value obtained from Connection Handler section
        Note: BLE_TRSPC_Event_T p_event structure stores the information about BLE transparent UART callback functions.
        #include <string.h>
        #include <stdint.h>
        #include "ble_trspc/ble_trspc.h"
        #include "definitions.h"
    10. In case BLE_TRSPC_EVT_RECEIVE_DATA:
      uint16_t data_len;
      uint8_t *data;
      // Retrieve received data length
      BLE_TRSPC_GetDataLength(p_event->eventField.onReceiveData.connHandle, &data_len);
      
      // Allocate memory according to data length
      data = OSAL_Malloc(data_len);
      if(data == NULL)
      break;
      // Retrieve received data
      BLE_TRSPC_GetData(p_event->eventField.onReceiveData.connHandle, data);
      // Output received data to UART
      SERCOM0_USART_Write(data, data_len);
      // Free memory
      OSAL_Free(data);
      Example Implementation for printing the received data from peripheral device over UART:
      Figure 4-50. app_trspc_handler.c