<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="https://devzone.nordicsemi.com/cfs-file/__key/system/syndication/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Maximizing Notification throughput</title><link>https://devzone.nordicsemi.com/f/nordic-q-a/62608/maximizing-notification-throughput</link><description>I&amp;#39;m attempting to transfer 256K bps (1 244-byte notification every ~7.5ms) using an nRF52840 using Notifications and am not getting close to the necessary bandwidth. I&amp;#39;m getting the (dreaded) NRF_ERROR_RESOURCES error and have a few questions about the</description><dc:language>en-US</dc:language><generator>Telligent Community 13</generator><lastBuildDate>Fri, 26 Jun 2020 16:23:42 GMT</lastBuildDate><atom:link rel="self" type="application/rss+xml" href="https://devzone.nordicsemi.com/f/nordic-q-a/62608/maximizing-notification-throughput" /><item><title>RE: Maximizing Notification throughput</title><link>https://devzone.nordicsemi.com/thread/257191?ContentTypeID=1</link><pubDate>Fri, 26 Jun 2020 16:23:42 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:2a336065-bed6-4886-83af-7c2f422f390a</guid><dc:creator>CktDesigner</dc:creator><description>&lt;p&gt;Hi Sigurd,&lt;/p&gt;
&lt;p&gt;Here is a summary of where I&amp;#39;m at:&lt;/p&gt;
&lt;p&gt;The following defines have been modified in sdk_config.h&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;#define NRF_SDH_BLE_GAP_DATA_LENGTH 251&lt;/p&gt;
&lt;p&gt;#define NRF_SDH_BLE_GAP_EVENT_LENGTH 320&lt;/p&gt;
&lt;p&gt;#define NRF_SDH_BLE_GATT_MAX_MTU_SIZE 247&lt;/p&gt;
&lt;p&gt;I call:&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="c_cpp"&gt;void connEvtLenExtSet(bool onOff) {
  ret_code_t err_code;
  ble_opt_t opt;

  memset(&amp;amp;opt,0,sizeof(opt));
  opt.common_opt.conn_evt_ext.enable= onOff ? 1 : 0;

  err_code= sd_ble_opt_set(BLE_COMMON_OPT_CONN_EVT_EXT, &amp;amp;opt);
  APP_ERROR_CHECK(err_code);
}&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;after gap and gatt are initialized:&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="c_cpp"&gt;
    // Configure and initialize the BLE stack.
    ble_stack_init();

    // Initialize modules.
    timers_init();
    buttons_leds_init(&amp;amp;erase_bonds);
    gap_params_init();
    gatt_init();
    //dataLenExtSet();
    connEvtLenExtSet(true);
    advertising_init();
    services_init();
    sensor_simulator_init();
    conn_params_init();
    peer_manager_init();

    // Initialize the Queues
    bleNotificationsWritten= 0;
    bleNotificationsSent= 0;
    bleNotificationsFailed= 0;
    bleNotificationsReceived= 0;
    bleNotificationsAvailable= BLE_GATTS_HVN_TX_QUEUE_SIZE_DEFAULT;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;I update the Phy to 2MBPS using:&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="c_cpp"&gt;void updatePhy(uint16_t handle) {
  ret_code_t err_code;
  ble_gap_phys_t phys = {
    //.tx_phys = BLE_GAP_PHY_2MBPS | BLE_GAP_PHY_1MBPS,
    //.rx_phys = BLE_GAP_PHY_2MBPS | BLE_GAP_PHY_1MBPS

    .tx_phys = BLE_GAP_PHY_2MBPS,
    .rx_phys = BLE_GAP_PHY_2MBPS
  };
  NRF_LOG_DEBUG(&amp;quot;PHY update set.&amp;quot;);

  err_code= sd_ble_gap_phy_update(handle, &amp;amp;phys);
  APP_ERROR_CHECK(err_code);
}&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;This is called after the connection is established:&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="c_cpp"&gt;        case BLE_GAP_EVT_CONNECTED:
            NRF_LOG_INFO(&amp;quot;Connected&amp;quot;);
            err_code = bsp_indication_set(BSP_INDICATE_CONNECTED);
            APP_ERROR_CHECK(err_code);
            m_conn_handle = p_ble_evt-&amp;gt;evt.gap_evt.conn_handle;
            err_code = nrf_ble_qwr_conn_handle_assign(&amp;amp;m_qwr, m_conn_handle);
            APP_ERROR_CHECK(err_code);
            updatePhy(m_conn_handle);
            break;
&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;I keep track of the number of notifications being processed using the variable &amp;quot;bleNotificationsAvailable&amp;quot;.&amp;nbsp; &amp;nbsp;It is initialized to BLE_GATTS_HVN_TX_QUEUE_SIZE_DEFAULT (which is set to 20).&lt;/p&gt;
&lt;p&gt;This variable is incremented by the number of notifications sent in the BLE callback:&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="c_cpp"&gt;
        case BLE_GATTS_EVT_HVN_TX_COMPLETE:
            bleNotificationsSent= bleNotificationsSent + p_ble_evt-&amp;gt;evt.gatts_evt.params.hvn_tx_complete.count;
            bleNotificationsAvailable= bleNotificationsAvailable + p_ble_evt-&amp;gt;evt.gatts_evt.params.hvn_tx_complete.count;
            NRF_LOG_DEBUG(&amp;quot;HVN_TX_COMPLETE: Packets: %d&amp;quot;,p_ble_evt-&amp;gt;evt.gatts_evt.params.hvn_tx_complete.count);
            // Wake the Send process
            xTaskNotify(SendTaskHandle,SEND_PACKET_QUEUED,eSetBits);
            break;

        case BLE_GATTS_EVT_HVC:
            bleNotificationsReceived++;
            break;
&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;and decremented when a notification is sent.&lt;/p&gt;
&lt;p&gt;Since Notifications can be sent by multiple sensors,&amp;nbsp; the &amp;quot;send&amp;quot; code is consolidated in one FreeRTOS task.&amp;nbsp; This is the body of that task:&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="c_cpp"&gt;for (;;) {
    // Block until something appears in the queue...
    // Only bit that should cause Notification is SEND_PACKET_QUEUED, so don&amp;#39;t even check...
    xTaskNotifyWait(0x00,             // Don&amp;#39;t clear any bits on entry
                    ~0x00,            // Clear all bits on exit
                    &amp;amp;bleSendNotifyBits,
                    portMAX_DELAY);   // Block indefinitely
    
    // While there is space in the BLE queue AND there are packets to send...
    while(    (bleNotificationsAvailable &amp;gt; 2) 
           &amp;amp;&amp;amp; (uxQueueMessagesWaiting(characteristicQueue) &amp;gt; 0) ) {
      // Still room in TX QUEUE and a characteristic is waiting in the queue
      // Read the queue item
      xStatus= xQueueReceive(characteristicQueue,&amp;amp;charToSend,0);
      if( xStatus == pdPASS ) {	// Read from queue was successful
        ble_gatts_hvx_params_t hvx_params;

        memset(&amp;amp;hvx_params, 0, sizeof(ble_gatts_hvx_params_t));

        size                   = charToSend.size;

        hvx_params.handle      = charToSend.charHandle;
        hvx_params.type        = BLE_GATT_HVX_NOTIFICATION;
        hvx_params.offset      = 0;
        hvx_params.p_len       = &amp;amp;size;
        hvx_params.p_data      = charToSend.charPtr;

        err_code= sd_ble_gatts_hvx(charToSend.connHandle,&amp;amp;hvx_params);
        // size will reflect the number of bytes sent
        if(    (err_code == NRF_SUCCESS)
            &amp;amp;&amp;amp; (charToSend.size == size)
          ) {
          bleNotificationsAvailable--;
        } else {
          bleNotificationsFailed++;
          NRF_LOG_DEBUG(&amp;quot;Packet Send Failure: %d : %d&amp;quot;,err_code,bleNotificationsAvailable);
          break;
          //APP_ERROR_CHECK(err_code);
        }
      } else {
        break;
      }
    }
  }&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;This task sends Notifications as long as there is TX queue space available and as long as a notification is present in the queue (from other tasks that handle sensors).&amp;nbsp; &amp;nbsp; I thought using this code would eliminate getting NRF_ERROR_RESOURCES errors, but I still get them.&amp;nbsp; &amp;nbsp; There aren&amp;#39;t as many when I use shorter connect intervals (7.5).&amp;nbsp; &amp;nbsp;Here is the code where this is set:&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="c_cpp"&gt;#define MIN_CONN_INTERVAL                   MSEC_TO_UNITS(7.5, UNIT_1_25_MS)        /**&amp;lt; Minimum acceptable connection interval (0.4 seconds). */
#define MAX_CONN_INTERVAL                   MSEC_TO_UNITS(650, UNIT_1_25_MS)        /**&amp;lt; Maximum acceptable connection interval (0.65 second). */
&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;I thought perhaps there was some sort of race condition, so increased the comparison (as shown above) for the number of free TX queue entries to 2.&amp;nbsp; &amp;nbsp; So when I activate the &amp;quot;Send&amp;quot; Task, there should be at least 2 free TX queue slots or no call to sd_ble_gatts_hvn should be made.&amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;However, I still get a lot of debug print statements indicating packet failures with NRF_ERROR_RESOURCES and supposedly 16 empty TX queue slots.&lt;/p&gt;
&lt;p&gt;For completion, here is the code for a testing task that sends packets (about every 7.5 ms).&amp;nbsp; The Notifications are about 244 bytes in size:&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="c_cpp"&gt;    // Send value if connected and notifying
    if (service-&amp;gt;conn_handle != BLE_CONN_HANDLE_INVALID) {

        charQueueItem          thisChar;

        thisChar.connHandle      = service-&amp;gt;conn_handle;
        thisChar.charHandle      = service-&amp;gt;mic_data_handles.value_handle;
        thisChar.size            = sizeof(micDataCharacteristic);
        thisChar.charPtr         = (uint8_t *)charToSend;

        // Send the packet info
        xStatus= xQueueSendToBack(characteristicQueue, &amp;amp;thisChar, 0);
        if(xStatus != pdPASS ) {
          itemsInQueue= uxQueueMessagesWaiting(characteristicQueue);
          //fprintfsock(&amp;quot;Could not send MIC packet to the queue.\n&amp;quot;);
          while(1);
        }
        // Increment the written count
        bleNotificationsWritten++;
        // Wake the Send process
        xTaskNotify(SendTaskHandle,SEND_PACKET_QUEUED,eSetBits);

    } else {
        err_code = NRF_ERROR_INVALID_STATE;
    }&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;This creates a FreeRTOS queue item that includes information about the connection handle, the characteristic handle, a pointer to the characteristic value to be sent, etc. and sends it to the queue.&amp;nbsp; &amp;nbsp;It also wakes the Send task to actually send the notification if conditions permit.&amp;nbsp; &amp;nbsp; &amp;nbsp;If the notification can&amp;#39;t be sent, the queue item won&amp;#39;t be consumed.&amp;nbsp; &amp;nbsp;When a BLE_GATTS_EVT_HVN_TX_COMPLETE arrives, the bleNotificationsAvailable variable is updated and the Send Task is notified to check if anything should be sent.&lt;/p&gt;
&lt;p&gt;I didn&amp;#39;t expect to see the NRF_ERROR_RESOURCES.&amp;nbsp; &amp;nbsp;Are there any other conditions (besides the TX QUEUE being overrun) that I should consider?&amp;nbsp; &amp;nbsp;My variable indicates that there are 16 slots available when the error occurs.&lt;/p&gt;
&lt;p&gt;I am attempting to receive the notifications on a Samsung S8 running Android 9.&amp;nbsp; &amp;nbsp;I have used LightBlue, nRF Connect, and my own Android app as receiving apps (central) and all do pretty much the same thing.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;What am I doing wrong???&lt;/p&gt;
&lt;p&gt;Thanks!&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: Maximizing Notification throughput</title><link>https://devzone.nordicsemi.com/thread/256045?ContentTypeID=1</link><pubDate>Sat, 20 Jun 2020 21:20:46 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:2efc8875-2cb6-494d-a0a7-8b35560f3d3f</guid><dc:creator>CktDesigner</dc:creator><description>&lt;p&gt;Another update:&lt;/p&gt;
&lt;p&gt;1.&amp;nbsp; &amp;nbsp;I had increased the TX_QUEUE size by modifying BLE_GATTS_HVN_TX_QUEUE_SIZE_DEFAULT to 20 in ble_gatts.h.&amp;nbsp; &amp;nbsp; I thought perhaps doing it dynamically might have a better outcome, so I changed the #define back to 1 and used the code segment:&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="c_cpp"&gt;    // Increase the TX QUEUE size
    ble_cfg_t ble_cfg;
    memset(&amp;amp;ble_cfg, 0, sizeof ble_cfg);
    ble_cfg.conn_cfg.conn_cfg_tag = APP_BLE_CONN_CFG_TAG;
    ble_cfg.conn_cfg.params.gatts_conn_cfg.hvn_tx_queue_size = 20;
    err_code = sd_ble_cfg_set(BLE_CONN_CFG_GATTS, &amp;amp;ble_cfg, ram_start);
    APP_ERROR_CHECK(err_code);&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;to attempt to increase it.&amp;nbsp; &amp;nbsp; This resulted in an error that there was not enough memory, so I switched back to setting the QUEUE size to 20 in the .h file.&lt;/p&gt;
&lt;p&gt;2. Using the code in the earlier post, I attempted to run with my emulator sending one 244 byte Notification every 7.6 ms.&amp;nbsp; &amp;nbsp;Many of the notifications don&amp;#39;t get sent because sd_ble_gatts_hvx returns error 19 (NRF_ERROR_RESOURCES) even though the variable I maintain that tracks the number of TX queue entries shows there should be 16 empty queue positions (per an NRF_LOG_DEBUG message that logs the err_code and bleNotificationsAvailable variable.)&lt;/p&gt;
&lt;p&gt;3. I&amp;#39;m using a Samsung S8 phone (BLE 5.x) to receive (as the central) and set the phy to 2MBPS in the peripheral when the BLE_GAP_EVT_CONNECTED is received.&amp;nbsp; &amp;nbsp; With the MIN_CONN_INTERVAL set to 7.5 ms, a significant number of packets don&amp;#39;t get sent.&amp;nbsp; &amp;nbsp; I increased the MIN_CONN_INTERVAL to 50 ms and even more packets don&amp;#39;t get set.&lt;/p&gt;
&lt;p&gt;Are there other resources that must be increased when the TX QUEUE size is increased?&lt;/p&gt;
&lt;p&gt;Thanks...&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: Maximizing Notification throughput</title><link>https://devzone.nordicsemi.com/thread/256007?ContentTypeID=1</link><pubDate>Fri, 19 Jun 2020 17:08:51 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:d9ac5b3b-ee87-4023-99ec-e1e7bd984e63</guid><dc:creator>CktDesigner</dc:creator><description>&lt;p&gt;Hi Sigurd,&lt;/p&gt;
&lt;p&gt;I&amp;#39;m a bit confused on what I&amp;#39;m seeing.&amp;nbsp; &amp;nbsp;I though that I was following the procedure outlined in sd_ble_gatts_hvx documentation:&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;The application can keep track of the available queue element count for notifications by following the procedure below:&lt;/span&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Store initial queue element count in a variable.&lt;/li&gt;
&lt;li&gt;Decrement the variable, which stores the currently available queue element count, by one when a call to this function returns&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a class="el" href="https://infocenter.nordicsemi.com/topic/com.nordic.infocenter.s140.api.v7.0.1/group__nrf__error.html#ga7e6367efeaac363d8cf024940b4ec123"&gt;NRF_SUCCESS&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Increment the variable, which stores the current available queue element count, by the count variable in&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a class="el" href="https://infocenter.nordicsemi.com/topic/com.nordic.infocenter.s140.api.v7.0.1/group___b_l_e___g_a_t_t_s___e_n_u_m_e_r_a_t_i_o_n_s.html#ggae537647902af1b05c1e32f12d6b401c7afab96bfa9918017082235f7664919f9d"&gt;BLE_GATTS_EVT_HVN_TX_COMPLETE&lt;/a&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;event&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;My application has several sensors that can send Notifications, and I&amp;#39;m using FreeRTOS, so I created a small task that does nothing but collect (via a queue) notification requests from other tasks (that control the sensors) and send them.&amp;nbsp; &amp;nbsp;&lt;/p&gt;
&lt;p&gt;For testing purposes, I&amp;#39;m using a Samsung S8 running nRF Connect.as a Central.&lt;/p&gt;
&lt;p&gt;I set&amp;nbsp;BLE_GATTS_HVN_TX_QUEUE_SIZE_DEFAULT to 20 and maintain counters for packets written (notification requests), packets sent (notifications sent via sd_ble_gatts_hvx) and packet failures (errors from sd_ble_gatts_hvx - they are always NRF_ERROR_RESOURCES).&amp;nbsp; &amp;nbsp;I never see more than 1 packet sent (when BLE_GATTS_EVT_HVN_TX_COMPLETE is invoked).&lt;/p&gt;
&lt;p&gt;Here is the code for the body of the send task:&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="c_cpp"&gt;    // While there is space in the BLE queue AND there are packets to send...
    while(    (bleNotificationsAvailable &amp;gt; 2) 
           &amp;amp;&amp;amp; (uxQueueMessagesWaiting(characteristicQueue) &amp;gt; 0) ) {
      // Still room in TX QUEUE and a characteristic is waiting in the queue
      // Read the queue item
      xStatus= xQueueReceive(characteristicQueue,&amp;amp;charToSend,0);
      if( xStatus == pdPASS ) {	// Read from queue was successful
        ble_gatts_hvx_params_t hvx_params;

        memset(&amp;amp;hvx_params, 0, sizeof(ble_gatts_hvx_params_t));

        size                   = charToSend.size;

        hvx_params.handle      = charToSend.charHandle;
        hvx_params.type        = BLE_GATT_HVX_NOTIFICATION;
        hvx_params.offset      = 0;
        hvx_params.p_len       = &amp;amp;size;
        hvx_params.p_data      = charToSend.charPtr;

        if(xStatus == pdPASS) {
          err_code= sd_ble_gatts_hvx(charToSend.connHandle,&amp;amp;hvx_params);
          // size will reflect the number of bytes sent
          if(    (err_code == NRF_SUCCESS)
              &amp;amp;&amp;amp; (charToSend.size == size)
            ) {
            bleNotificationsAvailable--;
          } else {
            bleNotificationsFailed++;
            NRF_LOG_DEBUG(&amp;quot;Packet Send Failure: %d&amp;quot;,err_code);
            break;
            //APP_ERROR_CHECK(err_code);
          }
        }
      } else {
        break;
      }
    }&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Here is the code for an emulated sensor that attempts to send a packet every X ms.&amp;nbsp; &amp;nbsp;X needs to be about 7.5, but is currently set to 20 ms.&amp;nbsp; &amp;nbsp;It sends the packet information to the send task via the characteristicQueue.&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="c_cpp"&gt;    // Send value if connected and notifying
    if (service-&amp;gt;conn_handle != BLE_CONN_HANDLE_INVALID) {

        charQueueItem          thisChar;

        thisChar.connHandle      = service-&amp;gt;conn_handle;
        thisChar.charHandle      = service-&amp;gt;mic_data_handles.value_handle;
        thisChar.size            = sizeof(micDataCharacteristic);
        thisChar.charPtr         = (uint8_t *)charToSend;

        // Send the packet info
        xStatus= xQueueSendToBack(characteristicQueue, &amp;amp;thisChar, 0);
        if(xStatus != pdPASS ) {
          itemsInQueue= uxQueueMessagesWaiting(characteristicQueue);
          //fprintfsock(&amp;quot;Could not send MIC packet to the queue.\n&amp;quot;);
          while(1);
        }
        // Increment the written count
        bleNotificationsWritten++;
        // Wake the Send process
        xTaskNotify(SendTaskHandle,SEND_PACKET_QUEUED,eSetBits);

    } else {
        err_code = NRF_ERROR_INVALID_STATE;
    }&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Here is the code for that handles the BLE events:&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="c_cpp"&gt;
        case BLE_GATTS_EVT_HVN_TX_COMPLETE:
            bleNotificationsSent= bleNotificationsSent + p_ble_evt-&amp;gt;evt.gatts_evt.params.hvn_tx_complete.count;
            bleNotificationsAvailable= bleNotificationsAvailable + p_ble_evt-&amp;gt;evt.gatts_evt.params.hvn_tx_complete.count;
            //NRF_LOG_DEBUG(&amp;quot;HVN_TX_COMPLETE: Packets: %d&amp;quot;,p_ble_evt-&amp;gt;evt.gatts_evt.params.hvn_tx_complete.count);
            // Wake the Send process
            xTaskNotify(SendTaskHandle,SEND_PACKET_QUEUED,eSetBits);
            break;

        case BLE_GATTS_EVT_HVC:
            bleNotificationsReceived++;
            break;
&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Given the way things are set up, I didn&amp;#39;t expect to see any NRF_ERROR_RESOURCES errors since the logic should not attempt to initiate an sd_ble_gatts_hvx unless there are at least 2 empty slots available, but I do!&lt;/p&gt;
&lt;p&gt;Eventually, the code hits the &amp;quot;while(1)&amp;quot; statement as the Queue fills and no more entries can be added.&lt;/p&gt;
&lt;p&gt;Any thoughts on why I&amp;quot;m seeing NRF_ERROR_RESOURCES?&amp;nbsp; &amp;nbsp;Are there other conditions that cause this other than requests exceeding BLE_GATTS_HVX_TX_QUEUE_SIZE?&lt;/p&gt;
&lt;p&gt;Thanks!&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: Maximizing Notification throughput</title><link>https://devzone.nordicsemi.com/thread/255635?ContentTypeID=1</link><pubDate>Wed, 17 Jun 2020 21:45:18 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:5f5dd564-f69d-4a77-85b2-db4924eb0974</guid><dc:creator>CktDesigner</dc:creator><description>&lt;p&gt;OK, thanks!&amp;nbsp; &amp;nbsp; I think I&amp;#39;ve done all that you suggested, but still having problems.&amp;nbsp; &amp;nbsp;I&amp;#39;ll have to get another development board to try the nRF Sniffer.&amp;nbsp; &amp;nbsp; &amp;nbsp;I also need to try to better manage the Notification send requests.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: Maximizing Notification throughput</title><link>https://devzone.nordicsemi.com/thread/255304?ContentTypeID=1</link><pubDate>Tue, 16 Jun 2020 14:15:41 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:936af170-6fec-4613-a95b-f50cfed23839</guid><dc:creator>Sigurd</dc:creator><description>&lt;p&gt;Hi,&lt;/p&gt;
&lt;p&gt;1) It&amp;#39;s copied and&amp;nbsp;&lt;span&gt;queued internally.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;2) The packets are buffered and transmitted in the order they were queued.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;3) It can be increased further, but 247 will give you the max&amp;nbsp;throughput.&amp;nbsp;By setting&amp;nbsp;NRF_SDH_BLE_GAP_DATA_LENGTH = 251 (this is max), and&amp;nbsp;NRF_SDH_BLE_GATT_MAX_MTU_SIZE = 247, then we avoid fragmentation of the ATT packet into several on-air data packets.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;4) Yes.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;5) No. As far as I can see, it&amp;#39;s only a parameter to the event handler that you pass when the observer is registered. e.g. here only NULL is passed,&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt; &lt;pre class="ui-code" data-mode="text"&gt;// Register a handler for BLE events.
NRF_SDH_BLE_OBSERVER(m_ble_observer, APP_BLE_OBSERVER_PRIO, ble_evt_handler, NULL);&lt;/pre&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;6) We have a chapter about&amp;nbsp;throughput in the SDS, see &lt;a href="https://infocenter.nordicsemi.com/index.jsp?topic=%2Fsds_s140%2FSDS%2Fs1xx%2Fble_data_throughput%2Fble_data_throughput.html"&gt;this link&lt;/a&gt;. This &lt;a href="https://www.novelbits.io/bluetooth-5-speed-maximum-throughput/"&gt;blog-post from novel bits&lt;/a&gt; might be helpful as well.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;For increased throughput, I recommend increasing NRF_SDH_BLE_GAP_EVENT_LENGTH in sdk_config.h to e.g. 320, and enable connection event length extension.&lt;/p&gt;
&lt;p&gt;You can enable Connection Event Length Extension with a function like this:&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="text"&gt;void conn_evt_len_ext_set(bool status)
{
    ret_code_t err_code;
    ble_opt_t  opt;

    memset(&amp;amp;opt, 0x00, sizeof(opt));
    opt.common_opt.conn_evt_ext.enable = status ? 1 : 0;

    err_code = sd_ble_opt_set(BLE_COMMON_OPT_CONN_EVT_EXT, &amp;amp;opt);
    APP_ERROR_CHECK(err_code);

}
&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Then call conn_evt_len_ext_set(true) after you have enabled the SoftDevice.&lt;/p&gt;
&lt;p&gt;If you still are having issues with&amp;nbsp;&lt;span&gt;throughput, please do a sniffer trace with &lt;a href="https://www.nordicsemi.com/Software-and-tools/Development-Tools/nRF-Sniffer-for-Bluetooth-LE"&gt;nRF Sniffer&lt;/a&gt;.&lt;/span&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item></channel></rss>