This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts
This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

dealing large data packet's through ble

Hi, I need to send(using BLE) large amount of data's, which are collected by the accelerometer sensor for 1 hour. I have an external NOR flash where the accelerometer data's are stored and from there data's are transmitted to the BLE stack when sync occurs. I am using nRF51822 nordic controller. Assume that, data size will be 50KB.

Regards, Balaji

Parents
  • The easiest way to send large amounts of data is to send them sequentially as notifications.

    Add a characteristic that is 20 bytes long and has the notify property. Split your data in 20 byte chunks and call sd_ble_gatts_hvx() repeatedly until you get the BLE_ERROR_NO_TX_BUFFERS back. At that time, wait until you get a BLE_EVT_TX_COMPLETE, at which point you again can send data until you get the BLE_ERROR_NO_TX_BUFFERS. Repeat until all data has been sent.

    Edit: Following is a code snippet that shows how this could be done:

    
    static void heart_rate_meas_send(void)
    {
        static uint32_t cnt = 0;
        uint32_t        err_code;
        uint16_t        heart_rate;
        
        while (true)
        {
            heart_rate = (uint16_t)ble_sensorsim_measure(&m_heart_rate_sim_state, &m_heart_rate_sim_cfg);
    
            cnt++;
            err_code = ble_hrs_heart_rate_measurement_send(&m_hrs, heart_rate);
            if (err_code == BLE_ERROR_NO_TX_BUFFERS ||
                err_code == NRF_ERROR_INVALID_STATE || 
                err_code == BLE_ERROR_GATTS_SYS_ATTR_MISSING)
            {
                break;
            }
            else if (err_code != NRF_SUCCESS) 
            {
                APP_ERROR_HANDLER(err_code);
            }
        
            // Disable RR Interval recording every third heart rate measurement.
            // NOTE: An application will normally not do this. It is done here just for testing generation
            //       of messages without RR Interval measurements.
            m_rr_interval_enabled = ((cnt % 3) != 0);
        }
    }
    
    

    and then in the event handler on_ble_evt:

    
            case BLE_EVT_TX_COMPLETE:
                heart_rate_meas_send();
                break;
    
    

    You'd also have to add a call to hear_rate_meas_send() somewhere after a connection has been established and the CCCD written, to actually start the transmission (or do something else that triggers a TX_COMPLETE).

    To maximize throughput, you'd also have to change the size of the characteristic to be 20 bytes. This is done by setting the max_len field of the ble_gatts_attr_t struct, and possibly vlen in ble_gatts_attr_md_t for the characteristic to be variable length. This is done on lines 228 and 237 in ble_hrs.c:

    
        attr_md.vlen       = 1;
        [...]
        attr_char_value.max_len      = MAX_HRM_LEN;
    
    
Reply
  • The easiest way to send large amounts of data is to send them sequentially as notifications.

    Add a characteristic that is 20 bytes long and has the notify property. Split your data in 20 byte chunks and call sd_ble_gatts_hvx() repeatedly until you get the BLE_ERROR_NO_TX_BUFFERS back. At that time, wait until you get a BLE_EVT_TX_COMPLETE, at which point you again can send data until you get the BLE_ERROR_NO_TX_BUFFERS. Repeat until all data has been sent.

    Edit: Following is a code snippet that shows how this could be done:

    
    static void heart_rate_meas_send(void)
    {
        static uint32_t cnt = 0;
        uint32_t        err_code;
        uint16_t        heart_rate;
        
        while (true)
        {
            heart_rate = (uint16_t)ble_sensorsim_measure(&m_heart_rate_sim_state, &m_heart_rate_sim_cfg);
    
            cnt++;
            err_code = ble_hrs_heart_rate_measurement_send(&m_hrs, heart_rate);
            if (err_code == BLE_ERROR_NO_TX_BUFFERS ||
                err_code == NRF_ERROR_INVALID_STATE || 
                err_code == BLE_ERROR_GATTS_SYS_ATTR_MISSING)
            {
                break;
            }
            else if (err_code != NRF_SUCCESS) 
            {
                APP_ERROR_HANDLER(err_code);
            }
        
            // Disable RR Interval recording every third heart rate measurement.
            // NOTE: An application will normally not do this. It is done here just for testing generation
            //       of messages without RR Interval measurements.
            m_rr_interval_enabled = ((cnt % 3) != 0);
        }
    }
    
    

    and then in the event handler on_ble_evt:

    
            case BLE_EVT_TX_COMPLETE:
                heart_rate_meas_send();
                break;
    
    

    You'd also have to add a call to hear_rate_meas_send() somewhere after a connection has been established and the CCCD written, to actually start the transmission (or do something else that triggers a TX_COMPLETE).

    To maximize throughput, you'd also have to change the size of the characteristic to be 20 bytes. This is done by setting the max_len field of the ble_gatts_attr_t struct, and possibly vlen in ble_gatts_attr_md_t for the characteristic to be variable length. This is done on lines 228 and 237 in ble_hrs.c:

    
        attr_md.vlen       = 1;
        [...]
        attr_char_value.max_len      = MAX_HRM_LEN;
    
    
Children
  • Thanks for this example. I got it working at 6580 bytes per second in a setup with a minimum connection interval of 10ms, and a timer interval of 10ms stuffing 20 bytes packets until it receives the BLE_ERROR_NO_TX_BUFFERS.

    Just what I needed :-)

  • Hi Ole,

    Thanks again for this excellent tutorial and example code. I tried it, and it greatly improved the achievable bandwidth.

    One problem I had was using this code was that I was missing every 7th packet. It seems that the while(1) above allows you an attempt to send 7 packets each connection interval, and the last one always fails. I got around this problem by checking to make sure I only attempt to send 6 packets (also using BLE_ERROR_NO_TX_BUFFERS to break me out of the loop), and my missing every 7th packet disappears.

    However, I still do miss the occasional packet, which I don't believe should happen given that notifications are still acked on the lower BLE layers (perhaps link layer?).

    What could I be doing wrong to be losing packets here?

    Thanks! Jamie

  • You should not be missing packets, but I can't think of anything obvious that could cause it. Can you please post this problem as a separate question, including all your code so that I can have a look? If you need confidentiality for the code, you can instead post a support case.

  • It's a little hard to read your code. Try the code tags next time :-)

    Anyway, it looks like you are incrementing values without being sure that the packet is actually sent. You should not increment the counters before the packet is sent successfully.

    After you have send the packet with "ble_hrs_heart_rate_measurement_send", you will have to check all the err_code conditions, and only when you have cleared all the checks, you can consider the packet as sent. This is where you can prepare the next packet, set of values or similar.

  • Thanks for the suggestions, KPE. I'll give only incrementing after an NRF_SUCCESS a try. I just figured that decrementing counters back if there was an BLE_ERROR_NO_TX_BUFFERS returned was equivalent.

    Regarding the code tag, the button for it doesn't seem to be available when commenting down in the thread like it is when you are starting a thread (formatting tools aren't shown?).

    Cheers, Jamie

Related