USART

USART is a universal synchronous serial interface; UART, is a simplified version - universal asynchronous serial interface. The difference being that USART also uses a clock signal line to synchronize data, but UART only uses data lines. AVR's USART allows the use of full duplex communication, 5- to 9-bit data words (8-bit word = byte), 1 or 2 stop bits, three parity modes and a wide variety of baud rates. AVR microcontrollers typically have up to 2 USART interfaces, although some may have no USART. Data transmission is performed one word at a time - AVR converts the word it gets from the user to bits on the hardware level and transmits it independently and vice versa. The user controls USART by reading and writing configuration, status and data registers.

Every configuration option has corresponding registers, which are quite easy to configure using the datasheet. The baud rate, though, is a bit more difficult to set. The clock signal for data transmission is generated from the controller's own clock, and the user can specify a number from 1 to 4096, by which the controller's clock cycle is divided. The result is additionally divided by 2, 8 or 16, depending on the mode. The problem is, not all clock frequencies can be divided so that the result is a standard baud rate. With some frequencies, the baud rate can differ from the standard by up to 10%. AVR datasheets contain tables with typical clock frequencies, baud rates, the needed multiplier to reach that baud rate and the possible calculation error.

Since data transmission takes place independently of the processor and much slower, it is necessary to confirm that the interface is ready for the next word before transmitting. This can be done by keeping an eye on the transmit buffer's ready bit, which signifies if the buffer is ready to accept a new word or not. The controller starts with the ready bit enabled. As soon as a word is transmitted and the buffer is empty, the ready bit is set high.

The arrival of a word is signified also by a special status bit. In addition to that, there are status bits to signify framing errors, parity errors and receive buffer overflows. Buffer overflow can occur when the last word is yet to be read from the buffer while a new one arrives - this is why it is always important to read the incoming words to the program as soon as possible, for example, by using an interrupt. There are three possible interrupt reasons: transmit buffer ready, transmit successful and receive successful.

The transmit and receive buffers are physically separate registers, but share the same memory address and name. When writing to the shared register, the data is stored in the transmit buffer, and when reading from it, the data is read from the receive buffer. When using 9-bit words, the 9th bit is transmitted and read using one of the configuration registers.

 

Example

Task: Configure an 8 MHz ATmega128's USART0 interface to transmit 8-bit words asynchronously using 9600 bps baud rate, 1 stop bit and no parity bits. Send the symbol “X”.

#include <avr/io.h>
 
int main()
{
	// Set baud rate to 9600 bps. Formula:
	//   multiplier = clock frequency / 16 / baud rate - 1
	//   UBRR = 8000000 / 16 / 9600 - 1 = ~51
	UBRR0H = 0;
	UBRR0L = 51;
 
	// Allow transmitting
	UCSR0B = (1 << TXEN0);
 
	// Configure asynchronous mode, set the word size to 8 bits
	// 1 stop bit, no parity bits.
	UCSR0C = (1 << UCSZ01) | (1 << UCSZ00);
 
	// Wait for the data buffer to empty (previous word to transmit)
	// In this example there is no need to wait, as the first symbol is yet
        // to be sent, but it should be done when transmitting more symbols.
	while (!(UCSR0A & (1 << UDRE))) continue;
 
	// Write the symbol to the buffer for transmitting
	UDR0 = 'X';
 
	// Endless loop
	while (1) continue;
}