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

Libuarte async high speed data receive and NUS transfer

Hi, 

I successfully added libuarte async library to the ble_app_uart example. Now I am able to receive data over UART from another board and my goal is to transfer it to the android application using NUS service just like in the ble_app_uart example. So here is the problem.

When you initialize the library you pass a function that will handle library events. The event I am interested in is NRF_LIBUARTE_ASYNC_EVT_RX_DATA. I get that event and it contains p_evt->data.rxtx.p_data and p_evt->data.rxtx.length that I want to send using ble_nus_data_send. Now my question when do I call the function. I tried the following things.

First I tried the most basic approach and that is to call ble_nus_data_send function right after the event is received, send the data and free the buffer.

 

        case NRF_LIBUARTE_ASYNC_EVT_RX_DATA:
        {
            do
            {
                err_code = ble_nus_data_send(&m_nus, p_evt->data.rxtx.p_data, &p_evt->data.rxtx.p_data, m_conn_handle);
                
                if ((err_code != NRF_ERROR_INVALID_STATE) &&
                    (err_code != NRF_ERROR_RESOURCES) &&
                    (err_code != NRF_ERROR_NOT_FOUND))
                {
                    APP_ERROR_CHECK(err_code);
                }
             } while (err_code == NRF_ERROR_RESOURCES);

            nrf_libuarte_async_rx_free(&libuarte, p_evt->data.rxtx.p_data, p_evt->data.rxtx.length);
            break;
        }

Problem is that this approach doesn't work. If the .int_prio   = APP_IRQ_PRIORITY_LOW_MID then I can transfer a couple of chunks and the uart won't transmit anymore. Also, if the priority is higher then it won't ever send anything and program crashes.

The second thing I tried is to use memcpy to copy data into the second buffer and set the flag that data is received. Then in idle_state_handle function, I check if the flag is true and if it is I call ble_nus_data_send. That works really well up to a certain point. I tried various speeds and below ~45KBps I receive every byte in the app that I send. If I increase the speed to, for example, 80KBps then I start losing chunks of data. One test that I had is that I send 244bytes * 10000 and after the test is done I checked the app and I was missing around 100 packets. Also, this loss is not deterministic and varies between tests.

So, my question is what am I doing wrong? Is there another way to use libuarte async to transmit data at high speed than to poll that flag in the main loop? I know that the test board can transmit uart data at ~100KBps and I also managed to transmit test data with only NUS at also around 100KBps to the app. So BLE stack is good and connection from test board to nordic chip is also good so the problem must be with the way I use libuarte..

I would appreciate any input in how I can increase the speed while maintaining the lossless packet transfer.

Thanks,

Aleksa

  • Aleksa said:
    I think I finally got it. I didn't really understand what you meant with buffering at first but I think I got it. Because there is more than 30KB or unused ram I split that into two buffers as you suggested and started filling them up in the NRF_LIBUARTE_ASYNC_EVT_RX_DATA event. After the buffer is full I set the flag in the main loop and switch the buffers so I can fill the next one. In the main loop, I bulk transfer the whole array instead of individual chunks like before.

     Good! That was at least what I was trying to say. Since the softdevice may keep the CPU busy for short periods, you may receive two NRF_LIBUARTE_ASYNC_EVT_RX_DATA before you manage to handle the first one of them. So if you increase to having two buffers, the application should be able to push the data to the queue before the 3rd NRF_LIBUARTE_ASYNC_EVT_RX_DATA. At least as long as the BLE link has a higher throughput than the UART. 

    Have a nice weekend.

    Best regards,

    Edvin

Related