megaAVR® USART Configuration
Overview
In this section, we will cover the basic coding steps required to configure/use the USART module in a megaAVR® MCU, with a focus on the ATmega328PB device.
The USART module consists of three main sections, Clock Generator, Transmitter, and Receiver, as shown in the following diagram:
Using the USART (Summary)
For basic polled operation, the following minimum steps need to be performed:
- Choose a baud rate and program the UBRRn[H:L] registers accordingly.
- Enable the USART serial transmit and receive sections.
- If transmitting, wait until the transmit shift register is empty (poll on UCSRnA.UDREn), then load your data byte into UDRn.
- If receiving, wait until the receiver data-received bit is set (poll on UCSRnA.RXCn), then read the data out of UDRn. Reading UDRn auto-clears the bit, and prepares the hardware to receive the next byte.
Initialization
The USART has to be initialized before any communication can take place. The initialization process normally consists of:
- Setting the baud rate,
- Setting frame format and
- Enabling the Transmitter or the Receiver depending on the usage.
Setting the Baud Rate
Internal clock generation is used for the Asynchronous mode of operation. The Clock Generation logic generates the base clock for the Transmitter and Receiver (key registers and control bits are highlighted):
USART Mode Select (UMSELn)
The baud rate equation used by the module is set based on the operating mode. For asynchronous mode operation, the USART Mode Select bits in the USART Control and Status Register C (UCSRnC.UMSELn[1:0]) are used to select asynchronous operation (UMSEL[1:0] = 00) as shown:
Double-Speed Mode (U2Xn)
For asynchronous mode, the USART TX rate can be doubled by setting the U2Xn bit in the UCSRnA register (UCSRnA.U2Xn = 1).
Baud Rate Register (UBRRn)
The USART Baud Rate Register (UBRRn) and the down-counter connected to it function as a programmable prescaler or baud rate generator. The down-counter, running at system clock (fosc), is loaded with the UBRRn value each time the counter has counted down to zero or when the UBRRnL Register is written. A clock is generated each time the counter reaches zero. This clock is the baud rate generator clock output (= fosc/(UBRRn+1)). The Transmitter divides the baud rate generator clock output by 2, 8, or 16 depending on the mode. The baud rate generator output is used directly by the Receiver’s clock and data recovery units. However, the recovery units use a state machine that uses 2, 8, or 16 states depending on the mode set by the state of the UMSEL, U2Xn, and DDR_XCK bits.
Table 24-1 contains equations for calculating the baud rate (in bits per second) and for calculating the UBRRn value for each mode of operation using an internally generated clock source.
- BAUD: Baud rate (in bits per second, bps)
- fOSC : System oscillator clock frequency
- UBRRn: Contents of the UBRRnH and UBRRnL Registers, (0-4095).
Setting the Frame Format
USART Control and Status Register C (UCSRnC) is used to configure the UART communication frame format—parity, number of stop bits, and number of data bits. Settings for the typical “8N1” frame format are as follows:
- UPM[1:0] = 00 for No Parity
- USBS = 0 for 1 Stop Bit
- UCSZ1[1:0] = 11 for 8 Bits
Enabling the Transmitter
The USART Transmitter is enabled by setting the Transmit Enable (TXEN) bit in the UCSRnB register:
When the Transmitter is enabled, the normal port operation of the TxDn pin is overridden by the USART and given the function as the Transmitter’s serial output.
Enabling the Receiver
The USART Receiver is enabled by writing the Receive Enable (RXEN) bit in the UCSRnB Register to ‘1':
When the Receiver is enabled, the normal port operation of the RxDn pin is overridden by the USART and given the function as the Receiver's serial input.
Code Example
The following USART initialization code example uses the setbaud utility library in AVR-LIBC. This library provides macros that use the c-preprocessor to calculate appropriate values for UBBRn.
Inputs
This header file requires that on-entry values are already defined for F_CPU and BAUD. In addition, the macro BAUD_TOL will define the baud rate tolerance (in percent) that is acceptable during the calculations. The value of BAUD_TOL will default to +/- 2%.
Outputs
Assuming that the requested BAUD is valid for the given F_CPU then the UBRR_VALUE macro is set to the required prescaler value. Two additional macros are provided for the low and high bytes of the prescaler, respectively; UBRRL_VALUE is set to the lower byte of the UBRR_VALUE, and UBRRH_VALUE is set to the upper byte. An additional macro, USE_2X, will be defined. Its value is set to 1 if the desired BAUD rate within the given tolerance could only be achieved by setting the U2Xn bit in the UART configuration. It will be defined as 0 if U2Xn is not needed.
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#define BAUD 38400UL desired baud
#define BAUD_TOL 2 desired baud rate tolerance (+/- %)
#include <avr/io.h>
#include <util/setbaud.h>
void USART0_Init(void){
Set the BAUD rate
UBRR0H = UBRRH_VALUE;
UBRR0L = UBRRL_VALUE;
#if USE_2X USE_2X defined by setbaud.h based on inputs
UCSR0A |= (1 << U2X0);
#else
UCSR0A &= (1 << U2X0);
#endif
Set the Mode & Frame Parameters
UCSR0C = 0x06; Asynchronous, 8-data, No parity, 1-stop
Enable USART0 Transmitter and Receiver
UCSR0B = (1 << TXEN0) | (1 << RXEN0);
}
Data Communications
Transmit
Data transmission is initiated by loading the transmit buffer with the data to be transmitted. The CPU can load the transmit buffer by writing to the UDRn register. For polled operation, firmware should monitor the data-register-empty flag (UCSRnA.UDREn) before loading UDRn.
The buffered data in the transmit buffer will be moved to the Shift Register when the Shift Register is ready to send a new frame. The Shift Register is loaded with new data if it is in an Idle state (no ongoing transmission) or immediately after the last stop bit of the previous frame is transmitted. When the Shift Register is loaded with new data, it will transfer one complete frame at the rate given by the Baud Register.
Receive
The Receiver starts data reception when it detects a valid start bit. Each bit that follows the start bit will be sampled at the baud rate or XCKn clock, and shifted into the Receive Shift Register until the first stop bit of a frame is received. The receive buffer can then be read by reading the UDRn register. The complete reception of a byte can be checked by polling the RXCn bit in UCSRnA register.
Code Example
The following simple blocking APIs send and receive a byte of data via USART0.
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Wait for empty transmit buffer
while(!(UCSR0A & (1 << UDRE0)));
Put data into buffer, sends the data
UDR0 = data;
}
unsigned char USART0_Receive(void){
Wait for data to be received
while(!(UCSR0A & (1 << RXC0)));
Get and return received data from buffer
return UDR0;
}