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

How to achieve max throughput with NUS service?

Hi All.

I have a project where my peripheral (nRF52832) connects to my central (nRF52840), and then transmits 128 byte packets continuously one after the other. It works ok, but data rate is about 5,000 bytes per second max (40,000 bps). This seems a little low. I am using the following event to trigger the message, so this should be the quickest way to send one after the other?

case BLE_NUS_EVT_TX_RDY:

            send_data();

            break;

Send data;

void send_data(void)
{
    uint8_t testData[128];
    ret_code_t err_code;

    for (uint8_t i = 0; i < 128; i++) {
       testData[i] = i;
    }
    testData[0] = P0;
    testData[1] = P1;
    testData[2] = P2;
    testData[3] = page_count;


    //TODO - Add something here so if it fails X number of times, we stop download and disconnect 
    uint16_t length = (uint16_t)128;
    err_code = ble_nus_data_send(&m_nus, testData, &length, m_conn_handle);
    if(err_code == NRF_SUCCESS)
    {
      P1++;
      if(P1 == 0) P2++;
      page_count--;
    }
}

Also here are my settings for the radio times which seem to give the best results (same on both central and peripheral);

#define MIN_CONNECTION_INTERVAL   MSEC_TO_UNITS(7.5, UNIT_1_25_MS)      /**< Determines minimum connection interval in milliseconds. */
#define MAX_CONNECTION_INTERVAL   MSEC_TO_UNITS(10, UNIT_1_25_MS)       /**< Determines maximum connection interval in milliseconds. */
#define SLAVE_LATENCY             0                                     /**< Determines slave latency in terms of connection events. */
#define SUPERVISION_TIMEOUT       MSEC_TO_UNITS(4000, UNIT_10_MS)       /**< Determines supervision time-out in units of 10 milliseconds. */

#ifndef NRF_SDH_BLE_GAP_DATA_LENGTH
#define NRF_SDH_BLE_GAP_DATA_LENGTH 251
#endif

// <o> NRF_SDH_BLE_PERIPHERAL_LINK_COUNT - Maximum number of peripheral links. 
#ifndef NRF_SDH_BLE_PERIPHERAL_LINK_COUNT
#define NRF_SDH_BLE_PERIPHERAL_LINK_COUNT 1
#endif

// <o> NRF_SDH_BLE_CENTRAL_LINK_COUNT - Maximum number of central links. 
#ifndef NRF_SDH_BLE_CENTRAL_LINK_COUNT
#define NRF_SDH_BLE_CENTRAL_LINK_COUNT 0
#endif

// <o> NRF_SDH_BLE_TOTAL_LINK_COUNT - Total link count. 
// <i> Maximum number of total concurrent connections using the default configuration.

#ifndef NRF_SDH_BLE_TOTAL_LINK_COUNT
#define NRF_SDH_BLE_TOTAL_LINK_COUNT 1
#endif

// <o> NRF_SDH_BLE_GAP_EVENT_LENGTH - GAP event length. 
// <i> The time set aside for this connection on every connection interval in 1.25 ms units.

#ifndef NRF_SDH_BLE_GAP_EVENT_LENGTH
#define NRF_SDH_BLE_GAP_EVENT_LENGTH 6
#endif

// <o> NRF_SDH_BLE_GATT_MAX_MTU_SIZE - Static maximum MTU size. 
#ifndef NRF_SDH_BLE_GATT_MAX_MTU_SIZE
#define NRF_SDH_BLE_GATT_MAX_MTU_SIZE 247

I don't really understand the above settings to be honest, but from what I have read should give the best throughput. However 40kbps seems a bit slow considering both ends are nRF52 devices?

Thanks

Phil

Parents
  • Hi Phil

    The SoftDevice team wrote a nice guide on how to set connection parameters and stack configuration properly for good throughput, and I would suggest reading through that first. 

    The guide is available here

    If something is still unclear after reading through it just let me know, and I will do my best to help Slight smile

    Best regards
    Torbjørn

  • Thanks Torbjørn, I will take a look at that guide.

    I managed to boost the speed a fair bit by calling "ble_nus_data_send" in a while loop until its response doesn't equal NRF_SUCCESS rather than just once in the BLE_NUS_EVT_TX_RDY event.

    Ill try some other tweeks once I have read the guide.

    Thanks

    Phil

  • Hi Philip 

    I should probably have asked you about that. That is the right way to maximize throughput, by uploading data continuously until the error is returned. Once the ready event occurs you can then repeat the procedure, and once again upload as many packets as you can. 

    Best regards
    Torbjørn

  • Hi Torbjørn,

    The guide didn't help much. After tinkering with config settings I'm still getting about 80kbps now max, is that close to the best possible throughput between two nRF52 devices?

    Phil

  • Hi Torbjørn,

    I added a pin toggle when ever ble_nus_data_send happens, and monitored it on a scope. I send 64 packets of 240 bytes. It takes about 10mS per message, so it is only fitting one in each connection interval at the moment. Surely it should be able to get more than 1 packet into each 10mS interval?

     Phil

  • Hi Philip 

    You should definitely be able to get more than one packet pr connection interval. 

    Do you make sure to call ble_nus_data_send(..) in a loop (until it returns an error) every time the BLE_NUS_EVT_TX_RDY event occurs?

    Maybe you can share the code you implemented for doing this?

    Best regards
    Torbjørn

  • Hi, yes here is my send_data function, and also where it is called;

    void send_data(void)
    {
        uint8_t swimData[244];
    
        uint8_t test_counter = 0;
    
        ret_code_t err_code;
    
        //TODO - Add something here so if it fails X number of times, we stop download and disconnect 
        uint16_t length = (uint16_t)240;
    
        err_code = NRF_SUCCESS;
    
        test_counter = 0;
    
        while (err_code == NRF_SUCCESS & page_count != 0)
        {
            //TODO - Commented the read out to get throughput result without the delay of this.
            //Read_Data(240, P0, P1, P2, swimData); //start writing at byte 1 rather than 0. This means there are 5 bytes we can overwrite
    
            swimData[0] = test_counter;
            swimData[1] = P1;
            swimData[2] = P2;  //test_counter to see how many times this loops before failing
    
            //Have to send this so central knows when it has received the last packet of data i.e. page_count gets to zero
            swimData[3] = GET_HI_CHAR(page_count);
            swimData[4] = GET_LO_CHAR(page_count);
    
    test_counter++;
            err_code = ble_nus_data_send(&m_nus, swimData, &length, m_conn_handle);
            
            if(err_code == NRF_SUCCESS)
            {
              nrf_gpio_pin_toggle(TEST_PIN); //TODO - Test toggle this when sending so we can monitor with scope
    
              P1++;
              if(P1 == 0) P2++;
              page_count--;
            }
        }
    }

    And called from;

            case BLE_NUS_EVT_TX_RDY:
                //Try sending data here
    
                if(downloading == true & page_count != 0)
                {
                    send_data();
                }

    I thought maybe NRF_SDH_BLE_GAP_EVENT_LENGTH (which is 6) is not big enough to get another packet in the 10mS slot, so am trying to increase that also / experiment.

    Thanks

    Phil

Reply
  • Hi, yes here is my send_data function, and also where it is called;

    void send_data(void)
    {
        uint8_t swimData[244];
    
        uint8_t test_counter = 0;
    
        ret_code_t err_code;
    
        //TODO - Add something here so if it fails X number of times, we stop download and disconnect 
        uint16_t length = (uint16_t)240;
    
        err_code = NRF_SUCCESS;
    
        test_counter = 0;
    
        while (err_code == NRF_SUCCESS & page_count != 0)
        {
            //TODO - Commented the read out to get throughput result without the delay of this.
            //Read_Data(240, P0, P1, P2, swimData); //start writing at byte 1 rather than 0. This means there are 5 bytes we can overwrite
    
            swimData[0] = test_counter;
            swimData[1] = P1;
            swimData[2] = P2;  //test_counter to see how many times this loops before failing
    
            //Have to send this so central knows when it has received the last packet of data i.e. page_count gets to zero
            swimData[3] = GET_HI_CHAR(page_count);
            swimData[4] = GET_LO_CHAR(page_count);
    
    test_counter++;
            err_code = ble_nus_data_send(&m_nus, swimData, &length, m_conn_handle);
            
            if(err_code == NRF_SUCCESS)
            {
              nrf_gpio_pin_toggle(TEST_PIN); //TODO - Test toggle this when sending so we can monitor with scope
    
              P1++;
              if(P1 == 0) P2++;
              page_count--;
            }
        }
    }

    And called from;

            case BLE_NUS_EVT_TX_RDY:
                //Try sending data here
    
                if(downloading == true & page_count != 0)
                {
                    send_data();
                }

    I thought maybe NRF_SDH_BLE_GAP_EVENT_LENGTH (which is 6) is not big enough to get another packet in the 10mS slot, so am trying to increase that also / experiment.

    Thanks

    Phil

Children
Related