nrf52811 interrupt driven UART does not receive everything correclty

Hi,

I am currently trying to connect a nrf52811 as an companion to an ESP32 user UART.

I am using the interrupt driven UART implementation as kind of the last resort.

I am facing the Problem, that i am getting the UART Messages not fully. It appears to be like this:

The message consists of 8 Bytes (thats not always the case. can be more but never less than 7 Byte).

I correctly get the first 4 Bytes. wich i immediatly put on a queue for further use.
Then nothing happens until the timeout in the ESP occurs as i am not sending any response.
The ESP now tries to re-send the message.
I now get the last 4 Bytes of the prrevious message as well as the first 4 Bytes of the current message!
So the message appears to still be in the UART Buffer but not correctly sent to the application.

I would greatly appreciate any answer regarding this behaviour.

I am using nrfConnect SDK V2.7 with mcuBoot using Serial Recovery.
I also want to use the same UART as the update port in Serial Recovery.

Here is my prj-conf:

CONFIG_LOG=y
CONFIG_LOG_DEFAULT_LEVEL=3
CONFIG_LOG_MODE_IMMEDIATE=y
CONFIG_LOG_BACKEND_RTT=y
CONFIG_USE_SEGGER_RTT=y
CONFIG_CBPRINTF_FP_SUPPORT=y
CONFIG_SEGGER_RTT_MODE_NO_BLOCK_TRIM=y
CONFIG_SEGGER_RTT_BUFFER_SIZE_UP=2048

CONFIG_NCS_SAMPLES_DEFAULTS=y
CONFIG_DEBUG=y
CONFIG_SHELL=y
CONFIG_INIT_STACKS=y
CONFIG_THREAD_MONITOR=y
CONFIG_THREAD_NAME=y


CONFIG_HW_STACK_PROTECTION=n
CONFIG_HEAP_MEM_POOL_SIZE=1024


CONFIG_CRC=y
CONFIG_AUDIO=y
CONFIG_AUDIO_CODEC=y
CONFIG_AUDIO_TAS5828=y
CONFIG_PWM=y
CONFIG_PWM_LOG_LEVEL_OFF=y

CONFIG_NRFX_SAADC=y
CONFIG_NRFX_PPI=y
# TIMER2 is 52 specific. for 54 use TIMER22
CONFIG_NRFX_TIMER2=y
CONFIG_NRFX_TIMER0=y

CONFIG_I2C=y
CONFIG_LED=y
CONFIG_SERIAL=y
CONFIG_UART_INTERRUPT_DRIVEN=y
CONFIG_UART_0_INTERRUPT_DRIVEN=y
CONFIG_UART_0_NRF_PARITY_BIT=y
CONFIG_UART_NRFX_UARTE_LEGACY_SHIM=n

CONFIG_EVENTS=y

CONFIG_ASSERT=y

CONFIG_MAIN_STACK_SIZE=1024
CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=512
CONFIG_IDLE_STACK_SIZE=512


CONFIG_ASSERT_NO_MSG_INFO=n

CONFIG_PM_DEVICE_RUNTIME=n
CONFIG_PM=n

here is my DT-Configuration:

&uart0 {
    status = "okay";
    pinctrl-0 = <&uart0_default>;
    pinctrl-names = "default";
    current-speed = <31250>;
    parity = "even";
    stop-bits = "1";
    data-bits = <8>;
};

As for DT: I am using a custom board definition which i recently updated to HWMv2 as part of the swap to nrf Connect SDK v2.7

here is part of the implementation of the UART in my application:

K_MSGQ_DEFINE(serial_rx_raw_q, sizeof(uint8_t), MSG_LENGTH_MAX * 2, 1);
K_MSGQ_DEFINE(serial_tx_raw_q, sizeof(uint8_t), 50, 1);
const struct device *uart = DEVICE_DT_GET(DT_NODELABEL(uart0));


void init() {
if (!device_is_ready(uart))
	{
		LOG_WRN("UART device not ready");
		return 1;
	}

	int err = uart_irq_callback_set(uart, serial_interruptdriven_cb);

	if (err < 0) {
		if (err == -ENOTSUP) {
			LOG_ERR("Interrupt-driven UART API support not enabled");
		} else if (err == -ENOSYS) {
			LOG_ERR("UART device does not support interrupt-driven API");
		} else {
			LOG_ERR("Error setting UART callback: %d", err);
		}
		return 0;
	}
	uart_irq_rx_enable(uart);
}


void serial_interruptdriven_cb(const struct device *dev, void *user_data) {
	uint8_t c[MSG_LENGTH_MAX];
	while(uart_irq_update(dev) && (uart_irq_rx_ready(dev) == 1 || uart_irq_tx_ready(dev) == 1)) {
		uint8_t tx_r = uart_irq_tx_ready(dev);

		if (tx_r == 1) {
			LOG_INF("tx");
			uint8_t data = 0;
			uint32_t count = 0;
			uint8_t buf[MSG_LENGTH_MAX] = {0};
			while (k_msgq_get(&serial_tx_raw_q, &data, K_NO_WAIT) == 0) {
				buf[count] = data;
				count++;
				if (count == MSG_LENGTH_MAX) {
					LOG_ERR("BUFFER OVERFLOW!");
					break;
				}
			} 
			if (count != 0) {
				int8_t num = uart_fifo_fill(dev, buf, count);
				if (num != count) {
					LOG_ERR("!!!!!COULD NOT SEND ALL DATA!!!!! (%d/%d)", num, count);
				}
			} else {
				LOG_WRN("nothing to send");
			}

			uart_irq_tx_disable(dev);
			count = 0;
			k_sem_give(&tx_byte_sync);
		}

		while (uart_irq_rx_ready(dev) == 1) {
			LOG_INF("rx");
			uint8_t read_bytes = 1;
			
			while(read_bytes > 0) {
				read_bytes = uart_fifo_read(dev, c, sizeof(c));
				LOG_INF("num: %d", read_bytes);
				for (uint8_t i = 0; i < read_bytes; i++) {
					LOG_INF("%x", c[i]);
					int status = k_msgq_put(&serial_rx_raw_q, &c[i], K_NO_WAIT);
					if (status != 0) {
						LOG_ERR("Error while putting on queue: %d", status);
						k_oops();
					}
				}
			}
		}
	}
}

Related