Beware that this post is related to an SDK in maintenance mode
More Info: Consider nRF Connect SDK for new designs
This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

How to synchronize application with radio notifications?

Hello,

I'm using nRF52840 devboards and am running the NUS-examples on two devboards (peripheral and central) with SoftDevice S140 (SDK 17.0.2). 

I want to synchronize my application code (sending on the peripheral side) with the radio to enhance data throughput and further implement a FreeRTOS sending task.

My idea is:

  • Configure Radio Notifications on active radio event with a distance of 800 us before the actual event
  • Give a FreeRTOS task notification in the radio-event-ISR to the sending task to indicate that the radio is going the be active soon
  • Implement a sending task which accesses the data-to-send in a queue and pends on that task notification given by the active radio event ISR

The code is something like that:

BLE_HANDLING_ERROR_CODE radioNotificationInit()
{
    sd_nvic_ClearPendingIRQ(SWI1_IRQn);
    
    sd_nvic_SetPriority(SWI1_IRQn, 3);
    
    sd_nvic_EnableIRQ(SWI1_IRQn);
    
    /* Configure the radio notification event */
    sd_radio_notification_cfg_set(NRF_RADIO_NOTIFICATION_TYPE_INT_ON_ACTIVE, NRF_RADIO_NOTIFICATION_DISTANCE_800US);
}

void SWI1_IRQHandler(bool radio_active)
{
    vTaskNotifyGiveFromISR(xbleCommTaskHandle, NULL);
}

void vbleCommunicationTask(void * pvParameters)
{
    while(1)
    {
      if(ulTaskNotifyTake(pdTRUE, portMAX_DELAY))
      {
          /* Send data now */
          do
          {
            returnValue = ble_nus_data_send(&m_nus, sendDataArray, &sendIndex, m_conn_handle);
          
            if ((returnValue != NRF_ERROR_INVALID_STATE) && 
                (returnValue != NRF_ERROR_RESOURCES) &&
                (returnValue != NRF_ERROR_NOT_FOUND))
            {
              // Something went clearly wrong here
            }
            
          } while (returnValue == NRF_ERROR_RESOURCES);
        }
      }
    }
}

The data array is something like that:

#define BLE_NUS_MAX_DATA_LEN (NRF_SDH_BLE_GATT_MAX_MTU_SIZE - OPCODE_LENGTH - HANDLE_LENGTH)

static uint8_t sendDataArray[BLE_NUS_MAX_DATA_LEN]; ///< This is for testing purposes only since it is NOT THREADSAFE!

The define NRF_SDH_BLE_GATT_MAX_MTU_SIZE is set to the maximum size of 247.

So the basic idea behind this is, each time the radio becomes active, the application can send all the pending data and no ressources are wasted. The actual communication and the radio notifications are working properly with my configuration.

Now my problem: The throughput is completely inconsistent with this approach. Sometimes data is send properly; sometimes nothing is sent and after a few seconds the communication starts to send properly again. I tried to change the notification distance but it doesn't help. 

Is there anything wrong with this approach in principle? What's the way to go to synchronize sending with radio notifications?

Best Regards,

Dominik

Parents
  • Hello,

    I don't quite understand your setup. What role does the radio notification have?

    From where is the vbleCommunicationTask() triggered? (it may be that you said it, but my FreeRTOS knowledge is not the best). 

    Why do you need to synchronize the queuing of data to 800µs before the connection event? And what do you see from the throughput? What does ble_nus_data_send() usually return? Do you see that it sometimes returns more NRF_ERROR_RESOURCES? Or how does it behave when the throughput is inconsistent? 

  • Thanks Edvin, 

    The idea is that the radio notification indicates that a connection event will occur soon (800µs before the event), so that the application can send all its queued data (since the last connection event) to the ble stack for sending. 

    The task is waiting (pending, but without CPU interaction) in line 5 for the task notification which is given by the radio notification ISR. So this means that the task will be woken when there will be a connection event (the data is queued by another task). 

    I will check what ble_nus_data_send() usually returns.

    Does the NRF_ERROR_RESOURCES error mean that there is currently no connection event ongoing?

    In general:

    What I wan't to achieve is a maximum throughput with BLE (I'm already on 2Mbit PHY) and I don't really know how to achieve this. I thought that synchronizing the application with the radio like this is the way to go.

    Do you have any other tips to achieve high throughput? I studied the maximum throughput example and have adjusted most of the suggested parameters (DLE, CI = 50ms, 2MbitPHY, MTU=247).

  • Dominik Weber said:
    Does the NRF_ERROR_RESOURCES error mean that there is currently no connection event ongoing?

     No. The NRF_ERROR_RESOURCES means that your softdevice queue is full, and you have to wait for at least one of the packets to be successfully transmitted and Aacked before you can queue another packet. This will not happen until the next connection event (800µs after the radio notification.

    Maximizing the throughput is a quite common question here on DevZone. Try to search on it. If you look at the softdevice specification: Bluetooth Low Energy Throughput, you can see that the maximum possible theoretical throughput is ~1.3Mbps, using the parameters that you are using. The throughput can be increased a little bit by increasing the connection interval, but it is also more sensitive to packet loss. 

    In order to increase the throughput you need to enable Data Length Extention, and make sure that your softdevice queue is full at all times (or at least when the connection event occurs). The softdevice queue is full when ble_nus_data_send() returns NRF_ERROR_RESOURCES. NB: The last packet, that returned NRF_ERROR_RESOURCES was not queued. 

    The ble_app_uart + ble_app_uart_c example pair is throughput optimized, I think. I you send dummy data (all zero's) from your main-loop while it returns NRF_SUCCESS, and just count the length of the packets received by the central, you can use a timer to calculate the throughput. NB: Don't print the data on UART. That is slow, and your application will not be able to handle the incoming data correctly.

    BR,

    Edvin

Reply
  • Dominik Weber said:
    Does the NRF_ERROR_RESOURCES error mean that there is currently no connection event ongoing?

     No. The NRF_ERROR_RESOURCES means that your softdevice queue is full, and you have to wait for at least one of the packets to be successfully transmitted and Aacked before you can queue another packet. This will not happen until the next connection event (800µs after the radio notification.

    Maximizing the throughput is a quite common question here on DevZone. Try to search on it. If you look at the softdevice specification: Bluetooth Low Energy Throughput, you can see that the maximum possible theoretical throughput is ~1.3Mbps, using the parameters that you are using. The throughput can be increased a little bit by increasing the connection interval, but it is also more sensitive to packet loss. 

    In order to increase the throughput you need to enable Data Length Extention, and make sure that your softdevice queue is full at all times (or at least when the connection event occurs). The softdevice queue is full when ble_nus_data_send() returns NRF_ERROR_RESOURCES. NB: The last packet, that returned NRF_ERROR_RESOURCES was not queued. 

    The ble_app_uart + ble_app_uart_c example pair is throughput optimized, I think. I you send dummy data (all zero's) from your main-loop while it returns NRF_SUCCESS, and just count the length of the packets received by the central, you can use a timer to calculate the throughput. NB: Don't print the data on UART. That is slow, and your application will not be able to handle the incoming data correctly.

    BR,

    Edvin

Children
No Data
Related