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

Data transfer time

Hi

I had this problem.
In my program, I send an archive with various data. I send the data using the notification. The central device is a smartphone with Android OS.
If you transfer data up to 10 packets, the smartphone normally receives them and displays the data. If the number of packets exceeds 10, then the remaining packets are no longer accepted, on the 10 packet, data reception is stopped. Data transfer is carried out as follows: after the connection, a timer is started, while the timer is interrupted, data is sent in a for loop. In this cycle, the data of the entire archive is divided into packets and the data transfer function is performed, therefore the delay between packets is minimal. The packet size does not matter, sent packets up to 200 bytes.
In order for the smartphone to be able to accept all packets, you must set a delay of at least 50 ms. before sending each package. If you set a delay with less time, then again the data does not come to the smartphone.

I also tried to send packets using the indication, and in this case, the transmission is normal, because the delay, due to the reverse response from the smartphone about the received data, is 75 ms.

I would like to know why the smartphone can not take a large number of packages? It may be necessary to have a minimum delay between packets or for some other reason.

Chip: BT840F (analog nRF52840);

SDK: nRF5_SDK_15.2.0;

Softdevice: s132_nrf52_6.1.0_softdevice;

Thanks in advance for the answer

Parents
  • Hi

    I do not have a sniffer, so I make a log on the phone.

    2021.hci_snoop20190424172643.cfa
    With the help of it, I understood the problem a little. The fact is that during the transfer I lost part of the packages, and if all the packages did not arrive on the phone, he did not send me a flag about the completion of the work. Because of this, it appeared that the program was hanging.
    About the data transfer. I have an archive of 12800 bytes. I form 200 byte packets and send them. Sending is done in a while (1) loop in the main program body. If you send packets without delay before each sending, then ~ 95% of packets are lost. To transfer the entire archive (64 packets) I need to set a delay of 25 ms. before sending each package.
    If the packet is lost, the sd_ble_gatts_hvx function generates an error NRF_ERROR_RESOURCES. I tried to send packets every time the BLE_GATTS_EVT_HVN_TX_COMPLETE event is executed, but then the delay between sending each packet is 75 ms, which is very much for my purposes.

    Can I somehow increase the transmission speed (that is, reduce the delay that I need to set) or is there a limitation due to the transfer of data to the phone?
    Here it is stated that the transfer for BLE 4.2 is 775 Kbps, but this is in the interaction between the two nRFs.

    I work within BLE 4.2, since it is this version that my phone supports

    Thanks in advance for the answer

  • I also wanted to clarify something.
    The total connection time of the peripheral device with the central and data transfer takes about 2800 ms. Separately, the connection takes ~ 850 ms., and data transmission ~ 1800 ms. The rest of the time is spent on data transmission from the central device, that the data is received and the time to disconnect the communication.
    From this it turns out that my bandwidth is equal to:

    Throughput = (64*200)/1800 = 7 kB/s.

    Is this the normal speed for transferring from nRF to a phone?

    I also have a phone with BLE v. 5.0. When setting up for transmission in PHY 2M, the result does not change at all, the transmission lasts the same 1800 ms. Also, if you reduce the delay before sending packets, packets will also be lost. Perhaps I am not correctly setting the transfer mode for BLE 5.0?

    static void ble_evt_handler(ble_evt_t const * p_ble_evt, void * p_context)
    {
      ret_code_t err_code = NRF_SUCCESS;
      
      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:
        {
          NRF_LOG_INFO("Handle Client (CON): %x", hadle_client);
          NRF_LOG_INFO("Connected.");
          action_evt = false;
          gap_phy_update(p_gap_evt, BLE_GAP_PHY_2MBPS, BLE_GAP_PHY_2MBPS);// Setting PHY
          min_int = p_ble_evt->evt.gap_evt.params.connected.conn_params.min_conn_interval;
          max_int = p_ble_evt->evt.gap_evt.params.connected.conn_params.max_conn_interval;
          NRF_LOG_INFO("Min int = %d, Max int = %d", min_int, max_int); 
            
          m_conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
          err_code = nrf_ble_qwr_conn_handle_assign(&m_qwr, m_conn_handle);
          APP_ERROR_CHECK(err_code);
        } break;
        
        ...
        
        case BLE_GAP_EVT_PHY_UPDATE_REQUEST:
        {
          NRF_LOG_DEBUG("PHY update request.");
          ble_gap_phys_t const phys =
          {
            .rx_phys = BLE_GAP_PHY_2MBPS,
            .tx_phys = BLE_GAP_PHY_2MBPS,
          };
          err_code = sd_ble_gap_phy_update(p_ble_evt->evt.gap_evt.conn_handle, &phys);
          APP_ERROR_CHECK(err_code);
        } break;
        
        case BLE_GAP_EVT_PHY_UPDATE:
        {
          ble_gap_evt_phy_update_t const * p_phy_evt = &p_ble_evt->evt.gap_evt.params.phy_update;
          ble_gap_phys_t phys = {0};
          phys.tx_phys = p_phy_evt->tx_phy;
          phys.rx_phys = p_phy_evt->rx_phy;
          NRF_LOG_INFO("PHY set to %s.", phy_str(phys));
        } break;
        
        ...
        
      }
    }
    
    
    void gap_phy_update(ble_gap_evt_t const * p_gap_evt, uint8_t rx_phy, uint8_t tx_phy)
    {
      ble_gap_phys_t const phys =
      {
        .rx_phys = rx_phy,
        .tx_phys = tx_phy,
      };
      uint32_t err_code = sd_ble_gap_phy_update(p_gap_evt->conn_handle, &phys);
      APP_ERROR_CHECK(err_code);
    }
    
    char const * phy_str(ble_gap_phys_t phys)
    {
        static char const * str[] =
        {
            "1 Mbps",
            "2 Mbps",
            "Coded",
            "Unknown"
        };
    
        switch (phys.tx_phys)
        {
            case BLE_GAP_PHY_1MBPS:
                return str[0];
    
            case BLE_GAP_PHY_2MBPS:
            case BLE_GAP_PHY_2MBPS | BLE_GAP_PHY_1MBPS:
            case BLE_GAP_PHY_2MBPS | BLE_GAP_PHY_1MBPS | BLE_GAP_PHY_CODED:
                return str[1];
    
            case BLE_GAP_PHY_CODED:
                return str[2];
    
            default:
                return str[3];
        }
    }

Reply
  • I also wanted to clarify something.
    The total connection time of the peripheral device with the central and data transfer takes about 2800 ms. Separately, the connection takes ~ 850 ms., and data transmission ~ 1800 ms. The rest of the time is spent on data transmission from the central device, that the data is received and the time to disconnect the communication.
    From this it turns out that my bandwidth is equal to:

    Throughput = (64*200)/1800 = 7 kB/s.

    Is this the normal speed for transferring from nRF to a phone?

    I also have a phone with BLE v. 5.0. When setting up for transmission in PHY 2M, the result does not change at all, the transmission lasts the same 1800 ms. Also, if you reduce the delay before sending packets, packets will also be lost. Perhaps I am not correctly setting the transfer mode for BLE 5.0?

    static void ble_evt_handler(ble_evt_t const * p_ble_evt, void * p_context)
    {
      ret_code_t err_code = NRF_SUCCESS;
      
      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:
        {
          NRF_LOG_INFO("Handle Client (CON): %x", hadle_client);
          NRF_LOG_INFO("Connected.");
          action_evt = false;
          gap_phy_update(p_gap_evt, BLE_GAP_PHY_2MBPS, BLE_GAP_PHY_2MBPS);// Setting PHY
          min_int = p_ble_evt->evt.gap_evt.params.connected.conn_params.min_conn_interval;
          max_int = p_ble_evt->evt.gap_evt.params.connected.conn_params.max_conn_interval;
          NRF_LOG_INFO("Min int = %d, Max int = %d", min_int, max_int); 
            
          m_conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
          err_code = nrf_ble_qwr_conn_handle_assign(&m_qwr, m_conn_handle);
          APP_ERROR_CHECK(err_code);
        } break;
        
        ...
        
        case BLE_GAP_EVT_PHY_UPDATE_REQUEST:
        {
          NRF_LOG_DEBUG("PHY update request.");
          ble_gap_phys_t const phys =
          {
            .rx_phys = BLE_GAP_PHY_2MBPS,
            .tx_phys = BLE_GAP_PHY_2MBPS,
          };
          err_code = sd_ble_gap_phy_update(p_ble_evt->evt.gap_evt.conn_handle, &phys);
          APP_ERROR_CHECK(err_code);
        } break;
        
        case BLE_GAP_EVT_PHY_UPDATE:
        {
          ble_gap_evt_phy_update_t const * p_phy_evt = &p_ble_evt->evt.gap_evt.params.phy_update;
          ble_gap_phys_t phys = {0};
          phys.tx_phys = p_phy_evt->tx_phy;
          phys.rx_phys = p_phy_evt->rx_phy;
          NRF_LOG_INFO("PHY set to %s.", phy_str(phys));
        } break;
        
        ...
        
      }
    }
    
    
    void gap_phy_update(ble_gap_evt_t const * p_gap_evt, uint8_t rx_phy, uint8_t tx_phy)
    {
      ble_gap_phys_t const phys =
      {
        .rx_phys = rx_phy,
        .tx_phys = tx_phy,
      };
      uint32_t err_code = sd_ble_gap_phy_update(p_gap_evt->conn_handle, &phys);
      APP_ERROR_CHECK(err_code);
    }
    
    char const * phy_str(ble_gap_phys_t phys)
    {
        static char const * str[] =
        {
            "1 Mbps",
            "2 Mbps",
            "Coded",
            "Unknown"
        };
    
        switch (phys.tx_phys)
        {
            case BLE_GAP_PHY_1MBPS:
                return str[0];
    
            case BLE_GAP_PHY_2MBPS:
            case BLE_GAP_PHY_2MBPS | BLE_GAP_PHY_1MBPS:
            case BLE_GAP_PHY_2MBPS | BLE_GAP_PHY_1MBPS | BLE_GAP_PHY_CODED:
                return str[1];
    
            case BLE_GAP_PHY_CODED:
                return str[2];
    
            default:
                return str[3];
        }
    }

Children
No Data
Related