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

nRF9160 UART: Loosing data when RxData is split into 2 buffers (Async API)

Hello everyone,

 

I am currently using the Nordic-Thingy-91 to test the nRF9160. Now I am trying to receive Data from the UART interface using the "UART Async API".

 

I am switching between three 64 bytes buffers to ensure continuous reception of data.

And that is where run into a problem when the receiving data is split into two buffers, due to one buffer running out of space.

 

I am using Putty to send data and I am not sending byte for byte, I am sending multiple bytes at once.

As long as the received data fits into the current buffer, everything is fine.

But if the RX data doesn't fit into to current buffer and the second buffer is used too, I loose data.

 

For example:

RxBuffer1 and RxBuffer2 each have 64 bytes.

 

RxBuffer1 has only 4 bytes left.

I send 10 bytes of data from Putty to the board.

 

Expected behaviour:

  • RX_RDY event for the 4 bytes in RxBuffer1
  • Another RX_RDY event for the remaining 6 bytes in RxBuffer2

 

Actual behaviour:

  • RX_RDY event for the 4 bytes in RxBuffer1
  • Another RX_RDY event, but the event data says there is only 1 byte in RxBuffer2
    --> so I loose 5 bytes of data

 

For RX_BUF_REQUEST events I provide the API with the next buffer, to ensure continuous reception.

 

Here are two Screenshots of exactly this case. I have marked the 3 buffers in the memory window.

The red entries in the memory view is the new data which is split into 2 buffers.

So there are 4 new bytes in the first buffer and 6 new bytes in the second buffer.

 

Here is the first RX_RDY event which gives me 4 bytes in the first buffer. Everythings is fine..

 

 

The second RX_RDY event, which is shown next, says there is only 1 byte new in the second buffer, even though I can see there is actually more data in the memory.

 

 

So all the data is received and correctly stored in the memory, but the second RX_RDY event for the second buffer only gives me 1 byte, even though there are more…

 

Has anyone experienced a similar problem and can help me with this issue? Or is this a known issue?

 

I have also looked into the Zephyr driver test under *\v1.5.0\zephyr\tests\drivers\uart\uart_async_api but this test only sends/receives data which fits perfectly into the buffer.

 

Here is my prj.conf and main.c I use:

prj.conf:

# UART
CONFIG_SERIAL=y
CONFIG_UART_ASYNC_API=y # Enable Async API

# Enable UART console, for printk()
CONFIG_CONSOLE=y
CONFIG_UART_CONSOLE=y

main.c

#include <string.h>
#include <zephyr.h>
#include <device.h>
#include <devicetree.h>
#include <drivers/uart.h>
#include <sys/printk.h>

// UART0 device
#define UART_DEV DT_LABEL(DT_NODELABEL(uart0))
//#define UART_DEV  DT_LABEL(DT_ALIAS(serial0)) // also works

// Rx Buffers
static uint8_t rx_buf0[64];
static uint8_t rx_buf1[64];
static uint8_t rx_buf2[64];

// Callback for asynchron UART communication
static void uart_CB(const struct device *dev, struct uart_event *evt, void *user_data)
{
	static uint8_t lineBuffer[64];
	static int lineLength = 0;
	static uint8_t * buffers[3] = { rx_buf0, rx_buf1, rx_buf2 };
	static uint8_t index = 1;

	switch (evt->type)
	{
	case UART_RX_RDY:

		if(evt->data.rx.len > 0)
		{
			//printk("UART RX reading %d bytes from buffer %p with offset %d\n", evt->data.rx.len, evt->data.rx.buf, evt->data.rx.offset);
			memcpy(lineBuffer+lineLength, evt->data.rx.buf + evt->data.rx.offset, evt->data.rx.len);
			lineLength += evt->data.rx.len;

			if(lineBuffer[lineLength-1] == '\n' || lineBuffer[lineLength-1] == '\r')	// echo line
			{
				int ret = uart_tx(dev, lineBuffer, lineLength, SYS_FOREVER_MS);

				if (ret != 0)	
                    printk("uart_tx() failed, returned: %d\n", ret);

				lineLength = 0;
			}
		}
		
		break;

	case UART_RX_BUF_REQUEST:
		printk("Event: UART_RX_BUF_REQUEST\n");
		uart_rx_buf_rsp(dev, buffers[index], 64); // switch between 3 buffers
		index = (index + 1) % 3;
		break;

	case UART_RX_DISABLED:
		printk("Event: UART_RX_DISABLED\n");
		uart_rx_enable(dev, evt->data.rx_buf.buf, 64, 100); // re-enable rx
		break;

	case UART_RX_BUF_RELEASED:
		printk("Event: UART_RX_BUF_RELEASED, buf = %p\n", evt->data.rx_buf.buf);
		break;

	case UART_TX_DONE:
		printk("\nuartCB() callback: TxDone sent %d bytes\n", evt->data.tx.len);
		break;
		
	default:
		printk("Unexpected event type in callback: %d\n", evt->type);
		break;
	}
	
}

void main(void)
{	
	int ret = 0;

	const struct device *uart_dev = device_get_binding(UART_DEV);

	if (uart_dev == NULL) {
		printk("Failed to get UART device\n");
	}

	// register callback function
	ret = uart_callback_set(uart_dev, uart_CB, NULL);

	if (ret != 0) {
		printk("uart_callback_set() failed, returned: %d\n", ret);
	}

	ret = uart_rx_enable(uart_dev, rx_buf0, 64, 10);

	if (ret != 0) {
		printk("uart_rx_enable() failed, returned: %d\n", ret);
	}

	while (1)
	{		

	}
}

Parents Reply
  • I have seen the option of using hardware rx counting with the UART_0_NRF_HW_ASYNC kconfig option. How do I use this properly?

    I tried to just add 

    CONFIG_UART_0_NRF_HW_ASYNC=y
    to my prj.conf file, but I can't build my application anymore.
    In Kconfig.nrfx it says that Hardware RX byte counting requires a timer instance and one PPI channel. 
    What do I have to do, to properly enable this feature?
Children
  • Hi,

     

    WaStefan said:
    CONFIG_UART_0_NRF_HW_ASYNC=y
    to my prj.conf file, but I can't build my application anymore.
    In Kconfig.nrfx it says that Hardware RX byte counting requires a timer instance and one PPI channel. 
    What do I have to do, to properly enable this feature?

    Try setting this in your prj.conf to get it to build properly:

    # Async
    CONFIG_UART_0_ASYNC=y
    CONFIG_UART_0_NRF_HW_ASYNC=y
    CONFIG_UART_0_NRF_HW_ASYNC_TIMER=1
    CONFIG_NRFX_TIMER=y
    CONFIG_NRFX_TIMER1=y

     

    Kind regards,

    Håkon

  • Hello Håkon,

    Thank you very much, it builds now with this configuration.

    Everything works now, when using Hardware RX byte counting. I don't loose any bytes.

    Thank you again for your help!

    I will use this configuration from now on.

  • Hi,

     

    WaStefan said:

    Thank you very much, it builds now with this configuration.

    Everything works now, when using Hardware RX byte counting. I don't loose any bytes.

    Thank you again for your help!

    I will use this configuration from now on.

    This is great to hear! I'm happy to help and glad to hear that the issue has disappeared!

    Kind regards,

    Håkon

      

  • I had the same issue with nrf52832.

    I used two buffers for swapping.

    I had 2 buffers of size 4 and I was expecting a message with 6 bytes.

    After the buffer was full I received the first 4 bytes (as expected) and the buffer was full.

    I got the UART_RX_BUF_RELEASED and UART_RX_BUF_REQUEST and handling the last event I swapped the buffers.

    Then I got the UART_RX_RDY, but instead of receiving the 2 remaining bytes, I received only one.

    The 6th byte wasn't lost. It just didn't raise the UART_RX_RDY event.

    After I requested the next bunch of 6 bytes, the first byte that arrived was the one missing from the previous message. Nothing was lost, but I couldn't find any way to overcome this bug, as I had to initiate the next exchange of data to get the last bytes from the previous...

    The problem has been solved after including in prj.conf the following (as suggested):

    CONFIG_UART_0_NRF_HW_ASYNC=y
    CONFIG_UART_0_NRF_HW_ASYNC_TIMER=1
    #CONFIG_NRFX_TIMER=y (this was not accepted for nrf52832, it was by default activated and I had no access)
    CONFIG_NRFX_TIMER1=y
    I post this just to thank  and  !
    And, for anyone else that runs on the same issue.
Related