UART_RX_RDY event in Zephyr UART Asynchronous API doesn't give all sent bytes

I'm trying to approach to the Zephyr UART Asynchronous API in SDK 2.5.1 and in the first time I'm testing only the receiving. My simplified code is 

 

#define UART_BUF_SIZE		                            16
#define UART_RX_TIMEOUT_MS	                            100

static uint8_t uartDoubleBuffer[ 2 ][ UART_BUF_SIZE ];
static uint8_t *uartBufNext = uartDoubleBuffer[ 1 ];

void Connection_Initialize( void )
{
	uart_callback_set( serialDev, Connection_Async_Callback, NULL );
	uart_rx_enable( serialDev, uartDoubleBuffer[ 0 ], UART_BUF_SIZE, UART_RX_TIMEOUT_MS );
}

void Connection_Async_Callback( const struct device *dev, struct uart_event *evt, void *userData )
{
    ARG_UNUSED( userData );
	
	switch ( evt->type )
	{
		case UART_TX_DONE:
		{
			LOG_INF( "UART_TX_DONE" );
			break;
		}
		
		case UART_RX_RDY:
		{
			LOG_INF( "UART_RX_RDY - received %d bytes", evt->data.rx.len );
			break;
		}
		
		case UART_RX_BUF_REQUEST:
		{
			LOG_INF( "UART_RX_BUF_REQUEST" );
			uart_rx_buf_rsp( serialDev, uartBufNext, UART_BUF_SIZE );
			break;
		}

		case UART_RX_BUF_RELEASED:
		{
			LOG_INF( "UART_RX_BUF_RELEASED" );
			uartBufNext = evt->data.rx_buf.buf;
			break;
		}

		case UART_RX_DISABLED:
		{
			LOG_INF( "UART_RX_DISABLED" );
			break;
		}
		
		default:
		{
			break;
		}
	}
}

Now if I send to my custom board 7 bytes via uart the UART_RX_RDY event rerurns to me not all bytes but always fewer and it stops. In the following logs every row rappresent a sending of 7 bytes:

00> [00:00:14.206,573] <inf> usb_connection: UART_RX_RDY  - received 1 bytes
00> [00:00:23.725,830] <inf> usb_connection: UART_RX_RDY  - received 5 bytes
00> [00:00:25.374,267] <inf> usb_connection: UART_RX_RDY  - received 10 bytes

In the following sendings I can get the lost bytes, but if I want to send only one packet it won't be received.

What am I doing wrong?

EDIT: I noticed that if I send a packet of 16 byte (the length of API's buffers) I get the right behaviour where UART_RX_RDY gives me the correct bytes number received

 

00> [00:00:01.740,661] <inf> usb_connection: UART_RX_RDY - received 16 bytes
00> [00:00:01.740,692] <inf> usb_connection: UART_RX_BUF_RELEASED
00> [00:00:01.740,692] <inf> usb_connection: UART_RX_BUF_REQUEST
00> [00:01:10.072,387] <inf> usb_connection: UART_RX_RDY - received 16 bytes
00> [00:01:10.072,418] <inf> usb_connection: UART_RX_BUF_RELEASED
00> [00:01:10.072,448] <inf> usb_connection: UART_RX_BUF_REQUEST
00> [00:01:11.766,571] <inf> usb_connection: UART_RX_RDY - received 16 bytes
00> [00:01:11.766,601] <inf> usb_connection: UART_RX_BUF_RELEASED
00> [00:01:11.766,632] <inf> usb_connection: UART_RX_BUF_REQUEST
00> [00:01:13.214,416] <inf> usb_connection: UART_RX_RDY - received 16 bytes
00> [00:01:13.214,447] <inf> usb_connection: UART_RX_BUF_RELEASED
00> [00:01:13.214,447] <inf> usb_connection: UART_RX_BUF_REQUEST

but if I send a packet less than the length of API's buffers UART_RX_RDY gives me a smaller number than the bytes sent. i.e. if I send 14 bytes, in the first sending I get

00> [00:00:07.343,170] <inf> usb_connection: UART_RX_RDY - received 13 bytes

and in the second sending I get

00> [00:00:10.390,441] <inf> usb_connection: UART_RX_RDY - received 3 bytes
00> [00:00:10.390,472] <inf> usb_connection: UART_RX_BUF_RELEASED
00> [00:00:10.390,502] <inf> usb_connection: UART_RX_BUF_REQUEST
00> [00:00:10.391,265] <inf> usb_connection: UART_RX_RDY - received 2 bytes

I tryed to remove the LOG macros and clear the code as much as possible but nothing changed.

Parents
  • Hi Andrea

    I made a wrapper for the UART async driver some way back to handle buffering in a static way and provide a simpler application interface, you might want to have a look at that for inspiration:
    https://github.com/too1/ncs-uart-handler

    With that said I believe your issue is related to the way the UART async driver counts incoming bytes. In the default configuration the driver relies on a an interrupt to count every received byte, and this method can be unreliable if you have a lot of other interrupts occurring in your application, or if the UART baudrate is set to a high value. 

    There is a way to use a hardware timer instead to count incoming bytes which should make the driver more reliable. 

    In order to have the UART async driver use TIMER1 to count bytes for UART0 you need to add the following lines to your project configuration:

    CONFIG_UART_0_NRF_HW_ASYNC=y
    CONFIG_UART_0_NRF_HW_ASYNC_TIMER=1

    Could you give this a go and see if it solves the issue? 

    Best regards
    Torbjørn

  • Hi Torbjørn,

    thank you very much for that hint!
    I had a simuliar issue where after providing a second buffer for continuous reception (preallocated, so should be quite fast) the remaining bytes were incorrect on the next UART_RX_RDY (always 1, expected more). This led to my next packets containing the remaining part of the previous one and only a part of the new one.

    Adding the provided configuration fixed that issue for me.

    Best regards,
    Lars

Reply
  • Hi Torbjørn,

    thank you very much for that hint!
    I had a simuliar issue where after providing a second buffer for continuous reception (preallocated, so should be quite fast) the remaining bytes were incorrect on the next UART_RX_RDY (always 1, expected more). This led to my next packets containing the remaining part of the previous one and only a part of the new one.

    Adding the provided configuration fixed that issue for me.

    Best regards,
    Lars

Children
No Data
Related