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;
    }
}

Parents
  • 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,

    I went ahead and tested the latest SDK 15.0.0 with S132 v6.0.0 and received the following error when sending more than 18 bytes of payload:

     0> <info> app: BLE UART central example started.
     0> <info> app: Connecting to target 19F0A32761E0
     0> <debug> nrf_ble_gatt: Requesting to update ATT MTU to 247 bytes on connection 0x0.
     0> <debug> nrf_ble_gatt: Updating data length to 251 on connection 0x0.
     0> <info> app: Connected to target
     0> <debug> ble_db_disc: Starting discovery of service with UUID 0x1 on connection handle 0x0.
     0> <debug> nrf_ble_gatt: Peer on connection 0x0 requested an ATT MTU of 247 bytes.
     0> <debug> nrf_ble_gatt: Updating ATT MTU to 247 bytes (desired: 247) on connection 0x0.
     0> <debug> nrf_ble_gatt: ATT MTU updated to 247 bytes on connection 0x0 (response).
     0> <info> app: ATT MTU exchange completed.
     0> <info> app: Ble NUS max data length set to 0xF4(244)
     0> <debug> ble_db_disc: Starting discovery of service with UUID 0x1 on connection handle 0x0.
     0> <debug> nrf_ble_gatt: Data length updated to 251 on connection 0x0.
     0> <debug> nrf_ble_gatt: max_rx_octets: 251
     0> <debug> nrf_ble_gatt: max_tx_octets: 251
     0> <debug> nrf_ble_gatt: max_rx_time: 2120
     0> <debug> nrf_ble_gatt: max_tx_time: 2120
     0> <debug> ble_db_disc: Found service UUID 0x1.
     0> <debug> ble_db_disc: Discovery of service with UUID 0x1 completed with success on connection handle 0x0.
     0> <info> app: Discovery complete.
     0> <info> app: Connected to device with Nordic UART Service.
     0> <debug> app: Ready to send data over BLE NUS
     0> <debug> app:  31                     |1       
     0> <debug> app: Ready to send data over BLE NUS
     0> <debug> app:  32                     |2       
     0> <debug> app: Ready to send data over BLE NUS
     0> <debug> app:  33                     |3       
     0> <debug> app: Ready to send data over BLE NUS
     0> <debug> app:  34                     |4       
     0> <debug> app: Ready to send data over BLE NUS
     0> <debug> app:  35                     |5       
     0> <debug> app: Ready to send data over BLE NUS
     0> <debug> app:  36                     |6       
     0> <debug> app: Ready to send data over BLE NUS
     0> <debug> app:  37                     |7       
     0> <debug> app: Ready to send data over BLE NUS
     0> <debug> app:  38                     |8       
     0> <debug> app: Ready to send data over BLE NUS
     0> <debug> app:  39                     |9       
     0> <debug> app: Ready to send data over BLE NUS
     0> <debug> app:  30                     |0       
     0> <debug> app: Ready to send data over BLE NUS
     0> <debug> app:  31                     |1       
     0> <debug> app: Ready to send data over BLE NUS
     0> <debug> app:  32                     |2       
     0> <debug> app: Ready to send data over BLE NUS
     0> <debug> app:  33                     |3       
     0> <debug> app: Ready to send data over BLE NUS
     0> <debug> app:  34                     |4       
     0> <debug> app: Ready to send data over BLE NUS
     0> <debug> app:  35                     |5       
     0> <debug> app: Ready to send data over BLE NUS
     0> <debug> app:  36                     |6       
     0> <debug> app: Ready to send data over BLE NUS
     0> <debug> app:  37                     |7       
     0> <debug> app: Ready to send data over BLE NUS
     0> <debug> app:  38                     |8       
     0> <debug> app: Ready to send data over BLE NUS
     0> <debug> app:  39                     |9       
     0> <debug> app: Ready to send data over BLE NUS
     0> <debug> app:  30                     |0       
     0> <error> app: Error: ID: 16385, PC: 0x2BCC9
     0> 
     0> <error> app: Error: Code: 0x0013 (19), Line: 246, File: ..\..\..\main.c
     0> 
     0> <error> app: ERROR 19 [NRF_ERROR_RESOURCES] at ..\..\..\main.c:246
     0> PC at: 0x0002BCC9
     0> <error> app: End of error report

  • Hi

    Error NRF_ERROR_RESOURCES means that you are still filling up the Softdevice's transmit queue too fast. What kind of central device do you use for testing? Have you tried more than one?

    There are a couple of suggestions here. Have you tried something similar?

    Can you upload your project if you are still stuck?

  • Hey,

    I am using two of the Rigado BMD-300 evaluation kits ( Rigado Eval Kit ) which are similar to the Nordic pca 10040 boards. One is configured as central and the other one as peripheral device. My project is the exact SDK UART example code (ble_app_uart_c and ble_app_uart) and I only made a small change to the function uart_event_handle of the file main.c of the central example. The single change was to comment out the if statement as indicated in my very first post here. The peripheral example code is unchanged.

  • Hi,

    I think I finally see the problem here. The uart_event_handle() function is an interrupt, so what you are doing is transmitting single UART bytes from within an interrupt context.

    By default the SDK configures the UART to use a baud rate of 115200. This means that if you are receiving strings of UART data you will receive new bytes every 10 us or so. The problem is that the lowest BLE connection interval you can have is 7.5 ms so you are receiving UART data way faster than you can transmit them. Unless you buffer the UART data and transmit as many bytes as you can per connection interval. 

    Furthermore, because we are using while loops inside the UART handler, the code is stuck there waiting for a successful BLE notification to be sent while new UART data mercilessly keeps flowing in. This creates a queue of interrupts and because of this the code enters some sort of deadlock (which I have yet to be able to wrap my head around). 

    The solution is to move the transmission of the data out of the interrupt and into the main context. Store the incoming UART bytes and set a flag in the UART handler. Then check this flag inside the main loop. If the flag is set, call ble_nus_data_send() and transmit the data. However, losing some of the UART data is inevitable if you insist on transmitting one by one byte. 

  • Hi Martin,

    thatnks for your explanation, this makes a lot of sense. I managed to implement a circular buffer that gets filled in the interrupt routines and in the main section I added some code to check if there is anything new in the buffer and starts the BLE transmission if required. I also added some functionality to pack more bytes into one message and only in certain circumstances sends single bytes in a BLE message. Those two additions seem to work and I am now able to transmit data in both directions with variable and unknown data packet lengths.

    Thanks for your help on this.

Reply
  • Hi Martin,

    thatnks for your explanation, this makes a lot of sense. I managed to implement a circular buffer that gets filled in the interrupt routines and in the main section I added some code to check if there is anything new in the buffer and starts the BLE transmission if required. I also added some functionality to pack more bytes into one message and only in certain circumstances sends single bytes in a BLE message. Those two additions seem to work and I am now able to transmit data in both directions with variable and unknown data packet lengths.

    Thanks for your help on this.

Children
No Data
Related