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

NUS central example can't send more than 4 packets of 244 Bytes

Hi everybody,

I have some trouble fixing the ERROR 19 [NRF_ERROR_RESOURCES]. I think it's something about the buffer queue size that is too busy. But I don't know how to fix it because most of the resolution on that matter was on the peripheral side with BLE_GATTS_EVT_HVN_TX_COMPLETE but it's a server whereas on the central side it's a client. 

So I think I can't solve my problem with BLE_GATTS_EVT_HVN_TX_COMPLETE or I misunderstood something.

If you could enlighten me on that matter or give me some solutions. It would be great.

Some informations that might be useful : 

NRF_SDH_BLE_GAP_EVENT_LENGTH is 320

NRF_SDH_BLE_GAP_DATA_LENGTH is 251

NRF_SDH_BLE_GATTS_ATTR_TAB_SIZE 1408

// Where I send my 244 Bytes data

void uart_event_handle(app_uart_evt_t * p_event)
{
    static uint8_t data_array[BLE_NUS_MAX_DATA_LEN];
    
    static uint16_t index = 0;
	static uint32_t ret_val;
    static uint16_t length = 244;
	static uint8_t j;
	static uint8_t send_data[BLE_NUS_MAX_DATA_LEN];
  
    
	for (uint8_t i=0; i<length; i++)
	{
		send_data[i]=i;
	}
    switch (p_event->evt_type)
    {
        /**@snippet [Handling data from UART] */
        case APP_UART_DATA_READY:
            UNUSED_VARIABLE(app_uart_get(&data_array[index]));
            index++;

            if (//(data_array[index - 1] == '\n') ||
                (data_array[index - 1] == '\r') ||
                (index >= (m_ble_nus_max_data_len)))
            {
                NRF_LOG_INFO("Ready to send data over BLE NUS");
                NRF_LOG_HEXDUMP_INFO(data_array, index);

                do
                {
					if (index % 4 != 0 || index > 4)
                    {
						for (int i=0;i<10;i++)
						{
								ret_val = ble_nus_c_string_send(&m_ble_nus_c, send_data, length);
						}
					}

                    if ( (ret_val != NRF_ERROR_INVALID_STATE) && (ret_val != NRF_ERROR_RESOURCES) &&
						(ret_val != NRF_ERROR_NOT_FOUND))
                    {
                        APP_ERROR_CHECK(ret_val);
                    }
                } while (ret_val == NRF_ERROR_RESOURCES);

                index = 0;
            }
            break;

        /**@snippet [Handling data from UART] */
        case APP_UART_COMMUNICATION_ERROR:
            NRF_LOG_ERROR("Communication error occurred while handling UART.");
            APP_ERROR_HANDLER(p_event->data.error_communication);
            break;

        case APP_UART_FIFO_ERROR:
            NRF_LOG_ERROR("Error occurred in FIFO module used by UART.");
            APP_ERROR_HANDLER(p_event->data.error_code);
            break;

        default:
            break;
    }
}

Best Regards,

  • Sorry if i wasn't clear enough.

    What I meant is that I store in total 2 packets for the 120 bytes case when I should be storing 4. And the storing process is as follow : 2 packets received the 2nd packet is stored and again  2 packets received the 2nd packet is stored. It's like I receive packet too fast before I can store it. 

    I didn't use an interrupts I use a flag that I put to true when the data is loaded and I put it to false when the storing process is done. 

    But yeah it feels like I don't have time to store my data. 

    But what I don't understand is why I don't have this issue with 244 bytes packets. It's like since it takes more time to process 244 bytes it has more time to store the data.

  • TermiteUser said:
    But what I don't understand is why I don't have this issue with 244 bytes packets. It's like since it takes more time to process 244 bytes it has more time to store the data.

    That depends on how often you receive 244 bytes vs. how often you receive 120 bytes. 

    In BLE there is something called a connection interval. The master and slave (central and peripheral) only communicate once every connection interval. Whenever you send data from one device to another, it will store the data in a queue, and send it at the next connection event (one connection event every connection interval). If you store two smaller packets instead of one large, they are probably sent in the same connection event, meaning you will receive them back to back.

    This boils down to application logic. How is your application supposed to handle the case where you get a new event with new data before the previous data has been stored? Have you tried setting a flag when you are done saving the data in your main loop, and checking this flag before you replace the data in m_buffer_tx[]? That doesn't solve the issue, but it may highlight the weakness of your implementation?

    Perhaps you need more buffers? Try doubling buffering the m_buffer_tx[]. Basically, set up m_buffer_tx1[] and m_buffer_tx2[], and write to them every other time. 

  • I suspected that the connection interval has some impact on how I receive my packets but there is something that I don't understand. 

    Each time I have that event p_evt->type == BLE_NUS_EVT_RX_DATA

    I take the data and store it in m_buffer_tx[]. That is working perfectly. Right after I do that I set my flag data_ready to true and so an event should trigger in my main.

    In case that the packet is 244 bytes right after my m_buffer_tx[] has its data it goes to my main loop and flash the data.

    Now if the data is too small. After data_ready is set to true it goes to my main loop but another event p_evt->type == BLE_NUS_EVT_RX_DATA pop out so it doesn't complete his task in the main and it does another p_evt->type == BLE_NUS_EVT_RX_DATA which load m_buffer_tx[] again. 
    Why does it not continue his task ? Shouldn't the main loop takes priority ? 

    At least that the behavior that my logs tell me :

    <info> app: Received data from BLE NUS. Writing data on UART.
    <info> app: Data length : 120
    <info> app: In main loop
    <info> app: Received data from BLE NUS. Writing data on UART.
    <info> app: Data length : 120
    <info> app: Process of writing data start
    <info> app: Data read
    <info> app: Compare...
    <info> app: Data consistent
    <info> app: Data size : 120 octet
    <info> app: Received data from BLE NUS. Writing data on UART.
    <info> app: Data length : 120
    <info> app: In main loop
    <info> app: Received data from BLE NUS. Writing data on UART.
    <info> app: Data length : 120
    <info> app: Process of writing data start
    <info> app: Data read
    <info> app: Compare...
    <info> app: Data consistent
    <info> app: Data size : 240 octet

  • The main loop has the lowest priority, so if you receive any interrupts, the main loop will be halted. Since your interrupt overwrites the m_buffer_tx[], the main loop will not have any way to continue with the previous data when your interrupt has written new data to m_buffer_tx[].

  • Can I change the priority so my main loop has a bit more priority at least over BLE_NUS_EVT_RX_DATA ? 

Related