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

Increase data transfer rate for nRF52840 for queued write

Hi

I am using the provided example ble_app_queued_writes to send 256 bytes in each call.

It is taking around 13 seconds to transfer 3136 bytes:

12 calls of 256 and one for 64. Around 1 second per transfer. This seems very slow to me.

I checked many posts on this site and refered the throughput and long range demo to make the data transfer faster.

I got slight improvement of a second overall when i made following changes:

1) Updated BLE_GAP_DATA_LENGTH_DEFAULT to 128 from 27 (Successful)

2) Updated 

MIN_CONN_INTERVAL to MSEC_TO_UNITS(10, UNIT_1_25_MS) (Successful)

MAX_CONN_INTERVAL to MSEC_TO_UNITS(20, UNIT_1_25_MS) (Successful)

Other useful changes sugested gives error once the hex is uploaded:

1) ATT MTU :  NRF_SDH_BLE_GATT_MAX_MTU_SIZE more than 23 results in error:

<warning> app: System reset
<info> app_timer: RTC: initialized.
<warning> nrf_sdh_ble: Insufficient RAM allocated for the SoftDevice.
<warning> nrf_sdh_ble: Change the RAM start location from 0x20002300 to 0x20002C80.
<warning> nrf_sdh_ble: Maximum RAM size for application is 0x3D380.
<error> nrf_sdh_ble: sd_ble_enable() returned NRF_ERROR_NO_MEM.
<error> app: Fatal error

2) When updating to BLE_GAP_PHY_2MBPS getting again System reset

I am using Iphone 8 Plus to transfer data: on printing character maximumWriteValueLength i get value as 512

SDK: nRF5_SDK_16.0.0_98a08e2

Kit: nRF52840-DK

Am i correct thinking using queued write will be the fasted way to transfer data in volume? Is updating MTU, DLE not possible with it?

Please advice how i can make the data transfer faster?

  • Hi Edvin,

    I am sending an Image data as bytes from my app in iOS (using iPhone 8 Plus):

    e.g. snipit

    {0x40,0x14,0x40,0x14,0x40,0x14,0xc0,0x0b,0xc0,0x0b.......}

    Data is sent in batch with 256 bytes per transmission. Taking around 2.5 mins for all data transfer.

    My gatt_init is the same as the example:

    /**@brief Function for initializing the GATT module.
     */
    static void gatt_init(void)
    {
        ret_code_t err_code = nrf_ble_gatt_init(&m_gatt, NULL);
        APP_ERROR_CHECK(err_code);
    }

    Please see the handler code below:

    static uint16_t queued_write_service_evt_handler(nrf_ble_qwrs_t     * p_qwrs,
                                                             nrf_ble_qwrs_evt_t * p_evt)
    {
        uint16_t ret_val = BLE_GATT_STATUS_SUCCESS;
        switch (p_evt->evt_type)
        {
            case BLE_QWRS_CHECK_RCVD_DATA:
                    ret_val =  BLE_GATT_STATUS_SUCCESS;
                break;//BLE_QWRS_CHECK_RCVD_DATA
    
            case BLE_QWRS_NEW_DATA_RCVD:
                // This is where the data is actually received and has been accepted.
                if(BUFFER_INDEX < 153600) {
                  memcpy(&screen_buffer[BUFFER_INDEX], &p_evt->rcvd_data[0], p_evt->rcv_length * sizeof(uint8_t));
                  BUFFER_INDEX = BUFFER_INDEX + p_evt->rcv_length;
                }
                
                if(BUFFER_INDEX == 153600) {
                  NRF_LOG_INFO("153600");
                  show_full_screen_image();
                  BUFFER_INDEX = 0;
                }
                break;//BLE_QWRS_NEW_DATA_RCVD
            default:
                // No implementation needed.
                break;
        }
    	NRF_LOG_FINAL_FLUSH();
        return ret_val;
    }

    I am not sure about your question:

    What is your m_ble_nus_max_data_len (or equivalent) after this callback?

    But i have set the max data length (251) in main as:

    data_len_set(251);
    advertising_start(erase_bonds);
    

    The functions definition is:

    void data_len_set(uint8_t value)
    {
        ret_code_t err_code;
        err_code = nrf_ble_gatt_data_length_set(&m_gatt, BLE_CONN_HANDLE_INVALID, value);
        APP_ERROR_CHECK(err_code);
    }

    Thanks

  • Look at the implementation of gatt_init() in the ble_app_uart example and add a callback like it is done there. Then look at what the callback says.

    You still failed to show me how you send data. Perhaps you can just upload the main.c file if you are not sure what I am asking for.

    What i am interrested in is how you queue up the data that you are sending. Where do you feed the  {0x40,0x14,0x40,0x14,0x40,0x14,0xc0,0x0b,0xc0,0x0b.......} data into to transmit it to the phone?

  • Hi Edvin, thanks for your reply. I will look at the ble_app_uart.

    I am not sending data from nRF52840 i am just receiving data in nRF52840-DK from iPhone app.

    I am storing the received data in buffer i.e. screen_buffer in function queued_write_service_evt_handler please see the code i posted in previous reply.

    Thanks

  • ok,

    Then the only remaining thing you need to check is that the event length is set to the maximum (equal to your connection interval) in order to maximize the efficiency. If you still see that it takes long to send, it is because of the phone application. You need to send the packets faster. If you are waiting for some sort of ACK before you send the next packet, skip that. Just queueu them up as fast as you can. I don't know how this is done on the phone side, so you probably know this better than me.

    If you were sending from the nRF, that then you should keep sending until it returns NRF_ERROR_RESOURCES. Perhaps it works similar on the phone side.

  • Hi Edvin,

    As per your advice i have updated the event length as:

    in main.c

    #define MIN_CONN_INTERVAL MSEC_TO_UNITS(7.5, UNIT_1_25_MS) 
    #define MAX_CONN_INTERVAL MSEC_TO_UNITS(30, UNIT_1_25_MS) 

    in sdk_config.h

    #ifndef NRF_SDH_BLE_GAP_EVENT_LENGTH
    #define NRF_SDH_BLE_GAP_EVENT_LENGTH 30
    #endif

    But i was able to see the slight difference in the speed, now instead of 2 mins and 30 seconds it is taking 2 min and 20 seconds to transfer the data. But still the performance is very poor.

    For the ACK, do you mean i need to send data without response? For this i have been going through the blogs and and articled on this site and found a tutorial  but it does not show how to implement it.

    So i changed char to write without response as, i hope this is the correct way?

    add_char_params.char_props.write_wo_resp = true;

    In another post i found was this and i implemented the following:

    ble_cfg.conn_cfg.params.gattc_conn_cfg.write_cmd_tx_queue_size = 25;


    static void ble_stack_init(void)
    {
        ret_code_t err_code;
    
        err_code = nrf_sdh_enable_request();
        APP_ERROR_CHECK(err_code);
    
        // Configure the BLE stack using the default settings.
        // Fetch the start address of the application RAM.
        uint32_t ram_start = 0;
        err_code = nrf_sdh_ble_default_cfg_set(APP_BLE_CONN_CFG_TAG, &ram_start);
        APP_ERROR_CHECK(err_code);
    
    //---- UPDATE START
    
        ble_cfg_t ble_cfg;
    
        memset(&ble_cfg, 0, sizeof(ble_cfg));
        ble_cfg.conn_cfg.conn_cfg_tag = APP_BLE_CONN_CFG_TAG;
        ble_cfg.conn_cfg.params.gattc_conn_cfg.write_cmd_tx_queue_size = 25;
    
        err_code = sd_ble_cfg_set(BLE_CONN_CFG_GATTC, &ble_cfg, ram_start);
        APP_ERROR_CHECK(err_code);
    
    //---- UPDATE END
    
        // Enable BLE stack.
        err_code = nrf_sdh_ble_enable(&ram_start);
        APP_ERROR_CHECK(err_code);
    
        // Register a handler for BLE events.
        NRF_SDH_BLE_OBSERVER(m_ble_observer, APP_BLE_OBSERVER_PRIO, ble_evt_handler, NULL);
    }

    I even disabled the logs #define NRF_LOG_ENABLED 0

    This gave me no performance change at all. I am bit stuck on this. Please can you help me on this? Do you have any sample program where nRF52840 can receive data fast atleast 20-30KBPS?

    On the iOS side i checked we are ok we are getting maximumWriteValueLength as 512, Also iPhone is writing data without response so i think the problem is in firmware side.

    I look forward for your reply. I am really stuck here with speed issue.

    Thanks

Related