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

Confusion about double buffered pointer on UARTE

I'm using an NRF52811 and trying to configure the UARTE for Tx & Rx at 57600 baud but I'm having trouble with the Rx. I think I am dropping bytes and so want to try and exploit the double buffered DMA  pointer, to see if that fixes the problem. I'm using the UARTE driver, which I want to stick with for now, but I'm wondering when and how often I need to call the nrfx_uarte_rx(..) function, and particularly how to call it to exploit double buffering of the pointer.

Q1. Is it necessary to call nrfx_uarte_rx(...) once to start the receiver, and then again inside the handler, after processing every received byte(s) ? If so, is this because the receiver task stops once the number of bytes specified  in the call have been received?

Q2. Regarding double buffering of the pointer, the API documentation says "The secondary buffer can be set immediately after starting the transfer and will be filled when the primary buffer is full. The double-buffering feature allows receiving data continuously", but this doesn't really explain how to use the driver calls. If I want to exploit the double buffering, and capture 1 byte at a time, alternating between two 1-byte buffers, is this correct:

(in initialisation)

     char rx_ch_1, rx_ch_2;

     nrfx_uarte_rx(&uarte0, &rx_ch_1, 1);   // first 1-byte buffer
    
     nrfx_uarte_rx(&uarte0, &rx_ch_2, 1);   // second 1-byte buffer
    

(the handler)

void uarte_event_handler(nrfx_uarte_event_t const *p_event, void *p_context)
{
    switch(p_event->type)
    {
...        

        case NRFX_UARTE_EVT_RX_DONE:

            // grab and process the received byte from the last buffer filled

            my_rx_byte_handler(*(p_event->data.rxtx.p_data));

            // start another rx task. Do I need to do this ?
            nrfx_uarte_rx(&uarte0, p_event->data.rxtx.p_data, 1);  // ??? 

What address do I specify here ^^ ?

Should  I do this again, inside the handler ?

            nrfx_uarte_rx(&uarte0, &rx_ch_1, 1);

            nrfx_uarte_rx(&uarte0, &rx_ch_2, 1);

Whatever I do I can't seem to get it work. I thought the point of double buffering is to allow me some slack before the handler is processed, ensuring that the last byte is not overwritten too soon, so it seems odd to have to specify the next buffer in the handler.

Any helpful comments appreciated.

Pete

  • I think I have a grip of this now. I had a bug in my main byte handler function which wasn't helping matters, and was the reason I was trying to use two 1-byte buffers. I now have two rx_buffers, each 10 bytes long, which gives me plenty of margin. I initialise the pointers in the initialisation using:

        nrfx_uarte_rx(&uarte0, rx_buffer[0], RX_BUFFER_SIZE);
        nrfx_uarte_rx(&uarte0, rx_buffer[1], RX_BUFFER_SIZE);

    and then in my event handler I have:

        case NRFX_UARTE_EVT_RX_DONE:

            p_data = p_event->data.rxtx.p_data;

            num_bytes = RX_BUFFER_SIZE;

            while(num_bytes--)
            {

                 my_rx_byte_handler(*(p_data++));    // call the external handler to dump the latest bytes into large buffer
            }

            nrfx_uarte_rx(&uarte0, p_event->data.rxtx.p_data, RX_BUFFER_SIZE); // ensure primary and secondary buffers flip

            break;

        case NRFX_UARTE_EVT_ERROR:

            nrfx_uarte_rx(&uarte0, rx_buffer[0], RX_BUFFER_SIZE);
            nrfx_uarte_rx(&uarte0, rx_buffer[1], RX_BUFFER_SIZE);

            break;

    I added a check to see what p_data is doing and it toggles between the two rx buffers, as expected, confirming that the double buffering of the pointers is working. 

    Is there any value in using   p_event->data.rxtx.bytes   to get the number of bytes waiting, or can I assume that it will always be the number requested, i.e. RX_BUFFER_SIZE

    Regards,

    Pete

  • Glad that you have this figured out.

     

    Pete W said:
    Is there any value in using   p_event->data.rxtx.bytes   to get the number of bytes waiting, or can I assume that it will always be the number requested, i.e. RX_BUFFER_SIZE

    RX:BUFFER:SIZE not the same as rxtx.bytes.

    RX_BUFFER_SIZE should be larger than the biggest single RX transaction your application does..

Related