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

  • \$\begingroup\$ When you call usart_read_wait, right now if it returns an error you're just ignoring it. I would suggest changing your code to print out at least what error code you've gotten, if you don't get STATUS_OK. That might be informative. I'm not sure what could cause a problem like this but more data's always helpful. \$\endgroup\$ – Glenn Willen Aug 22 at 0:09
  • \$\begingroup\$ How is printf implemented in your system? Does your UART library or hardware have a receive buffer for more than 1 byte? \$\endgroup\$ – brhans Aug 22 at 0:49
  • \$\begingroup\$ asf.atmel.com/docs/latest/samd21/html/… \$\endgroup\$ – Bruce Abbott Aug 22 at 1:17

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.

  • \$\begingroup\$ Thank you, I added interrupts and it works great when I tie RX and TX together. But when I connect to the transmitting device I never get an RX interrupt, is this something that the other device has to support? Should I switch to DMA in this case? \$\endgroup\$ – davis Aug 27 at 3:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.