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

How to increase notification throughput on nRF52840?

Hello there,

I'm developing a C++ application on the BLE654 development bord which shall be able to generate and send 100+ BLE notifications per second on a single BLE connection.

On my first try it managed 5.

After some digging, I found that the soft device (s140, Ver 6.1.0) got a BLE_GAP_EVT_CONN_PARAM_UPDATE event, which set the minimum and maximum connection interval to 200 ms, wich was the defined MAX_CONN_INTERVAL (the code burrowed from the blinky example). After setting this to 20 ms I could get (close to) 50 notifications per second, but further decreasing the value again reduced the throughput (maybe the Android on the 'other side' of the BLE connection prohibited a further decrease).

I read somewere that soft devices from s120 up were able to process up to 6 notifications in a 7.5 ms connectipon interval, but here it looks as is the sd only does one notification per interval. What can/must be done to further increase the througput to reach at least 100 notifications per second?

Notes:

-in our application, we send the notifications with sd_ble_gatts_hvx(). I don't have exact numbers, but the internal queue of the soft device seemd rather small and we got a NRF_ERROR_RESOURCES error quickly, after wich we wait for a BLE_GATTS_EVT_HVN_TX_COMPLETE until we call sd_ble_gatts_hvx() again. I am certain the soft device at all time had notifications in its queue.

-as recipient of the notifications we used two tablets with Android 6.0.1 and 7.0, respectively. Both showed similar throughputs, and the final application shall also run on an Android device.

Regards,

     Lasse

Parents
  • There is no functionality in the SoftDevice to put together small packets to larger packets, unfortunately. You will have to do this in the application. So you have to collect the data that you want to send in larger packs, before you send them to the softdevice. The limit of the size of the pack is defined by the MTU size of the connection. 

    I don't know what SDK version you use, but at least in the later SDKs, v15.0.0 and later, the ble_app_uart example is initialized with maximum MTU. The actual MTU, though, is dependent on the connected device. If it is a fairly new mobile phone, you will usually get an MTU of about 180B, but if it is connected to another nRF (with the ble_app_uart_c example) you will get the maximum possible MTU of 247.

    You can see the actual MTU in the gatt_evt_handler(), which will update the m_ble_nus_max_data_len in the ble_app_uart example.

    If you change the application to send messages based on UART input, but instead send packets from the main-loop, you can test the throughput.

    In this example, you can use ble_nus_data_send() with arrays of size m_ble_nus_max_data_len, and send them until you get the return value NRF_ERROR_RESOURCES. This means that your queue is full. Then you must wait for the BLE_GATTS_EVT_HVN_TX_COMPLETE event (you must add this to the ble_evt_handler() ), which means that a packet has been ACKed, and you can queue another.

    Best regards,

    Edvin

  • Hi Edvin,

    I'm using SDK 15.2.0.

    I've tried to integrate the nus from the ble_uart_example into my code. However it didn't work as expected, since the notifications I send were truncated after 20 Byte. This is the same behaviour i got with a normal notification and the sd_ble_gatts_hvx() function. After digging through the nus code, I saw that it essentially boils down to calling the sd_ble_gatts_hvx(), so this is not a big surprise after all.
    I may have overlooked something, but at this point I cannot see why I should need the nus - I could as well hand the array in which I accumulated the data to sd_ble_gatts_hvx() directly.

    Either way, the 20 byte border kills this approach.

    These are the parameters I've used:

    #define NRF_SDH_BLE_GAP_DATA_LENGTH 251
    #define NRF_SDH_BLE_GATT_MAX_MTU_SIZE 247
    #define NRF_SDH_BLE_GATTS_ATTR_TAB_SIZE 14080

    After negotiation, the mtu size was still 247 byte.

    Any more Ideas?

    Best regards,

         Lasse

  • Hi Edvin,

    I wasn't able to use the your application with our first tablet (it always lost connection during service discovery), but it worked with the 2nd one.

    this is what I got:

    The line beginning with "Es ist der Vater" was send from the dev kit to the tablet; more than 20 Bytes received, all fine.

    However, when I compile and run the example code, i get the following:

    The red error message occured wehin I tried to send data to the device (not good, but not my main concern). The "Er erreicht" line was send from the device to the tablet. it is longer than 20 Bytes, but only the first 20 Byte are shown in the application.

    What have you done that I am missing?

    Note: In these screenshots I used two different DVK-BL654 boards, but I also tried it on the same board. The results were the same (your App worked, mine not).

  • Oh. sorry again. I forgot to mention that the log backend is RTT. Can you check it with the RTT viewer? The same as I used in an earlier reply.

    Can you enable RTT logging on your project as well, and then check the RTT output on both applications?

    You can find RTT viewer here, if you don't have it already. 

    BR,

    Edvin

  • Hello Edvin,

    Your test_app_2.hex' application produced the following output:

    <info> app: Connected
    <info> nrf_ble_gatt: server_rx_mtu = 247, p_link->att_mtu_desired = 247
    <info> app: Data len is set to 0xF4(244)

    My application gave me

    ATT MTU exchange completed. central 0xf7 peripheral 0xf7

    Best regards,

         Lasse

  • Ok. So then we know that the phone supports more than MTU = 247 bytes, and it is actually updating to it.

    In the part that you have imported from the ble_app_uart example, can you see if you can find out where it complains after 20 bytes? Do you get the return value NRF_SUCCESS (=0) if you try to send more than 20 bytes?

    If it does, can you try to set a breakpoint on sd_ble_gatts_hvx() and look at the parameters that you are sending? Is the array larger than 20? Is p_len larger than 20?

    Is it possible to do a sniffer log of the connection?

    BR,

    Edvin

  • Hi Edvin,

    it doesn't complain. It always returns NRF_SUCCESS.

    p_len is 86 Byte (I'm trying a fixed string at the moment), the array is fine.

    I can't sniff the BLE connection. I've tried to get the sniffer software running on two different PCs, but each time anything didn't work (usually the sniffer wasn't visible in wiresharks main window).

    I willl try a third time.

    Best regards,

         Lasse

Reply
  • Hi Edvin,

    it doesn't complain. It always returns NRF_SUCCESS.

    p_len is 86 Byte (I'm trying a fixed string at the moment), the array is fine.

    I can't sniff the BLE connection. I've tried to get the sniffer software running on two different PCs, but each time anything didn't work (usually the sniffer wasn't visible in wiresharks main window).

    I willl try a third time.

    Best regards,

         Lasse

Children
  • The nRF Sniffer is a bit buggy if everything isn't correct with the segger versions. Did you remember to flash the sniffer-DK with the firmware for nRF Sniffer?

    If it still doesn't show up, try to close it and open it again (Wireshark), and it usually shows up after a few tries. Also remember to reset the DK after programming. Turn it off and on to be sure.

    Sorry that this description isn't very good. I usually have to close and open Wireshark a couple of times myself, but because it works eventually, I haven't looked into why it doesn't show up.

    You can try to update to the latest version of nRF Connect. Have you tested the nRF Connect app for mobile by the way? It looks ilke your screenshots is from nRF Toolbox, is that correct?

    BR,

    Edvin

  • Hi Edvin,

    we have tried to get the sniffer working on three PC by now, but we had no success. We have followed the instructions as well as the steps in the troubleshooting chapter, but we couldn't find an error. And yes, we tried multiple times.

    The screenshot was from the Toolbox, yes. I also have the Connect app, though.

  • Ok. But when you try to send one single string of length 80 bytes, or even longer, what is shown in nRF Connect? do you see the entire string?

    BR,

    Edvin

  • Hi Edvin,

    Using nRF Connect I see the same *censored* 20 Bytes I saw with any other application so far.

    However, there is something curious: If I use the "Request MTU" command from the Menu besides "SERVER" to increase the MTU to x Bytes, nRF Connect shows x-3 Bytes (the header, I know) of my string. That's great, but...

    -The gatt_evt_handler() of my device still says that the nRF Connect requested 0xF7 Bytes regardless of the Value I entered. I have no confirmation that the actual x Value was send to the device.

    -Only the first time I use "Request MTU" triggers the gatt_evt_handler(). I have to dis- and reconnect the device for it to trigger the gatt_evt_handler() again.

    -If I increase the MTU twice (i.e to 40 and then 60 Bytes) the nRF Connect still only shows 37 Bytes. If I increase and then decrease the MTU (i.e to 40 ant then 30 Bytes) the nRF Connect doesn't show any new notifications (allthoug it will again if i increase the MUT back to 40 or more).

    Do you know if this behaviour is a (misunderstood) feature or a bug in the nRF Connect?

    I'd love to send you a sniffer log of this, but still, we can't get the sniffer to work.

    Best regards,

         Lasse

  • Hello Lasse,

    I am sorry, but I am starting to loose track of where we are. Your phone supports a higher MTU, and the ble_app_uart example from SDK15.2.0 does as well, so there is something missing from your project that is not allowing it, I think. 

    Do you have gatt_init as in the ble_app_uart example?

    void gatt_init(void)
    {
        ret_code_t err_code;
    
        err_code = nrf_ble_gatt_init(&m_gatt, gatt_evt_handler);
        APP_ERROR_CHECK(err_code);
    
        err_code = nrf_ble_gatt_att_mtu_periph_set(&m_gatt, NRF_SDH_BLE_GATT_MAX_MTU_SIZE); //247
        APP_ERROR_CHECK(err_code);
    }

    What is your NRF_SDH_BLE_GAP_EVENT_LENGTH in sdk_config.h?

    Can you compare your gatt values from the log in the ble_app_uart example and your example?

    In both projects, set #define NRF_LOG_DEFAULT_LEVEL 4 in sdk_config.h, and make sure you are looking at the log, and not the uart output in ble_app_uart. You need to check the RTT log.

    Try to send a string larger than 20 bytes using the ble_app_uart example. You should see a string longer than 20 *cencored* bytes in the mobile application. Do you see a string longer than this in your example?

Related