Option for better throughput with BLE multi-link/multi-role

Hello everyone,

I’m trying to concurrently transmit data from two separate BLE devices to a smartphone. After reading several posts and other resources, the following are two different configurations that I probably use. I have several questions regarding these configurations before going to implement:

  1. Each BLE peripheral device has 1 or 2 biosensors and I wanted to send it continuously, say 32 bytes with minimum sampling rate of 250 samples/second. For both configurations, are they able to send that amount of data with that data rate to smartphone’s app without any data loss?
  2. I saw an example of Configuration 1 demonstrated at Nordic youtube video and it has a sample code using phone app to turn on/off LED from the peripheral devices. However, I’m not sure if it has high throughput or not. Between the two configurations, which one is easier to implement?
  3. Looking at the config #2, seems it will be more on the phone app to be able to connect, and then collect data from two BLE peripheral devices. Any suggestions/ comments if it’s more doable and flexible to work?

Parents
  • Hi Tai, 

    Each BLE peripheral device has 1 or 2 biosensors and I wanted to send it continuously, say 32 bytes with minimum sampling rate of 250 samples/second. For both configurations, are they able to send that amount of data with that data rate to smartphone’s app without any data loss?

     There is no data loss in BLE as each packet is ACKed before it transfers the next packet. If a packet is loss it will be retransmitted.

    It's possible to handle 32*250'8 = 64kbps with BLE. You can take a look at this: https://www.youtube.com/watch?v=K1ItqEZ2_tw

    I don't see much point of having configuration 1 except for that it can operate can collect data without the present of the phone. In configuration #2 you would need to have the phone in proximity of the device to be able to collect data. 

    With configuration 1, you can think of some solution to store and compress data before transfer the data to the phone. 

  • Thank you anh! Regarding the ease of programing for each approach, I found several tutorials and examples for multlink/multlink-multirole application (config #1), it seems complicated. Should I go with that approach? Or you think the config #2 is more approachable although I'm a newbie in IOS development? Thanks!

  • Hi Tai, 
    It can be slightly more complicated with approach #1. Configure a node to support multilink is not too complicated. The complicated part is on how you store data,  organize them, then prepare for request from the phone to send it. So unless you have a benefit of collecting data independently from the phone (which can't guarantee always available compare to a dedicated nRF52 board), then no point doing approach 1. 

  • Thanks anh!

    I'll spend a week or so working on the approach #1 to see how feasible it would be. I'm going to tackle with by following 3 steps:

    • Step 1: Connect and send data from 2 peripheral devices using nRF52832 to a central device using nRF52840. These will use NUS service.
    • Step 2: Work on configuring for nRF52840 acting multi-role (both central and peripheral role).
    • Step 3: Work on IOS app to receive data when nRF52840 acting as a peripheral device.

    Regarding step #1, I was able to connect and send data from peripheral devices to nRF52840 with central role. I'm using an app_timer (I modify ble_app_uart example) to periodically send data to nRF52840 every 1 second for both peripheral devices. At the central one, I'm using ble_app_uart_c multilink on Nordic github. I was able to receive data correctly at nRF52840. I have 3 questions in step #1.     please bare with me on these questions.

    • Question 1: If 2 peripheral devices are turned on at the same time and they're advertising, the central device couldn't connect any of the devices and it showed an error message regarding the service discovery. If I just turn off both peripheral devices, turn on the central one and let it connect to 1st peripheral device, then 2nd perpheral device. Error didn't happen.

    • This error happened when the BLE_GAP_EVT_CONNECTED event triggers and the db discovery starts working as shown in the following code (I just copied the function causing the error only - error happened at line 16).

    static void ble_evt_handler(ble_evt_t const * p_ble_evt, void * p_context)
    {
        ret_code_t            err_code;
        ble_gap_evt_t const * p_gap_evt = &p_ble_evt->evt.gap_evt;
    
        switch (p_ble_evt->header.evt_id)
        {
            case BLE_GAP_EVT_CONNECTED:
                err_code = ble_nus_c_handles_assign(&m_ble_nus_c[p_ble_evt->evt.gap_evt.conn_handle], p_ble_evt->evt.gap_evt.conn_handle, NULL);
                APP_ERROR_CHECK(err_code);
    
                err_code = bsp_indication_set(BSP_INDICATE_CONNECTED);
                APP_ERROR_CHECK(err_code);
    
                // start discovery of services. The NUS Client waits for a discovery result
                err_code = ble_db_discovery_start(&m_db_disc, p_ble_evt->evt.gap_evt.conn_handle);
                APP_ERROR_CHECK(err_code);
    
                if (ble_conn_state_central_conn_count() < NRF_SDH_BLE_CENTRAL_LINK_COUNT)
                {
                    // Resume scanning.
                    scan_start();
                }
                break;
        }

    • Please advise how to make the scanning process and connecting with multiple peripheral devices more flexible. 

    • Question 2: Although I was able to receive correct data at nRF52840, a warning keeps popping up as shown in the following figure.

    • This warning was derived from this function at ble_nus_c service

    uint32_t ble_nus_c_string_send(ble_nus_c_t * p_ble_nus_c, uint8_t * p_string, uint16_t length)
    {
        VERIFY_PARAM_NOT_NULL(p_ble_nus_c);
    
        nrf_ble_gq_req_t write_req;
    
        memset(&write_req, 0, sizeof(nrf_ble_gq_req_t));
    
        if (length > BLE_NUS_MAX_DATA_LEN)
        {
            NRF_LOG_WARNING("Content too long.");
            return NRF_ERROR_INVALID_PARAM;
        }
        if (p_ble_nus_c->conn_handle == BLE_CONN_HANDLE_INVALID)
        {
            NRF_LOG_WARNING("Connection handle invalid.");
            return NRF_ERROR_INVALID_STATE;
        }
    
        write_req.type                        = NRF_BLE_GQ_REQ_GATTC_WRITE;
        write_req.error_handler.cb            = gatt_error_handler;
        write_req.error_handler.p_ctx         = p_ble_nus_c;
        write_req.params.gattc_write.handle   = p_ble_nus_c->handles.nus_rx_handle;
        write_req.params.gattc_write.len      = length;
        write_req.params.gattc_write.offset   = 0;
        write_req.params.gattc_write.p_value  = p_string;
        write_req.params.gattc_write.write_op = BLE_GATT_OP_WRITE_CMD;
        write_req.params.gattc_write.flags    = BLE_GATT_EXEC_WRITE_FLAG_PREPARED_WRITE;
    
        return nrf_ble_gq_item_add(p_ble_nus_c->p_gatt_queue, &write_req, p_ble_nus_c->conn_handle);
    }

    • Please advise if I need to do anything with connection handle and how to clear this warning?

    • Question 3: As I mentioned earlier, I was able connect and transmit data to the central device. Is there anyway to know which data is from a specific peripheral device. I know that in connecting process, connection handle for each peripheral will be saved and this is done in ble_nus_c_evt_handler and ble_evt_handler function. How can I utilize this to distinguish data sent to the central device from different peripheral.

  • Hi Tai, 


    We won't be able to step to your code and debug every issue. 
    My suggestion is to look at the example that already available. 
    For a device that act as both peripheral and central please look at : 
    \ble_central_and_peripheral\experimental\ble_app_hrs_rscs_relay

    When you see an error please look for the function that throwing the error and the error_code. 
    Then you can look at the function description to see what could be the reason for the error. 
    For example if the function is sd_ble_gatts_hvx(), and the error is NRF_ERROR_BUSY you can read the reason for it in the description:

Reply
  • Hi Tai, 


    We won't be able to step to your code and debug every issue. 
    My suggestion is to look at the example that already available. 
    For a device that act as both peripheral and central please look at : 
    \ble_central_and_peripheral\experimental\ble_app_hrs_rscs_relay

    When you see an error please look for the function that throwing the error and the error_code. 
    Then you can look at the function description to see what could be the reason for the error. 
    For example if the function is sd_ble_gatts_hvx(), and the error is NRF_ERROR_BUSY you can read the reason for it in the description:

Children
Related