Hi All,
I send larger amount of data through BLE (I know that it wasn't desinged for this purpose, but know I have to do this). Currently the connection parameters are:
- min. connection interval: 6 (7.25 msec)
- max connection itnerval: 6 (7.25 msec)
- slave latency: 0
Therefore the effective connection interval is 7.25 msec. I transfer data by using SimpleProfile_SetParameter, and the appropriate characteristic value is 16 bytes long. These suggest me that the transfer rate should be ~2 kB/s. However, I measured 70 B/s. There is some overhead caused by another operations, but it wouldn't cause this. My questions are:
- Are indications and notifications sent in the same connection event in which the actual data is transferred?
- Are confirmations sent back in the same connection event.
- The most important: what other bottlenecks can be there?
Thanks,
Gergo
Hi Gergo,
Do you have a USB sniffer? The first thing to check is that you are really getting 7.25msec connect interval. By default the connection starts at 100ms and you have to issue a connection update from the central device to change the connect interval e.g.
GAPCentralRole_UpdateLink(BLEConnHandle,5,5,0,1000);
You also need to ensure that the minimum connect interval on the peripheral side is less than equal to 5. I think this is the limit so you may want to try higher values to start.
In practice you might find a connect interval of 5 does not work or is hard to achieve if your system has other processing overhead (reading / writing flash etc). I found the link could be unreliable if the interval was too low.
As far as I know notifications can occur up to 4 times per interval, but confirmations for indications happen in the following timeslot - someone may be able to correct me here.
Hi Michael,
Thanks for your suggestion, the lack of GAPCentralRole_UpdateLink(...) was the (first) problem. I set the parameters on the GAP peripheral side and thought that it would take effect. Now the transfer rate is about 700 Bytes/s, which is ten times faster than previously, but still slower than 2,1 kBytes/s. Do you think that it can be obtained, or is this just a theoretical upper limit for the speed?
Now I am planning to change the GATT profile, too, and hope that it will multiply the speed by 4.
Best regards,
The theoretical speed for this settings ~10 Kbytes/sec, because in each connection event, up to 4 packets can be sent in each direction.
However, some messages, such as gatt write charachteristic are sequential, meaning only one message is sent in each connection event, afte a confirmation is recieved.
You can use GATT_WriteNoRsp API function to transfer data faster.
You can check with the sniffer how many messages are transferred on each connection event.
Hi Sasha,
As far as I know the GATT_WriteNoRsp is tipically used on the client side. However, usually I send larger amount of data in the opposite direction using SimpleProfile_SetParameter(...).
Do you think that the speed can be also improved in this case?
There are two ways to send data from the Peripheral (server) to the Central (Client). These are the client initiated "Read" and the sever initiated "Notify" (or "Indicate"). Which method are you using?
The SimpleProfile_SetParameter uses notifications (Notify) to send data back to the Central (client) side. I found that there was some additional work required to get notifications working on the client side.
Notifications do not require confirmation from the client so they should be as fast as GATT_WriteNoRsp in the opposite direction. I think reads are slower as they require a read request to be sent and the corresponding response to be returned.
Mike
Hi Mike,
I use both indications and notifications, but for separate characteristic values. Indications are used at a charvalue which is for transmitting larger amount of data. The mechanism is the following:
I havent used Indications before, but when I was using Write I was getting similar speeds to you. I moved to just using WriteNoRsp and Notify to send data each way. My application only sends data one way at a time & the application layer handles error checking and retries. I can move data at about 2KB/s but I may look at trying to optimize this further when I get the time
Have a look at our wiki on some throughput tests we've done: http://processors.wiki.ti.com/index.php/CC2540_Data_Throughput
Br
Thanks Nick,
In the link there is a comment: "When sending the notifications, a check is made to see if a buffer is available"
Can you please explain this a little further? Does this use the return code from the GATT_Notification call?
Hi,
So every 7ms, the function below is called 4 times,
So regardless of the connection interval, we are always trying to keep the buffer full, which is as you say checked by using the return command of the GATT_Notification().
Hi Nick,
This speed sounds promising, I am trying this solution.
I noticed that you call GATT_Notification() with 0 connHandle, could you explain this? I didn't find anything in the documentation regarding to this, and neither can imagine what a 0 connection handle means.
One more question: you use one characteristic value (with the handle 20) to send data 4 times in every 7 ms. I thought that it wasn't possible, can you explain this thing, too?
If you have several peripherals connected to a central device you would have internal pointers to each connection, called connection handles. The first connection is always enumerated as handle 0x0000, second connection 0x0001 and so on.
7ms is just a OSAL timer which is suppose to be less than the connection interval, so we always keep the output buffer full and thereby maximizing the throughput. since the minimum connection we usually recommend is 10ms you could just as well test 9ms OSAL timer. But if you'd like to test minimum possible connection interval of 7.5ms, you'd like to push as many packets (maximum allowed is currently 4) you can between every connection event, so they might be sent during the actual connection interval.
Again, the OSAL timer is just used to put packets in the output buffer, and the buffer is emptied upon the connection event.
BR
Thank you very much for your quick response, I've understood the concept, and I am changing my sources to work in this way.
Just one note: I see that you call the function int the following way: osal_memcpy( &nData.value, &burstData, 20 );. However, nData.value and burstData are both arrays, and therefore the operator '&' isn't needed for getting their adresses (which are expected as actual parameters for memcopy). Or did I miss something?
Senthi,
XDATA uses RAM (Not Flash), which the CC2540 and CC2541 has 8KB of. To get more info on this, have a look at section 4.2.4 in the Software Developers Guide (found here).