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

UART FIFO Flush: How to determine that UART TX is completed

Hi everyone,

in our project we transmit from an android app to Nordic BLE big amount of data (up to 180.000 bytes). I do it by using hvx notifications (MTU 247) and each time I get the notification I try to transmit the data over UART. But we have realized that the uart TX takes too much time and causes packet loss. So I have decieded to store the BLE data and send it after the BLE notifications are completed. Now I face the problem that the UART FIFO (2048) will be full and causes system fault. I need to find out a way where I can determine when the TX transmition is completed and I can flush the TX buffer. I ve searched the uart driver but could find the right function for that. Can anyone help me regarding that?

Thx and Regards

Parents
  • So first of all thx for the answer, I wasn't able the work on that project in the past 2 weeks. Now I am back on track again:

    By sending data over the UART as heap I assume you mean you are forwarding a larger buffer to the UART driver, rather than just single bytes?

    Yes, as I mentioned before, at every notification 244Bytes will be received and if I try to send this over UART right after, I lose some BLE notifications and packets. So I have created a large buffer to process them later.

    Also, the client on the nRF52 side should always be able to unsubscribe or subscribe to notification updates, doing otherwise would be in violation of the Bluetooth specification.

    Why unsubscribe?

    I am not quite sure what you mean by the notification response. There is an onNotificationSent callback issued after the server on the Android side sends a notification, which you should check to ensure the notifications are successfully sent. 

    I am not responsible for the Android implementation, but it was wrong definition, I meant "acknowledge" that the BLE notification packet on nRF52 side have been received. But consumes time (packets between 200- 400).

    An alternative to controlling the data flow by enabling/disabling notifications is to use a separate characteristic to inform the server about how much buffer space you have on the nRF52 side. Then you can update this dynamically, and the Android app can make sure not to send any more data than the buffers in the nRF52 can handle. 

    I can try this one. Good idea.

    By sending data over the UART as heap I assume you mean you are forwarding a larger buffer to the UART driver, rather than just single bytes?

    Somehow singlebytes cause a traceble crash in nRF SW. 

  • Hi Hüseyin 

    Comodo said:
    Why unsubscribe?

     A client would typically unsubscribe to data updates if the application controlling it doesn't need the data, or if it is unable to receive them (like in your case). 

    By being able to only subscribe to updates on the characteristics that are currently needed you can get a more power efficient system, since you are not wasting time and energy sending data that the client doesn't need. 

    Comodo said:
    I am not responsible for the Android implementation, but it was wrong definition, I meant "acknowledge" that the BLE notification packet on nRF52 side have been received. But consumes time (packets between 200- 400).

     Maybe you are referring to sending an indication instead of a notification, which requires the client to send an explicit acknowledge on every received packet. 

    This will definitely slow down communication, and is not recommended if you are trying to optimize throughput and/or power consumption.  

    Comodo said:
    Somehow singlebytes cause a traceble crash in nRF SW. 

    Hm, that shouldn't really happen, but from an efficiency standpoint it is definitely better to send data in larger chunks. Otherwise you won't be able to take advantage of the easyDMA controller to seamlessly get data from the RAM during longer sequences. 

    Best regards
    Torbjørn

  • Thanks for the support. I will get back to you after I got some new results.

  • Ok, just let me know when you have more questions. 

  • So our final conclusion: I can transfer 80KB of data from Android device->Nordic->UART->PC(Matlab) in around 4,4 seconds which is still too long (1000ms of sound data, 2300ms BLE 1Mbits, 1000ms UART). The bottleneck is the UART (1Mbits) ofcourse in case we use 2Mbits. My collegue asked me today why do I am not using the USBD interface for the data transfer. I checked out the examples and I am not sure if its possible to use it with Matlab directly. Have someone any experience with BLE->USB?

Reply
  • So our final conclusion: I can transfer 80KB of data from Android device->Nordic->UART->PC(Matlab) in around 4,4 seconds which is still too long (1000ms of sound data, 2300ms BLE 1Mbits, 1000ms UART). The bottleneck is the UART (1Mbits) ofcourse in case we use 2Mbits. My collegue asked me today why do I am not using the USBD interface for the data transfer. I checked out the examples and I am not sure if its possible to use it with Matlab directly. Have someone any experience with BLE->USB?

Children
  • Hi

    If I understand you correctly you spend 2.3 seconds transferring the entire image over Bluetooth, and then 1.0 seconds afterwards to send it over UART?

    If so then you would probably realize the biggest savings if you are able to send the data over the UART during BLE activity, so that you don't have to wait until the end of the BLE transmission before starting UART TX. In this case you should be able to shave off almost the entire 1 second spent during UART activity, since it appears the BLE communication is slower than the UART communication in your example. 

    I realize you did the UART transfer after the BLE transfer to solve some other issue, but tackling this issue will probably be easier than to move everything to USB. 

    It is technically possible to configure the USB interface in the nRF52840, and handover information from the BLE stack to USB, but I doubt it will be significantly faster compared to the UART running at 1Mbaud. 

    Best regards
    Torbjørn

  • Yeah I have tried to send small heaps (244Bytes, each BLE Packet) on every "on_HVX" interrupt. I have faced crashes at some point (for example packetnr. 55 out of 365 BLE Packets). It was necessary to slow down the BLE notifications (by 4 ms for each packet). The reason for crash I guess was that the interrupt came before UART wasn't done with a packet transfer.  BLE 2MBit is (as expected) a bit faster than UART can handle. But unfortunately reducing the speed to BLE 1MBit was not the solution. I had to build some (4ms) delays between notifications on Android side. In sdk_config I have:


    #define NRF_BLE_SCAN_MIN_CONNECTION_INTERVAL 7.5

    #define NRF_BLE_SCAN_MAX_CONNECTION_INTERVAL 30


    #define NRF_SDH_BLE_GATT_MAX_MTU_SIZE 247

    #define NRF_SDH_BLE_GAP_EVENT_LENGTH 400

    and  

    config of the PHY:

    ble_gap_phys_t const phys =
    {
    .rx_phys = BLE_GAP_PHY_1MBPS,
    .tx_phys = BLE_GAP_PHY_1MBPS,
    };

    has no impact since the delay of 4 ms is necessary.

    The part of the code for on_hvx:

    static void on_hvx(ble_timeandsound_c_t * p_ble_timeandsound_c, ble_evt_t const * p_ble_evt)
    {

    ....

    if(pcounter <= NumOfExpPackets)
    {
      u16counter++; 
      ble_tas_uart_senddata(p_ble_evt->evt.gattc_evt.params.hvx.data, m_ble_max_data_len,   counter);
      //NRF_LOG_INFO(" PACKET = %d", pcounter);
    }else
    {
      u16counter = 0;
    }

    ....

    p_ble_timeandsound_c->evt_handler(p_ble_timeandsound_c, &ble_timeandsound_c_evt);

    }

    So there is no delay in on_hvx handle and m_ble_max_data_len = 244.

    Regarding LOG_INFO or debug information; does it has any impact on UART speed? 

  • Hi 

    If you have room to buffer the entire image in RAM then you should be able to simply use this buffer. Once the BLE data starts coming in you store it in the buffer, and once the buffer has got enough data to send a block over the UART you send a block from the buffer over the UART. 

    The incoming data from BLE will always go to the buffer first, and it doesn't matter what the UART is doing. 

    If the UART is quicker than the BLE link then they will stay more or less in sync, but if the UART is slower then the buffer will store the data while the UART is working. 

    Comodo said:
    Regarding LOG_INFO or debug information; does it has any impact on UART speed? 

    Which backend are you using? 
    The RTT backend should have very little impact on system performance. 

    Best regards
    Torbjørn

  • Hi I have tried that with a buffer of 100.000Bytes size and fed it with BLE data but it is always the same:

    -> NRF_ERROR_NO_MEM (4)

    I have also tried to buffer 20 Packets (20 x 244Bytes) and start then with the UART but no effect.

  • Hi 

    It seems like the buffers are full then. When the NRF_ERROR_NO_MEM error occurs you should stop sending bytes to the UART, and buffer them locally instead. 

    Once the APP_UART_TX_EMPTY event occurs you know that the UART has emptied it's internal buffers and are ready to receive more data. 

    Best regards
    Torbjørn

Related