NCS UARTE1 receiver (UART_RX_RDY) returns wrong (short) buffer length

Hi Team,

I think I've found an issue when using the nrFX UARTE1 Zephyr driver.  I'm building an application based on the Bluetooth peripheral UART sample.

I use 20 byte buffers.  In the attached log you can see that I've sent 44 bytes and received 44 bytes. Then I send the 44 bytes again and only receive 43, but in this case the last buffer contains the 4 bytes sent but the length is passed with the value of 3. This occurs about 20% of the time.  Because the last '\r' character is not found the UART disable-enable doesn't occur and a new buffer is not allocated.  Then I get bus fault trying to free an already freed buffer. (see the last section of the log).  What might be the problem here?

 case UART_RX_RDY:
        buf = CONTAINER_OF(evt->data.rx.buf, struct uart_data_t, data);
        buf->len += evt->data.rx.len;
        buf_release = false;

        
        LOG_INF("Data to Rx FIFO, %u bytes", buf->len);
        if (buf->len == UART_BUF_SIZE) 
        {
            k_fifo_put(&fifo_uart_rx_data, buf);
            // UART will get a new Rx buffer from call to UART_RX_BUF_REQUEST in this case
        } 
        else if ((evt->data.rx.buf[buf->len - 1] == '\n') ||
              (evt->data.rx.buf[buf->len - 1] == '\r'))
        {
            // End of packet found
            k_fifo_put(&fifo_uart_rx_data, buf);
            evt->data.rx.len = 0;
            current_buf = evt->data.rx.buf;
            buf_release = true;
            uart_rx_disable(uart);
        }
        else
            LOG_INF("UART buf not full");
        
        break;    

Also, why do we have to find an end of packet char and disable the uart rx? Shouldn't the driver reset the buffer pointers to the start of the buffer after the Rx timeout?  Currently the next bytes received are added to the end of the last few bytes received before another timeout or full buffer.

Why do you need the += in the  buf->len += evt->data.rx.len; line?

I'm using NCS 1.6.1

Thanks in advance.

Simon

   

Parents Reply Children
  • Hi Simon,

    After further development and many Hard Faults...I think I've found a fix for my issue. I can still get the wrong length value passed to the UART_RX_RDY event but this doesn't happen very often and is handled by packet and message validation built into our protocol.

    According to the Zephyr documentation for the Uart interface UART_RX_RDY event can be generated multiple times, passing the same buffer, with more data (after a timeout). The next buffer is not used until the first one is full or has been released after a call to uart_rx_disable().  The main problem with the Bluetooth Peripheral Uart sample code is that the second UART_RX_RDY event (after uart_rx_disable() ) which is called before UART_RX_BUF_RELEASED is not handled when the user is not using '\n' or '\r' to find the end of the data packet.

    In my case the first received is put into the FIFO for later processing, and the second event is ignored.

    case UART_RX_RDY:
    		LOG_DBG("rx_rdy");
    		buf = CONTAINER_OF(evt->data.rx.buf, struct uart_data_t, data);
    		buf->len += evt->data.rx.len;
    		//buf_release = false;
    
    		if (buf->len == UART_BUF_SIZE) {
    			k_fifo_put(&fifo_uart_rx_data, buf);
    		} 
    		else if (buf_release)
            {
                // buffer has already been processed and has likely been free'd 
                // UART_RX_RDY can be called again with the same buffer after uart_rx_disable()
                printk("already released\n");
            }	
    		else  {
    			k_fifo_put(&fifo_uart_rx_data, buf);
    			current_buf = evt->data.rx.buf;
    			buf_release = true;
    			uart_rx_disable(uart);
    		}
    		break;

    This works well now even after going back up to 115200 Baud.

Related