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

nRF52 Stale UART RX Data

On a custom board with an nRF52832 communicating over UART with another microcontroller with no flow control capability.

SDK 13.0.0-1.alpha with an S132SD.

I have some weirdness where reading data from the UART is returning the previously received message. (i.e. - messages seem to be one message behind.)

Messages are encoded as raw bytes (nano-bp) and I have verified that the other micro is transmitting/receiving and encoding/decoding just fine.

I can TX messages from the nRF52 without issue.

init looks like this:

static void uart_init(void)
{
    uint32_t	err_code;
    const app_uart_comm_params_t comm_params =
    {
        RX_PIN_NUMBER,
        TX_PIN_NUMBER,
        NULL,
        NULL,
        APP_UART_FLOW_CONTROL_DISABLED,
        false,
        UART_BAUDRATE_BAUDRATE_Baud19200
    };

    APP_UART_FIFO_INIT( &comm_params,
                       UART_RX_BUF_SIZE,
                       UART_TX_BUF_SIZE,
                       uart_event_handle,
                       APP_IRQ_PRIORITY_LOWEST,
                       err_code);
    APP_ERROR_CHECK(err_code);
}

UART event handler:

void uart_event_handle(app_uart_evt_t * p_event)
{
    switch (p_event->evt_type)
    {
//        case APP_UART_DATA_READY:
//		      UART_available = true; // globally defined bool
//            break;

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

Checking for APP_UART_DATA_READY events doesn't seem to solve the problem as the data is definitely there.

Messages are more or less read a byte at at time like so then decoded, which works just fine:

while(app_uart_get(&data) == NRF_SUCCESS)
  {
		if(index < sizeof(msg_buffer))
		{
			msg_buffer[index] = data;
		}
    index++;
  }

msg_buffer is local and is reinitialized before every read.

I have tried app_uart_flush() in various locations to clear any extraneous data that might be in the buffer prior to the data arriving to no avail.

Oddly, the very first attempt to decode a message after boot always fails (but subsequent messages are successfully decoded, just with the previous message's data) leading me to believe there's initially garbage in the buffer which could account for the messages always being one behind.

I tried consuming the data and ignoring it on first read to discard any garbage to no avail:

static bool is_first_message = true;
    if(is_first_message)
    {
        while(app_uart_get(&data) == NRF_SUCCESS)
        {
            if(index < sizeof(msg_buffer))
            {
                msg_buffer[index] = data;
            }
            index++;
        }
    is_first_message = false;
    }

Happy to provide more details within reason.

Any suggestions or thoughts would be greatly appreciated!

  • Hi, do you see the same issue with the uart example in the SDK ? Also, the latest SDK is 13.1, you may consider moving away from the SDK v13 alpha.

  • The UART example in the SDK does not exhibit this behavior but it is also not representative of my use case.

    The issue noted above is the gist of problem. In my actual application a byte is written to a custom characteristic over BLE. This value is encoded with a message type and sent over UART to the secondary MCU which parses the data and sends back an acknowledgement message with the same value to confirm the data has been handled. This message is then read by the nRF52 (this is where I'm having the issue) and the value is used to update a separate characteristic byte value.

    I know that everything else in the communication chain is working properly as I can hardcode values and messages are still one behind. Values are reinitialized before every call so the only place the old data could be sitting is in the UART buffer.

  • Additionally, I had a feeling the alpha SDK would come up as an issue (what exactly is different in the UART driver between the alpha and release version?) so I took the several hours necessary to port my code to the 13.1 SDK in a separate branch of my project and the result is exactly the same; the issue remains.

  • I managed to more or less resolve the issue with a ferociously strict set of message checking logic and retries within the APP_UART_DATA_READY event handler.

    It doesn’t explain the stale data I was seeing but it’s a fairly robust and sufficient solution for the time being.

  • Sorry to hear ab your struggle with the UART. Is it possible to reproduce the issue with a very simple code ? Let's ignore BLE , simply send a byte to the peer and then wait for a byte (ACK/NACK ) to come back from the peer ? From what I understand, you only receive the ACK of the pervious packet from the peer ?

Related