This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

CC1312R: UART_read in Callback Mode does not flush rx buffer

Part Number: CC1312R


I am trying to write the callback function for the UART in callback mode but I have a question.

Data I am expecting is always 6-bytes. 

1- If I set the rxBuf size to be 6 as an argument for "Uart_read" function, things go well as long as there is no incomplete or more-than-complete data. For instance, instead of 6-bytes, if I send less than 6-bytes, callbackfunction is never called since readReturnMode = UART_RETURN_FULL (6-byte buffer is not full). Sending the i.e. 4-byte message again fills the buffer to 6 and callback function is called with the previous data + last data (first 2-bytes of it) in the buffer.

However, I do not want this, because than the whole protocol commands get shifted and a meaningful communication is never established.

I need to somehow flush the rx buffer so that next time, I receive the 6-byte data as a whole, but that means I also need to reset the pointer that points to the buffer (I guess that is a pointer/counter to know how many bytes have been received).

or,

I will make the rx buffer size 1-byte, and start a sequence: Start Byte has been received, next 5-bytes will be data, if another Start Byte is received, then cancel the sequence and start over etc. However, this may not be really efficient since callback function will be called very frequently and not sure what kind of impact it may have on the TI15.4 tasks.

Here is how my callback function looks like:

/*!
 Interrupt callback UART Rx.
 */
static void readCallback(UART_Handle handle, void *buffer, size_t size)
{   /* Received frame shall only be 6 byte in length with start address of 0xFE */
    if ((0xFE == (*((uint8_t *)buffer))))
    {
        if (6 == size)
        {
            address_h = ((uint8_t*)buffer)[1];
            address_l = ((uint8_t*)buffer)[2];
            cmd = ((uint8_t*)buffer)[3];
            data = ((uint8_t*)buffer)[4];
            checksum = ((uint8_t*)buffer)[5];
            UART_read(hUart, rxBuf, sizeof(rxBuf));
        }
        else // size will always be 6 so this is unneccessary
        {
            UART_readCancel(hUart);
        }
    }
    else 
    {
        UART_readCancel(hUart);
    }
    asm(" nop");  // debugging breakpoint purpose
}

2- WARNING: "Do not call UART_read() from its own callback function when in UART_MODE_CALLBACK". I have seen in a post on E2E as an answer to a question: it is safe to call this function inside the callback funciton but file reference says the opposite. However, uart rx does not work unless I call this function after a reception. If I do not call this function inside the callback, then what if I do not enable reception fast enough and miss some data?

3- "UART_readCancel() calls the registered RX callback function no matter how many bytes were received. It is the application's responsibility to check the count argument in the callback function and handle cases where only a subset of the bytes were received." Where and when shall I call this function? It seems to be related to what I am trying to do. 

  • Hi Arda,

    Could you comment on which SDK version you are currently using?

    1) This is the default intended behavior. The UART driver has an internal ringbuffer which it keeps receiving into in between the read calls. This also means that when you have sent in 8 bytes and only read out 6 of them, 2 is left in the buffer for later processing. This is to assure you do not miss out on data that the device might receive while your application was not "ready" to receive. 

    If you want to flush the RX FIFO, you can do this by using the UART_control() API together with the "UARTCC26XX_CMD_RX_FIFO_FLUSH" command. Note that the RX module is still left "on" in between calls which means you would get data put into the ringbuffer whenever you are not asking for data in the application. 

    2) Ignore this, for the UARTCC26XX.c driver, you can call UART_read() from inside the callback. There is typical these kind of high level warnings as the UART API is shared across many devices (with their own implementation under the hood). If you have a look at the UARTCC26XX.h documentation which is the more "specific" version, you will find that calling UART_read() from the callback is even the proposed solution to the continious RX case.

    3) UART_readCancel() only invoke the callback if there was an active read where you have received data (readSize > 0). In case the internal read size is zero it will return without invoking the callback.

  • UART_control(hUart, UARTCC26XX_CMD_RETURN_PARTIAL_ENABLE, NULL);
    
    static void readCallback(UART_Handle handle, void *buffer, size_t size)
    {   /* Received frame shall be 6-bytes in length with start address of 0xFE */
        if ((START_BYTE == ((uint8_t*)buffer)[0]))
        {
            if (COMMAND_FRAME_SIZE == size)
            {
                address_h = ((uint8_t*)buffer)[1];
                address_l = ((uint8_t*)buffer)[2];
                cmd = ((uint8_t*)buffer)[3];
                data = ((uint8_t*)buffer)[4];
                checksum = ((uint8_t*)buffer)[5];
                asm(" nop");
            }
            else
            {
               asm(" nop"); // debugging purpose
            }
        }
        else
        {
            UART_control(hUart, UARTCC26XX_CMD_RX_FIFO_FLUSH, NULL);
        }
        UART_read(hUart, rxBuf, sizeof(rxBuf));
    }

    This configuration has done the job.