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

Issue when calling "ble_nus_c_string_send" multiple times to send multiple single bytes

Hi,

I am using the ble_app_uart_c example for the ble_central of SDK 12.2.0 to send data over UART to a nrf52832 based peripheral. When following the format as suggested in the example everything appears to be working fine (terminate data to be sent with \n). I sucessfully sent commands with 60 bytes and \n terminated spread across 3 BLE packets at 20 bytes payload each.

However, when commenting out the section that tests for \n or size>20 bytes my code stops working (see attached code snippet). I am basically trying to force sending each individual byte,  not only when certain conditions are met. When sending small amounts (less than 5 bytes) it still works ok, but when sending more than 5 bytes the code seems to be stuck at line "while (ble_nus_c_string_send(&m_ble_nus_c, data_array, index) != NRF_SUCCESS)" and I am struggling to find out why. Could someone please point me in the right direction?

void uart_event_handle(app_uart_evt_t * p_event)
{
    static uint8_t data_array[BLE_NUS_MAX_DATA_LEN];
    static uint8_t index = 0;

    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') || (index >= (BLE_NUS_MAX_DATA_LEN)))
            //{
                while (ble_nus_c_string_send(&m_ble_nus_c, data_array, index) != NRF_SUCCESS)
                {
                    // repeat until sent.
                }
                index = 0;
            //}
            break;
        /**@snippet [Handling data from UART] */
        case APP_UART_COMMUNICATION_ERROR:
            APP_ERROR_HANDLER(p_event->data.error_communication);
            break;

        case APP_UART_FIFO_ERROR:
            APP_ERROR_HANDLER(p_event->data.error_code);
            break;

        default:
            break;
    }
}

  • Hi,

    It would be interesting to see what value ble_nus_c_string_send() returns if not NRF_SUCCSS. Maybe you can change your code to something like this, and then debug to find out:

    uint32_t err_code;
    do
    {
        err_code = ble_nus_c_string_send(&m_ble_nus_c, data_array, index);
    }while(err_code != NRF_SUCCESS);

    You can also add APP_ERROR_CHECK(err_code) between line 4 and 5 to have your code end up in an error handler and print your errors to a terminal. 

  • Hi Martin,

    thanks for your help. I changed my code to what you suggested and also added the APP_ERROR_CHECK(err_code). The error code is 0x3004 and the error handler prints this:

    0> SDH:DEBUG:sd_ble_enable: RAM start at 0x20001fe8
    0> BLE_DB_DISC:INFO:Starting discovery of service with UUID 0x1 for Connection handle 0
    0> BLE_DB_DISC:INFO:Found service UUID 0x1
    0> BLE_DB_DISC:INFO:Discovery of service with UUID 0x1 completed with success for Connection handle 0
    0> APP_ERROR:ERROR:Fatal

    Can you see from that what the issue is?

    Thanks

  • Hi,

    Error 0x3004 is BLE_ERROR_NO_TX_PACKETS: 

    // In file ble_err.h
    #define BLE_ERROR_NO_TX_PACKETS          (NRF_ERROR_STK_BASE_NUM+0x004) /**< Not enough application packets available on this connection. */
    
    // In file nrf_error.h
    #define NRF_ERROR_STK_BASE_NUM  (0x3000)    ///< STK error base

    It means that the TX buffer in the Softdevice is full, and that you can't queue more packets before one or more packets that are already queued are transmitted successfully. It is strange though, because a simple workaround for this is to do as you are already doing and keep on calling ble_nus_c_string_send() in a loop. What happens if you mask out the no packets error as well and use:

    while((err_code != NRF_SUCCESS) && (err_code != BLE_ERROR_NO_TX_PACKETS));

    Do you get any other errors?

    You can also have a look at the ATT_MTU Throughput Example as well. The example shows how you can use BLE_EVT_TX_COMPLETE events returned from the Softdevice to queue packets only when there is space in the TX buffers. 


    PS:

    To make it print out more informative messages, you can change the code in app_error_fault_handler() in app_error_weak.c to something like this:

    __WEAK void app_error_fault_handler(uint32_t id, uint32_t pc, uint32_t info)
    {
        static error_info_t  * p_error_info;
        p_error_info = (error_info_t*)info;
        NRF_LOG_ERROR("Error: ID: %d, PC: 0x%X\r\n", id, pc);
        NRF_LOG_ERROR("Error: Code: 0x%04X (%d), Line: %d, File: %s\n\r", p_error_info->err_code, p_error_info->err_code, p_error_info->line_num, (uint32_t)p_error_info->p_file_name);
        
        NRF_LOG_FINAL_FLUSH();
        // On assert, the system can only recover with a reset.
    #ifndef DEBUG
        NVIC_SystemReset();
    #else
        app_error_save_and_stop(id, pc, info);
    #endif // DEBUG
    }

  • Hi,

    I tried masking out the "no packets" error but couldn't see any other errors, still only 0x3004. I will have a look at the throughput example and try to understand how to use the BLE_EVT_TX_COMPLETE event.

    What concerns me is that the code seems to be stuck in this endless loop of waiting to sucessfully transmit packets and free up the queue. But it seems that after the first couple of bytes not a single packet gets transmitted sucessfully anymore. I would have expected that the queue gets cleared one by one as packets get transmitted. Is there an easy way to troubleshoot the reason for no packets being sucessfully transmitted?

  • Hi,

    When I looked at your original code again I realized that you are not handling the index variable correctly. In your code index is initialized to 0. Then used to put your UART byte into an array. At line 11 index is incremented to 1 and then it is used as length of the string you want to transmit with ble_nus_c_string_send(). And then, at line 19 index is set to 0 again. And so it goes over and over. You will in other words never transmit more than 1 byte at the time.  I'm a little short of time so I haven't had the time to figure out why this seemingly causes everything to stall in an endless loop though. Anyway, you should try to implement some code that puts together a longer packet before you transmit the data. 

Related