XMEGA USART driver with TX DMA

This is a quite universal, non-blocking UART driver for XMEGA. It supports both transmission (with optional DMA) and reception. Receive side can deliver callbacks whenever a complete line (terminated with \n) is received or received bytes can be retrieved one-by-one from a ringbuffer (more useful for GPS units). This driver can support multiple hardware USARTs in a single application.

Usage example

This is a real world usage example of this driver with a GPS unit. Due to bursty GPS transmission (a couple of NMEA sentences at once) I had to use a ringbuffer instead of a callback every line, because the time spent analyzing a sentence was too long and some sentences were randomly lost.


In order to use the ringbuffer the application has to keep:

  • uart_state_t structure
  • a generic buffer (_gps_line_buffer) for the exclusive use by the driver – in this case this is used as a ringbuffer for reception or as a linear buffer for transmission
  • optionally – another buffer to logically process the received bytes one by one

Initilization and interrupts

The application passes pointers to USART, optionally DMA channel. Line callback is not used in this case. Last arguments are the buffer and its size.

In order to reduce GPS refresh rate (I don’t need an update every second) a special command is sent to the GPS (buffer is taken using get_uart_buffer and filled with sprintf).

The application also has to declare interrupts as shown – in this case the USART RX interrupt (with ringbuffer isr functions) and DMA channel interrupt.

Using DMA to transmit single command is of course an overkill, but it gives the general usage idea of the driver.

Receiving data

The gps_uart_task is called from the main loop. It tries to receive as many bytes from the UART RX buffer as possible until a newline is encountered.

If line callback mode is used, then a function taking a string as an argument has to be implemented and passed to uart_init. Main loop has to keep calling uart_task and the function called from RXC ISR has to be uart_rx_isr.


Most parts are similar to my SPI driver. Have a look for a detailed overview.


All the functions have doxygen comments that should make their intended use understood.


Rate this post