Data streaming between two BLE devices: PSoc6 and nRF52832

Data streaming between two BLE devices: PSoc6 and nRF52832

I had a project where I had to stream data between two BLE devices. The data source was connected to PSoc6 and sent using its BLE transceiver to the destination device, nRF52832. Usually but not must, the peripheral devices are used as a GATT client, and the central machines are used as a GATT server. Therefore, I set the PSoc6 (The data source) as the central device (client) and the nRF52832 as the peripheral device (server). This setup is convenient for timing a new data packet and sending it whenever possible.

PSoc6 as Peripheral

In this section, I present the BLE settings on PSoc6 as a central device/ For doing it, I had to follow the teachings on this video, and I summarized them in this section.

Parsing the Advertising String

To parse the advertising stream, I have used the same function from the function from here.

void find_adv_info(uint8_t *adv, uint8_t len) {
	memset ((void*)&adv_info, 0, sizeof(struct adv_info));
	for (uint8_t i=0;i < len;){
		switch (adv[i+1]) {
			case 0x07:// servce uuid
				adv_info.serviceUUID = &adv[i+2];
				adv_info.servUUID_len = adv[i] - 1;
				break;
			case 0x09: // name
				adv_info.name = (char*)&adv[i+2];
				adv_info.name_len = adv[i] - 1;
				break;
		}
		i = i + adv[i] + 1;
	}
}

The main BLE task, the one that runs that BLE stack, looks like that:

struct adv_info {
	char *name;
	int name_len;
	uint8_t *serviceUUID;
	uint8_t servUUID_len;
} adv_info;


void ble_task(void *arg)
	{
		(void)arg;   

		Cy_BLE_Start(customEventHandler);


		while (Cy_BLE_GetState() != CY_BLE_STATE_ON) 
		{
			Cy_BLE_ProcessEvents();		
		}

		Cy_BLE_RegisterAppHostCallback(ble_irq);

		//	Cy_BLE_RegisterAttCallback(ias_event);
		for(;;)
		{
			uint32_t ulNotifiedValue =  ulTaskNotifyTake(pdTRUE, portMAX_DELAY);

			Cy_BLE_ProcessEvents();
		}
	}

Where ble_irq looks like this:

static __inline void ble_irq(void)
{
	BaseType_t xHigherPriorityTaskWoken = pdFALSE;
	if (xBLETaskHandle != 0) {
		vTaskNotifyGiveFromISR( xBLETaskHandle, &xHigherPriorityTaskWoken );
		portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
	}
}

And the custom event handle looks like a witch case function that responds to GATT client events. Here are some useful events:

void customEventHandler(uint32_t event, void *eventParameter)
{
	cy_stc_ble_gatts_write_cmd_req_param_t   *writeReqParameter;   

	switch (event)
	{
	.....
	}
}
  • CY_BLE_EVT_STACK_ON and CY_BLE_EVT_GAP_DEVICE_DISCONNECTED: These events will make the device start scanning.
case CY_BLE_EVT_STACK_ON:
case CY_BLE_EVT_GAP_DEVICE_DISCONNECTED: 
{
	Cy_BLE_GAPC_StartScan(CY_BLE_SCANNING_FAST, 0);
	break;
}

  • CY_BLE_EVT_GAPC_SCAN_PROGRESS_RESULT happens when scan results are available:

In this sample, I detected the device by its name “Nordic.” The better way to do it is by the UUID.

case CY_BLE_EVT_GAPC_SCAN_PROGRESS_RESULT: 
{
	cy_stc_ble_gapc_adv_report_param_t *scan_progress_param = (cy_stc_ble_gapc_adv_report_param_t*)eventParameter;
	if (memcmp(adv_info.name,"Nordic",5) ==0) {
		cy_stc_ble_gap_bd_addr_t connected_addr;
		memcpy(&connected_addr.bdAddr[0], &scan_progress_param->peerBdAddr[0], CY_BLE_GAP_BD_ADDR_SIZE);
		connected_addr.type = scan_progress_param->peerAddrType;
		Cy_BLE_GAPC_ConnectDevice(&connected_addr, 0);
		Cy_BLE_GAPC_StopScan();
	}
	break;
}
  • CY_BLE_EVT_GATT_CONNECT_IND happens when the connection to a peer device happens. as a response to this device, I change the MTU size to allow larger packages more than the default 23 bytes.
case CY_BLE_EVT_GATT_CONNECT_IND: 			
{
	cy_en_ble_api_result_t res;
	cy_stc_ble_gatt_xchg_mtu_param_t p;
	p.connHandle  = (cy_ble_connHandle[0]);
	p.mtu = 400;
	res = Cy_BLE_GATTC_ExchangeMtuReq(&p);
	break;

}
  • Other useful events: CY_BLE_EVT_GATTC_DISCOVERY_COMPLETE, CY_BLE_EVT_GATTC_ERROR_RSP,CY_BLE_EVT_GATTC_WRITE_RSP, CY_BLE_EVT_GATTC_XCHNG_MTU_RSP can be referred here.
void customEventHandler(uint32_t event, void *eventParameter)
{
	cy_stc_ble_gatts_write_cmd_req_param_t   *writeReqParameter;   

	switch (event)
	{

		case CY_BLE_EVT_GATTC_DISCOVERY_COMPLETE:
			{
				break;
			}
		case CY_BLE_EVT_GATTC_ERROR_RSP:
			{
				break;
			}
		case CY_BLE_EVT_GATTC_WRITE_RSP: 
			break;

		case CY_BLE_EVT_GATTC_XCHNG_MTU_RSP :
			break;
	}

The device settings

The device is set up to be a central device. So I change the parameters of MTU (maximum transfer unit) to be at maximum. So the MTU parameter has a direct influent on the data rate.

PSoc6 BLE - Genneral Settings

PSoc6 BLE - GATT Settings

PSoc6 BLE - GAP Settings

PSoc6 BLE - L2CAP Settings

PSoc6 BLE - Low Level Settings

Clock setup

The clock setting was defined as presented in the following figure. Refer here for more details.

PSoc6 BLE - Clock Settings

PSoc6 BLE - Clock Settings

Nordic (nRF52832) Settings

I have used the same work details I allready did in this.

References

[1] zephyr Bluetooth APIs
[2] https://infineon.github.io/bless/ble_api_reference_manual/html/
[3] A Practical Guide to BLE Throughput

Comments
comments powered by Disqus