Electrical – UART read consistently missing half of the transmitted bytes


I have setup a simple UART test on my SAML21 and believe I must be misusing the library due to the behavior I'm seeing

uint8_t testData[8] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06}

void broadcast_test_data(void)
    usart_write_buffer_wait(&usart_instance, testData, sizeof(testData))

void serial_data_handler(void)
    unit16_t rxInt;
    if (usart_read_wait(&usart_instance, &rxInt) == STATUS_OK) {
        printf("RX %d", rxInt);

int main(void)
    struct usart_config config_usart;

    config_usart.baudrate = 1000;
    config_usart.mux_setting = USART_RX_3_TX_2_XCK_3;
    config_usart.pinmux_pad0 = PINMUX_UNUSED;
    config_usart.pinmux_pad1 = PINMUX_UNUSED;
    config_usart.pinmux_pad2 = PINMUX_PA24C_SERCOM3_PAD2;
    config_usart.pinmux_pad3 = PINMUX_PA24C_SERCOM3_PAD3;


    while (1) {
        // run-loop

I verified that the TX data is transmitting the entire testData array via Putty.

The issue is that when I tie the RX and TX together to test receiving, I am only ever getting bytes (0x01, 0x02, and 0x06). Is polling for RX data via the while loop not the way I should be doing this? Do I need to somehow mark data as read before UART moves onto the next received byte? Should I be asking for more than 1 byte at a time?

Thanks for any info you can provide

Best Answer

The issue here is that both usart_write_buffer_wait() and usart_read_wait() are blocking. The USART hardware seems to have a 2 byte FIFO buffer on RX.

Now what happens is the RX FIFO is filled during writing, and usart_write_buffer_wait returns during the transmission of the last character.

As soon as usart_read_wait is called - which can only happen after usart_write_buffer_wait due to it being a blocking function, it reads the first 2 bytes from the fifo. The following bytes are missing due to fifo overflow - check hardware status registers, they should tell you that. The last byte is received and read once the usart finished the transmission's stop bit.

Workaround: Use interrupts or DMA for RX, TX or both.