微波EDA网,见证研发工程师的成长!
首页 > 研发问答 > 无线和射频 > TI蓝牙设计交流 > CC2541主机向从机发送大量数据的实现方式

CC2541主机向从机发送大量数据的实现方式

时间:10-02 整理:3721RD 点击:

请教一下,在串口透传模块,主机端需要实现大容量数据的发送,我通过GATT_WriteCharValue函数像从机发送数据,一次只能发送19个字节,当数据个数超过19个字节后,会自动分包发送。但是我自己测试最大只能分为两个包,19+18=37字节,可以正常收发。但是超过之后,就会发生错误,例如发送50字节时,自动分包19+19+12,但是主机只能成功发送第一个19字节和最后的12字节,中间的19字节调用GATT_WriteCharValue时,会产生错误,错误码22。同样如果是发送65字节时,自动分包为19+19+19+8,但是也只有头尾19+8正常收发,中间的19+19还是产生错误,错误码22。

看帖子,有人调用GATT_WriteLongCharValue函数,我自己测试也没有成功,不知道是哪里出了问题,请各位大神们帮忙,方便的话顺带提供一下发送数据的代码段,非常感谢!

大数据用GATT_WriteLongCharValue()函数,可以实现自动分包

另外您也可以使用 

http://processors.wiki.ti.com/index.php/OverlappedProcessing 给出的方法

Note, to use back to back packets, you will want to use GATT notifications or writeNoRsp.

你好,

下面链接的文章应该可以帮到你。

Purpose / Scope

This wiki page will demonstrate the maximum BLE throughput that can be achieved with a Texas Instruments CC2640 where the following assumptions are made:

  • both sides of the connection are CC2640 devices. Other stacks in master devices such as iOS and Android will limit the maximum packets per connection interval, thus limiting the throughput. See this blog post on how to maximize throughput with Android & iOS devices.
  • ideal RF conditions. Missed events / CRC errors due to RF interference will limit the throughput.
  • Neither master nor slave device contains processing that will starve the controller, thus limiting throughput. That is, application-specific processing or other custom constraints may further decrease throughput.

The throughput being measured is actual usable payload GATT throughput. Any LL / L2CAP headers are not considered part of the throughput. 
The GATT architecture used is such that the GATT server is sending GATT notifications to the GATT client. 
The test setup considered in this wiki can be replicated by applying the following patch to the BLE-Stack v2.1.0 installer: File:Throughput patch.zip This will update the simpleBLEPeripheral (SBP) project (acting as the GATT server) and the simpleBLECentral (SBC) project (acting as the GATT client).

Parameters

The basic idea is to be constantly sending GATT notifications, with as little overhead as possible, and as little downtime as possible. The following parameters must be considered.

ATT_MTU Size

Please refer to Section "5.5.2 Maximum Transmission Unit (MTU)" in the CC2640 BLE SW Developer's Guide (SWRU393) for an explanation of the Attribute Protocol Maximum Transmission Unit (ATT_MTU).

In order to minimize L2CAP header overhead, the maximum ATT_MTU size is being used: 255 bytes. This will result in 248 byte notifications being sent. This means that there is a 7 byte L2CAP overhead for every 248 bytes sent. In order to achieve this, both SBP and SBC project must set the following defines in bleUserConfig.h:

#define MAX_NUM_PDU 6
 
#define MAX_PDU_SIZE 255

This will allocate 6 Tx buffers of 255 bytes. In order to support this, the heap size must be increased by setting the following preprocessor definition: HEAPMGR_SIZE=6000. This will still produce a compiler warning that there is not enough heap. However, this can be ignored as this warning is triggered if 1/3 of the heap is being used for the Tx buffers. Since our application is using very little other heap, this is not an issue. A custom application will need to be profiled to verify that there is enough heap for the desired PDU / PDU size combination. If there is not, then the MAX_NUM_PDU define can be decreased, possibly causing a loss of throughput. Since the actual (worst case) memory used is a product of the MAX_NUM_PDU & MAX_PDU_SIZE, the system designer will need to balance these parameters according to available memory and capability of the peer device. For example, when interfacing to an iOS8+ device, a MAX_PDU_SIZE=162 and MAX_NUM_PDU=6 would match the iOS device's ATT_MTU of 158 and up to 6 packets per connection event. These parameters may vary from a given iOS release or device.

Connection Interval

Depending on the amount of post/pre-processing, the controller needs 2-3 ms to prepare for the next connection event. Therefore, longer connection intervals allow for higher throughput as there is less downtime where notifications are not being sent. This example will use a connection interval of 200 ms. Note that there is a significant downside to using higher intervals in a real world scenario: missed connection events due to RF interference will drastically decrease the throughput. Therefore, it is up to the user to decide what throughput / latency tradeoff is desired. Note that there is not much of a throughput increase after ~ 100 ms connection interval: 

Throughput graphy.png

Notification Queuing

The case considered here assumes that the application is able to queue up notifications quickly enough so that there is always a notification ready to be sent when a slot opens. This is achieved by the application RTOS task running in an infinite loop in simpleBLEPeripheral.c:

static void blastData()
{
  uint16 len = MAX_PDU_SIZE-7;
  attHandleValueNoti_t noti;
  bStatus_t status;
  noti.handle = 0x1E;
  noti.len = len;  
 
  while(1)
  {
    //attempt to allocate payload
    noti.pValue = (uint8 *)GATT_bm_alloc( 0, ATT_HANDLE_VALUE_NOTI, GATT_MAX_MTU, &len );
 
    if ( noti.pValue != NULL ) //if allocated
    {
      //place index
      noti.pValue[0] = (msg_counter >> 24) & 0xFF;
      noti.pValue[1] = (msg_counter >> 16) & 0xFF;
      noti.pValue[2] = (msg_counter >> 8) & 0xFF;
      noti.pValue[3] = msg_counter & 0xFF;      
      status = GATT_Notification( 0, &noti, 0 );    //attempt to send 
      if ( status != SUCCESS ) //if noti not sent
      {
        GATT_bm_free( (gattMsg_t *)&noti, ATT_HANDLE_VALUE_NOTI );
      }
      else //noti sent, increment counter
      {
        msg_counter++;
      }
    }
    else
    {
      //bleNoResources
      asm("NOP");
    }
  }
}

Due to other processing needs, a custom application may not be able to replicate or sustain this throughput (e.g., having to wait for payload data to arrive over serial interface). In addition, the blastData function maximizes enqueuing of data (Notifications in this example), so it is expected to see GATT_Notification return a non-SUCCESS status, such as blePending when the queue is full. When this status is returned, the BLE Stack will gradually clear the Tx queue as channel conditions permit, thus allowing the application to enqueue more GATT Notifications once the queue clears. The depth of the Tx queue is determined by the MAX_NUM_PDU define listed above. 
Note that the LED pins are used for debugging. Under maximum throughput conditions, you may expect to see a high number of blePending (non-SUCCESS) status results from calling GATT_Notification.

Method

The throughput will be calculated from an extrapolation of the amount of data sent in one connection event. This will be cross referenced with the one second throughput from a Frontline sniffer. 
The test can be replicated via: 
1. Apply patch from above to 2.1.0 installer 
2. Compile simpleBLEPeripheral and simpleBLECentral projects 
3. Connect simpleBLECentral to simpleBLEPeripheral

Result

Using the parameters described above, we are able to achieve a throughput of around 295 kbps. 

Throughput 2.png 

Throughput3.png

As seen in the above capture, 29 packets of 248 GATT payload bytes are sent in one connection event (200 ms). This comes out to 295.8 kbps. Frontline gives a one second throughput of 301.68 kbps. However, this includes 7 bytes of overhead for L2CAP headers. To account for this, 301.68 * (248/255) = 293.4 kbps which correlates with our extrapolated estimate.

我看CC2541手册并没有给出GATT_WriteLongCharValue这个函数API,请问一下哪有该函数的使用例程或者介绍资料,谢谢!

您可以在例程的工程内查找该API,但只给出了函数定义。

/**
* @brief This sub-procedure is used to write a Characteristic Value to
* a server when the client knows the Characteristic Value Handle
* but the length of the Characteristic Value is longer than can
* be sent in a single Write Request Attribute Protocol message.
*
* The ATT Prepare Write Request and Execute Write Request are
* used to perform this sub-procedure.
*
* If the return status from this function is SUCCESS, the calling
* application task will receive multiple OSAL GATT_MSG_EVENT messages.
* The type of the messages will be either ATT_PREPARE_WRITE_RSP,
* ATT_EXECUTE_WRITE_RSP or ATT_ERROR_RSP (if an error occurred on
* the server).
*
* Note: This sub-procedure is complete when either ATT_PREPARE_WRITE_RSP
* (with bleTimeout status), ATT_EXECUTE_WRITE_RSP (with SUCCESS
* or bleTimeout status), or ATT_ERROR_RSP (with SUCCESS status)
* is received by the calling application task.
*
* Note: The 'pReq->pValue' pointer will be freed when the sub-procedure
* is complete.
*
* @param connHandle - connection to use
* @param pReq - pointer to request to be sent
* @param taskId - task to be notified of response
*
* @return SUCCESS: Request was sent successfully.<BR>
* INVALIDPARAMETER: Invalid connection handle or request field.<BR>
* MSG_BUFFER_NOT_AVAIL: No HCI buffer is available.<BR>
* bleNotConnected: Connection is down.<BR>
* blePending: A response is pending with this server.<BR>
* bleMemAllocError: Memory allocation error occurred.<BR>
* bleTimeout: Previous transaction timed out.<BR>
*/


extern bStatus_t GATT_WriteLongCharValue( uint16 connHandle, attPrepareWriteReq_t *pReq, uint8 taskId );

我自己写了一个串口函数,用来实现主从机串口透传数据,函数如下所示:


static void NpiSerialCallback( uint8 port, uint8 events )
{
    (void)port;

    if (events & (HAL_UART_RX_TIMEOUT | HAL_UART_RX_FULL))
    {
        uint8 numBytes = 0;
        numBytes = NPI_RxBufLen();
        uint8 *buffer = osal_mem_alloc(numBytes);

        if(buffer)
        {
            NPI_ReadTransport(buffer, numBytes);
            HalLcdWriteString((char*)buffer, HAL_LCD_LINE_7);
            
            if (connectedPeripheralNum == 0)
            {
                simpleBLE_AT_CMD_Handle(buffer, numBytes);
            }
            else
            {
                for (int i = 0; i < connectedPeripheralNum; i++)
                {
                    BLE_DEV *p = &(gDev[i]);
                    
                    if ( (numBytes > 2 && buffer[numBytes-2] == '\r' && buffer[numBytes-1] == '\n') &&
                              ( ((numBytes == 9) && str_cmp(buffer, "AT+TERM\r\n", 9)) ||
                                ((numBytes == 10) && str_cmp(buffer, "AT+RESET\r\n", 10)) ) )
                    {
                        simpleBLE_AT_CMD_Handle(buffer, numBytes);
                    }
                    else if ( p->simpleBLEDoWrite && (p->simpleBLEState == BLE_STATE_CONNECTED) )
                    {
                        uint8 status;
                        gattPrepareWriteReq_t longWriteReq;
                        
                        longWriteReq.pValue = osal_mem_alloc(numBytes);
                        longWriteReq.len = numBytes;
                        osal_memcpy(longWriteReq.pValue, buffer, numBytes);
                        longWriteReq.offset = 0;
                        longWriteReq.handle = p->simpleBLECharHdl[BLE_CHAR6];//0x35;
                        status = GATT_WriteLongCharValue(p->simpleBLEConnHandle, &longWriteReq, simpleBLETaskId);
                        if(status != SUCCESS)
                        {
                            NPI_PrintValue("Write Error :", status, 10);
                        }
                    }
                    else //(p->simpleBLEState != BLE_STATE_CONNECTED)
                    {
                        if (numBytes > 2 && buffer[numBytes-2] == '\r' && buffer[numBytes-1] == '\n')
                        {
                            simpleBLE_AT_CMD_Handle(buffer, numBytes);
                        }
                    }
                }
            }

            //NPI_WriteTransport(buffer, numBytes);
            osal_mem_free(buffer);
        }
    }
}
但是测试的时候总是出错,错误码22,我想问一下,是不是 gattPrepareWriteReq_t 结构体内容填充错误,还是 GATT_WriteLongCharValue 调用错误。
另外,调用 GATT_WriteCharValue 时,从机产生 simpleProfileChangeCB 回调,处理接收的数据;
那么调用 GATT_WriteLongCharValue 时,从机接收到数据之后如何处理,还是 simpleProfileChangeCB 回调吗?

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top