nRF52DK nRF52832 UART asynchronous receive

I am working through the Nordic Developer Academy and got stuck at lesson 4 (UART receive)

https://academy.nordicsemi.com/courses/nrf-connect-sdk-fundamentals/lessons/lesson-4-serial-communication-uart/topic/uart-driver/

In particular, I am confused about this part:

I have created a sample project and connected external CP2102 USB->Serial adapter to P0.06 and P0.08 pins.

The code that I use:

/*
 * Copyright (c) 2012-2014 Wind River Systems, Inc.
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include <zephyr/kernel.h>
#include <zephyr/drivers/gpio.h>
#include "stdio.h"
#include "zephyr/drivers/uart.h"

const struct device *uart = DEVICE_DT_GET(DT_NODELABEL(uart0));

static uint8_t tx_buf[] =  {"nRF Connect SDK Fundamentals Course \n\r"};
static uint8_t rx_buf[10] = {0}; //A buffer to store incoming UART data 

const struct uart_config uart_cfg = {
		.baudrate = 115200,
		.parity = UART_CFG_PARITY_NONE,
		.stop_bits = UART_CFG_STOP_BITS_1,
		.data_bits = UART_CFG_DATA_BITS_8,
		.flow_ctrl = UART_CFG_FLOW_CTRL_NONE
	};

static void uart_cb(const struct device *dev, struct uart_event *evt, void *user_data)
{
	switch (evt->type) {
	
	case UART_TX_DONE:
		printf("transmission complete \n");
		break;

	case UART_TX_ABORTED:
		// do something
		break;
		
	case UART_RX_RDY:
		printf("rx rdy \n");
		if((evt->data.rx.len) != 0){
			printf("data received = %s \n", evt->data.rx.buf[evt->data.rx.offset]);
		}


		
		break;

	case UART_RX_BUF_REQUEST:
		printf("requesting buffer \n");
		// do something
		break;

	case UART_RX_BUF_RELEASED:
		printf("buffer released \n");
		// do something
		break;
		
	case UART_RX_DISABLED:
		printf("rx disabled \n");
		uart_rx_enable(dev, rx_buf, sizeof(rx_buf), 100);
		break;

	case UART_RX_STOPPED:
		// do something
		break;
		
	default:
		break;
	}
}


int main(void)
{	

	if (!device_is_ready(uart)) {
    	return;
	}

	int err;
	err = uart_callback_set(uart, uart_cb, NULL);
	if (err) {
		return err;
	}

	uart_rx_enable(uart, rx_buf, sizeof(rx_buf), 100);


	err = uart_tx(uart, tx_buf, sizeof(tx_buf), SYS_FOREVER_US);
	if (err) {
		return err;
	}



	while(1){
		k_msleep(1000);
	}
	return 0;
}

I am having issues understanding how to properly print out all the received data:

I tried to do:

	case UART_RX_RDY:
		printf("rx rdy \n");
		if((evt->data.rx.len) != 0){
			printf("data received = %s \n", evt->data.rx.buf[evt->data.rx.offset]);
		}

		break;

but when I send the data via UART (using Termite) , the following is printed:

I would appreciate if someone could clarify how to correctly print out all the received data.  Thanks in advance

Just for testing, I have also tried to print:

    case UART_RX_RDY:
        printf("rx rdy \n");
        printf("data: %s \n", rx_buf);
        break;
 
and the logs are as following: (captured using Termite):
 
As you can see, it receives the first message (ping) correctly, but after that, the buffer overflows (rx_buf is 10 bytes size) and then it cannot print out the data correctly)
  • Hello,

    Andreas is currently busy with other tasks, so I will have a look at this ticket. 

    Please note that there is a lot of information here, but I have tried to get a reasonable overview. 

    zazas321 said:
    POINT 1

    Yes. This is a very simplified application. I suspect you are looking for functionality closer to the one found in ncs\nrf\samples\bluetooth\peripheral_uart. Please note that this doesn't echo the data back on the UART, but it will transmit the UART data over BLE to the connected device. Please see the sample description.

    zazas321 said:
    POINT 2

    Noted. I agree.

    zazas321 said:
    POINT 3

    This makes sense, actually. 

    printf, in your case uses the UART backend, so every time you send a message, or possibly a character, over UART, it will trigger a new callback to the very same uart callback that printed the character in the first place. Therefore, I recommend, if you want to use the log while using the UART, you should use the logging module (LOG_INF()) with RTT backend (and not UART backend). To see how to do this, look at how it is done in the ncs\nrf\samples\bluetooth\peripheral_uart sample. 

    zazas321 said:
    Is this expected behaviour that a few printf statements in uart_cb causes weird behaviour as have been shown above?

    I wouldn't recommend using printf(), which will trigger uart callbacks inside the uart_cb.

    zazas321 said:
     If above is true, I am concerned about other high priority tasks or callbacks interrupting the UART reception and causing similar issues even when all print statements are removed from the callback itself. Is ASYNC UART affected by other Zephyr RTOS threads running or it is independent and not affected at all?

    I don't think you will see similar issues with other high priority interrupts, as long as they are not triggered recursively via the UART callback. 

    zazas321 said:
    During the discussion above it has been mentioned that it is recommended to use larger UART_BUF_SIZE but that did not help in any way. The only thing that does is just simply requires more serial data to be received before it fills up and eventually breaks.

    I agree. That will just postpone the issue. 

    zazas321 said:
    I would highly appreciate if someone with good Zephyr and ASYNC UART knowledge could shed some light here and cover the issues that I have encountered and the solutions that I have found.

    I agree that this seems like a good solution for this need. However, I suggest not using the UART for log messages at all inside the uart callback handler. Either use no log, or use the RTT backend.

    Best regards,

    Edvin

Related