This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Slow Transfer - Calling ble_nus_string_send multiple times to send a large array

Hi all,

I am using PCA10040 with nRF5_SDK_14.2.0 and using the ble_app_uart example.

Basically I have a large array of size 18750 to send out and having read on the forum, I understand that I need to split up the data into smaller chunks and call ble_nus_string_send multiple times. Most people manage to get it to work by splitting into chuck of 20 bytes.

What I have tried so far is that I can provide a 150 byte array into the ble_nus_string_send function without any problem and its receiving well on a mobile phone. I also made a few changes:

#define MIN_CONN_INTERVAL MSEC_TO_UNITS(7.5, UNIT_1_25_MS) /**< Minimum acceptable connection interval (20 ms), Connection interval uses 1.25 ms units. */
#define MAX_CONN_INTERVAL MSEC_TO_UNITS(7.5, UNIT_1_25_MS) /**< Maximum acceptable connection interval (75 ms), Connection interval uses 1.25 ms units. */

Inside the gatt_init function, I also increase the max MUT size to 247:

err_code = nrf_ble_gatt_att_mtu_periph_set(&m_gatt, 247);

This is what I did in the main function:

// Enter main loop.
    for (;;)
    {
        UNUSED_RETURN_VALUE(NRF_LOG_PROCESS());
        power_manage();
			
				if(start_transfer)
				{
					start_transfer = false;
					uint16_t length = 150;
					uint8_t j = 0;
					uint16_t k = 0;
					for(j=0; j<125; j++)
					{
						do
						{	
							err_code = ble_nus_string_send(&m_nus, mybuffer+k, &length);
							if ( (err_code != NRF_ERROR_INVALID_STATE) && (err_code != NRF_ERROR_BUSY) )
							{
								APP_ERROR_CHECK(err_code);
							}
						} while (err_code == NRF_ERROR_BUSY);
						k = k + 150;
						while(!tx_complete);
						tx_complete = false;
					}
					
				}
    }

Each call to ble_nus_string_send, I am sending out 150 bytes, and I go this in a for loop that iterates for 125 times, so essentially I will transfer all 18750 bytes. After each call to ble_nus_string send, I am checking a flag tx_complete , which is set to true when a BLE_GATTS_EVT_HVN_TX_COMPLETE event happens. 

case BLE_GATTS_EVT_HVN_TX_COMPLETE:
	tx_complete = true;
	break;

This is working well except that the transfer seems to be still fairly slow about 19-20 seconds to send everything over. Is there anything I am doing wrong? How can I make this go much more faster?

Parents
  • New updates:

    I am able to achieve must faster transfer using the following parameters:

    ********************************

    #define MIN_CONN_INTERVAL MSEC_TO_UNITS(8, UNIT_1_25_MS) /**< Minimum acceptable connection interval (20 ms), Connection interval uses 1.25 ms units. */
    #define MAX_CONN_INTERVAL MSEC_TO_UNITS(20, UNIT_1_25_MS) /**< Maximum acceptable connection interval (75 ms), Connection interval uses 1.25 ms units. */

    err_code = nrf_ble_gatt_att_mtu_periph_set(&m_gatt, 64);

    ******************************

    Knowing that the data length has been updated to 123 from the debug output, I send out the data in block of 100 bytes.

    Am I correct to say that it doesn't matter what I set for the MUT size in this line:  err_code = nrf_ble_gatt_att_mtu_periph_set(&m_gatt, 64)" , because at the end of the day, the program will negotiate with the mobile device for a larger MUT and DLE?

    How do I determine what is the optimum value for the connection intervals and also the pack size to send in ble_nus_string_send to achieve the best throughput assuming I know the final data length that has been negotiated?

  • I would use this value, which is the max size of 247 bytes. With 3 bytes of overhead, that allows user data of up to 244 bytes per transmission.

        err_code = nrf_ble_gatt_att_mtu_periph_set(&m_gatt, NRF_SDH_BLE_GATT_MAX_MTU_SIZE);
    

    I find that even though the peripheral is using notifications, it is waiting for an ack from central, and central only sends out a single ack per connection interval. Therefore using a longer connection interval - which should be much more effient - actually slows down transmission. I get 6,000 bytes per second with both peripheral and central at 7.5 mSecs connection interval.

    This might clarify what's going on but it doesn't explain why the peripheral waits for an ack rather than just continually transmitting; I expect there is a simple setting for ack which we are missing. Sorry if I already posted this, it's my notes on timing. At 450 x 186-byte packets per second that gives 83,700 bytes per sec, somewhat less in practice..

    // This application uses a packet size of 186 bytes
    //
    // An integral number of packets can be sent in each connection interval using "Write Command". Shortest interval
    // is 7.5mSecs, longest 4,000mSecs in steps of 1.25mSecs
    // 7.5 mSec Connection Interval:
    //  1MHz: 2,116 uSecs @ 7.50mSecs -> 3.5 so maximum of 3 packets per connection interval, 400 packets/sec
    //  2MHz: 1,260 uSecs @ 7.50mSecs -> 5.9 so maximum of 5 packets per connection interval, 666 packets/sec
    // 40.0 mSec Connection Interval (proposed size):
    //  1MHz: 2,116 uSecs @ 40mSecs -> 18.9 so maximum of 18 packets per connection interval, 450 packets/sec
    //  2MHz: 1,260 uSecs @ 40mSecs -> 31.7 so maximum of 31 packets per connection interval, 775 packets/sec
    //
    // Theoretical Maximum 186-byte Packet Throughput - Packet Timing in uSecs, 40mSec Connection Interval
    //  1MHz: 2,116 uSec per packet -> less connection interval 0.9522 -> 2,222 usecs/pkt, 450 packets/sec
    //  2MHz: 1,260 usec per packet -> less connection interval 0.9765 -> 1,290 usecs/pkt, 775 packets/sec
    // Practical Maximum Throughput - quite a bit less, say 50%.
    //
    //    ---[Connection Interval j-1]---[Connection Interval j]---[Connection Interval j+1]---
    //                                  /                      \
    //                                /                          \
    //                             /                                \
    //                          /                                      \
    //                       /                                            \
    //                    /                                                  \
    //                 /                                                        \
    //              /                                                              \
    //           /                                                                    \
    //        /                                                                          \
    //        |<-------------- Packet Cycle --------------------------------------------->|
    //        |                    |  |       |  |                             |  |       |
    //      --[Master->Slave Packet]--[ IFS   ]--[Slave->Master Data Packet    ]--[ IFS   ]--[Master->Slave Packet]--
    //  1MHz: [10 octets -> 80uSec ]  [150uSec]  [217 octets -> 1,736uSecs     ]  [150uSec] -> 2,116 uSec/packet
    //  2MHz: [11 octets -> 88uSec ]  [150uSec]  [218 octets ->   872uSecs     ]  [150uSec] -> 1,260 usec/packet
    //                                         /                                 \
    //                                      /                                       \
    //                                   /                                             \
    //                                /                                                   \
    //                             /                                                         \
    //                          /                                                               \
    //                       /                                                                     \
    //                    /                                                                           \
    //                 /                                                                                 \
    //              /                                                                                       \
    //           /                                                                                             \
    //        /                                                                                                   \
    //     /                                                                                                         \
    //  /                                                                                                               \
    // |<------------------------------------------ Slave -> Master ECG Data Packet ------------------------------------>|
    // |                                                                                                                 |
    // +-----------------------------------------------------------------------------------------------------------------+
    // |                                            BLE Data Packet Min/Max/186-byte                                     |
    // +-----------------------------------------------------------------------------------------------------------------+
    // |                                     1MHz: 10/265/217 octets, 2MHz: 11/266/218 octets                            |
    // +----------+--------+--------------------------------------------------------------------------------------+------+
    // |          | Access |                                                                                      |      |
    // | Preamble | Address|         Protocol Data Unit PDU                                                       | CRCC |
    // +----------+--------+--------------------------------------------------------------------------------------+------+
    // |   1 (2)  |    4   |                                                   2-257                              |  3   |
    // |          |        +-----------+------------------------------------------------------------------+-------+      |
    // |          |        | LL Header |  Payload                                                         |  MIC  |      |
    // |          |        +-----------+------------------------------------------------------------------+ (opt) |      |
    // |          |        |   2       |                                       0-251                      |   4   |      |
    // |          |        |           +--------+---------------------------------------------------------+       |      |
    // |          |        |           | L2CAP  |                                                         |       |      |
    // |          |        |           | Header |  ATT Data                                               |       |      |
    // |          |        |           +--------+---------------------------------------------------------+       |      |
    // |          |        |           |   4    |                              0-247                      |       |      |
    // |          |        |           |        +-----+-------+-------------------------------------------+       |      |
    // |          |        |           |        | ATT | ATT   |                                           |       |      |
    // |          |        |           |        | Op  | Attrib|  ATT Payload                              |       |      |
    // |          |        |           |        +-----+-------+-------------------------------------------+       |      |
    // |  1 (2)   |   4    |  2        |   4    |  1  |  2    |                0-244                      |  (4)  |  3   |
    // +----------+--------+-----------+--------+-----+-------+-------------------------------------------+-------+------+
    //                                                        /                                           \
    //                                                      /                                               \
    //                                                    /                                                   \
    //                                                  /                                                       \
    //                                                /                                                           \
    //                                              /                                                               \
    //                                            |<-------------------- Payload 0-244 bytes ----------------------->|
    //
    //
    // Preamble is 1 byte for LE 1MHz (BLE 4.2) and 2 bytes for 2MHz (BLE 5.0). If the first bit of the ADDRESS is 0 the preamble
    // will be 0xAA otherwise 0x55.
    // The MIC field is optional used when we are using an encrypted connection
    

  • So my calculation above shows 83 Kbytes/sec using 186-byte packet, 1MHz phy, 40 mSecs connection interval. Testing these settings with a modified throughput test on two Nordic nRF52 dev boards (PCA10040) shows 141Kbytes/sec (1024 Kbytes in 7.4 seconds) - which is fast! Suspiciously fast, or is my calculation incorrect, not sure.

Reply Children
No Data
Related