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

Sending lots of data using notifications in a loop, data rate slows down after few seconds? (FreeRTOS based app)

Hello,

this question has been probably asked many times, but I could not find any good matches using the search.

My setup: I am using nRF52832, latest SDK 16.0.0 and a test application based on the FreeRTOS HRS example from the SDK.

I want to test sending lots of data from the peripheral to the central using notifications. To do this, I have tweaked the HRS example a little. Normally the example updates the HRS data once per second. I have basically just increased the rate of the updates to get more data sent over the air.

I have tried two approaches:

1) configure the timer to use 10ms (100Hz) interval, i.e. make it run 100x faster than in the original example

2) send one notification once the central has subscribed to notifications, then trigger each subsequent notification to the BLE_GATTS_EVT_HVN_TX_COMPLETE event received from stack

With both solutions, I have the same problem: initially, the data transfer seems quite fast, but after running a few seconds (maybe 5 sec?) the data transfer always slows down considerably, to a rate that is something like one notification per second.

I have checked that the ble_hrs_heart_rate_measurement_send() function does not return any error code when the slowdown happens.

Any ideas where to start looking for reason for the slowdown? If the stack buffers are becoming full, then I would expect to get some error code when trying to send a new notification.

I first tried with 75ms connection interval and then changed the value to 7.5 ms. Using smaller interval results in fast data rate, but only during the first ~5 seconds after which it slows down a lot.

Is there perhaps some issues in the FreeRTOS based example that makes it not suitable for throughput testing? I am not looking to reach very high data rates right now, I would be happy to get the notifications running stable at roughly 100 Hz, 8 bytes per packet which corresponds to 6400 bps. 

EDIT: more info about the problem. The slow down always happens at the same time, about 4 seconds after starting sending data. It is not random but very deterministic. And the distance between the two devices is very short, about 30 cm. Because of this, I would assume that after pushing lots of data for a few seconds there is some internal buffer that becomes full and that is causing the slowdown...

EDIT2: slowing down the transmit interval from 100Hz to 10Hz did not really help. First 4-5 seconds the data is transmitted at steady pace, then something causes a major slowdown. And eventually after 10-20 secs there is a supervision timeout and connection drops. 

Parents
  • Argh... after some hair pulling I found out that the FreeRTOS example is changing connection parameters on the fly. And the first change occurs at 5 seconds mark. I don't get it, what is the point of adding this kind of hidden features in the examples. For me, it just complicates things and causes unnecessary confusion.

    This is the relevant piece of code of the FreeRTOS HRS main.c ->

    /**@brief Function for initializing the Connection Parameters module. */
    static void conn_params_init(void)
    {
        ret_code_t             err_code;
        ble_conn_params_init_t cp_init;
    
        memset(&cp_init, 0, sizeof(cp_init));
    
        cp_init.p_conn_params                  = NULL;
        cp_init.first_conn_params_update_delay = FIRST_CONN_PARAMS_UPDATE_DELAY;
        cp_init.next_conn_params_update_delay  = NEXT_CONN_PARAMS_UPDATE_DELAY;
        cp_init.max_conn_params_update_count   = MAX_CONN_PARAMS_UPDATE_COUNT;
        cp_init.start_on_notify_cccd_handle    = m_hrs.hrm_handles.cccd_handle;
        cp_init.disconnect_on_fail             = false;
        cp_init.evt_handler                    = on_conn_params_evt;
        cp_init.error_handler                  = conn_params_error_handler;
    
        err_code = ble_conn_params_init(&cp_init);
        APP_ERROR_CHECK(err_code);
    }

    Value of FIRST_CONN_PARAMS_UPDATE_DELAY is set to 5000ms. 

    I think I'll try to strip the entire "connection parameters" module from the code, I don't see any use for this kind of clutter.

Reply
  • Argh... after some hair pulling I found out that the FreeRTOS example is changing connection parameters on the fly. And the first change occurs at 5 seconds mark. I don't get it, what is the point of adding this kind of hidden features in the examples. For me, it just complicates things and causes unnecessary confusion.

    This is the relevant piece of code of the FreeRTOS HRS main.c ->

    /**@brief Function for initializing the Connection Parameters module. */
    static void conn_params_init(void)
    {
        ret_code_t             err_code;
        ble_conn_params_init_t cp_init;
    
        memset(&cp_init, 0, sizeof(cp_init));
    
        cp_init.p_conn_params                  = NULL;
        cp_init.first_conn_params_update_delay = FIRST_CONN_PARAMS_UPDATE_DELAY;
        cp_init.next_conn_params_update_delay  = NEXT_CONN_PARAMS_UPDATE_DELAY;
        cp_init.max_conn_params_update_count   = MAX_CONN_PARAMS_UPDATE_COUNT;
        cp_init.start_on_notify_cccd_handle    = m_hrs.hrm_handles.cccd_handle;
        cp_init.disconnect_on_fail             = false;
        cp_init.evt_handler                    = on_conn_params_evt;
        cp_init.error_handler                  = conn_params_error_handler;
    
        err_code = ble_conn_params_init(&cp_init);
        APP_ERROR_CHECK(err_code);
    }

    Value of FIRST_CONN_PARAMS_UPDATE_DELAY is set to 5000ms. 

    I think I'll try to strip the entire "connection parameters" module from the code, I don't see any use for this kind of clutter.

Children
  • what is the point

    I think the point is that often you'd like to connect using a fairly short interval, so that the initial data exchange, potentially including a lengthy service discovery, happens fast. Then switch to the interval you actually want to use.

    But I do agree that the way it is done in many examples is pretty 'hidden'.

  • I agree that there could be some use for this like you said, to speed up the service discovery for example and then switch to slower interval to save power. 

    However, in my experience it is typically the central that should be responsible for this. For example, when testing with an Android phone (OnePlus 5) I've noticed that when I connect to a peripheral, the phone (i.e. the central) is toggling the connection parameters in the beginning. Having toggling on the peripheral side seems a bit odd for me, and in worst case both the central and the peripheral can be requesting connection parameter updates which would result in a mess.

    Now that I found the hidden feature in the example it is easy to fix, but it cost me 1-2 hours of extra debugging time.

Related