Electrical – UART read consistently missing half of the transmitted bytes

atmelmicrocontrollerserialuart

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;
    usart_get_config_defaults(&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;

    usart_enable(&usart_instance);

    while (1) {
        // run-loop
        SYSTEM_RunTasks();
        serial_data_handler();
    }
}

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.