Page 1 of 1

STM32 Programming. Part 16: USART

Posted: 17 Oct 2023, 07:09
by Oleg
image.png
image.png (17.35 KiB)
Viewed 3540 times
Many of those who have had any dealings with microcontrollers, such as PIC and AVR, know about such a thing as UART. Universal asynchronous receiver transmitter - Universal asynchronous receiver transmitter is built as a peripheral device in any modern MC, and in some MCs it is not represented in a single copy. There is also some confusion about what is UART and what is USART. Universal synchronous asynchronous receiver transmitter (USART) - universal synchronous / asynchronous transceiver fully repeats the functionality of UART, which operates in asynchronous mode, and includes synchronous mode. In this case, the communication between the two USART devices is a bit like the SPI interface: in addition to the RX and TX signals, another one is added: CK, which carries the clock signal from the master USART module to the slave. In this article we will consider the simplest and most popular case, namely the usual asynchronous mode of USART operation in the microcontroller stm32f103c8.

Introduction

There are 3 USART modules built into the stm32f103c8 microcontroller, which can be configured quite flexibly to suit your needs. Among the features are the following:
  • full duplex;
  • the ability to work in half-duplex mode on a single wire;
  • fractional setting of the USART rate divider. This allows you to adjust the transmission rate with zero error on "inconvenient" for USART quartz resonators;
  • customizable transmit data size of 8 or 9 bits;
  • configurable number of stop bits;
  • possibility to work with DMA;
  • various accessories for working with IR port (IrDA), with smart cards, etc.
Description of USART operation

Within the framework of this article we will touch only on such concepts as the format of transmitted data (number of bits, parity, stop bits) and interrupts USART. Everything related to hardware flow control, IR port, smart cards, synchronous mode, etc. we will omit. Also we will not study the operation of USART together with DMA.

First, let's take a look at the USART block diagram
Figure 1. USART block diagram
image.png (91.66 KiB)
Figure 1. USART block diagram Viewed 3540 times
Does it look terrifying? Let's go over the basics.

Shift registers and data registers
The main part of any serial data interface is the shift register. In USARTs there are 2 of them: one for transmitting (Transmit Shift Register) and one for receiving (Receive Shift Register). Each of these shift registers has its own data buffer register: Transmit Data Register (TDR) and Receive Data Register (RDR).

In order to send a word of data to the USART (intentionally I say "word" rather than "byte" because the word size can be 8 or 9 bits), it must be loaded into the Transmit Data Register TDR. Once written to the TDR, this value will "fail" into the transmitter shift register and the transmit process will be started. It is worth noting that once the value from the TDR has been sent to the shift register, more data can be loaded into the TDR, which will be there waiting for the end of the transfer from the shift register. Thus, we have a buffer for 2 words: one is in the shift register, the other in the TDR, which allows you to transmit data on USART a continuous stream without pauses between neighboring transmissions.

In a similar way is performed and the reception of data. After the data is received by the shift register of the receiver, they fall into the RDR register, and the receiver is immediately ready to receive the next word of data. Here we also have a buffer for 2 words, one in the shift register, the other in the RDR. Thus, we have the ability to receive a continuous stream of data without pauses between neighboring transmissions.

In STM32F103C8 registers TDR and RDR are not directly accessible programmatically. For this purpose, the DR (Data register) is used. During a write operation to the DR, the written value falls into the TDR register, and when reading from the DR will read the value of RDR. In other words, receiving and transmitting data from the firmware side will look like accessing the same DR register.

Flags and interrupts

In the module USART microcontrollers STM32 microcontrollers have a sufficient number of various flags and interrupts, with which we can very conveniently realize the process of data exchange both on interrupts and the method of polling registers.

Let's briefly familiarize ourselves with some interesting flags. Let's consider the process of data transfer. If the transmitter register TDR is empty and the next word can be written into it, the special flag TXE (Transmit data register empty) will be set to 1 in the status register. It should be noted that setting the TXE flag to 1 does not mean that the data transfer process has ended. TXE only indicates that the next value can be written to the transmitter register.

In order to make sure that the data transmission on the Tx leg is complete, there is another flag in the status register: TC (Transmission complete). It is set only if the data transmission is complete and there is no next data in the transmitter register to load into the shift register (TXE flag is set). The TC flag can be useful when implementing an RS485 interface where the direction of the interface driver can only be switched after the data transfer is complete.

Let's move on to receiving data. There is a flag RXNE (Read data register not empty) in the status register. It is set to 1 if there is new data in the receiver buffer.

In addition, by setting one of the above flags to 1, it is possible to enable USART interrupt generation, which is very useful when transmitting data through interrupts.

Data transmission formats

The USART supports setting the following baud rates:
  • number of data bits (8 or 9)
  • parity (none, even, odd)
  • number of stop bits (0.5, 1, 1.5, 2).
There is one peculiarity worth mentioning here when exchanging data using parity control. Suppose we have selected 8 bits of data, 1 stop bit, then, if we do not use parity, the format of the USART frame will be as follows:
  • start bit; 8 data bits; stop bit
But, if we use parity control, which is like this:
  • start bit; 7 data bits; 1 parity bit; stop bit
In other words, if we want to configure data transmission of the form "8 data bits + parity bit", we must choose the word length not 8, but 9 bits. In one of my projects I encountered such a trick, as if everything was set up correctly, but the receiving side did not want to receive data. I figured it out with the help of an oscilloscope and thoughtful study of the manual.

Transmission speed

Those who have worked with AVR microcontrollers, know about special resonator frequencies, convenient for working with UART-om. In microcontrollers STM32 USART has a trickier implementation, which allows you to get zero deviation of the baud rate from standard values when working from the most common quartz, for example, 8 MHz (the table below shows the bus frequencies using PLL):
Figure 2. Error of baud rate generation for standard baud rate values
image.png (46.01 KiB)
Figure 2. Error of baud rate generation for standard baud rate values Viewed 3540 times
This is achieved by setting the baud rate division ratio fractionally. The BRR division ratio setting register consists of 2 parts: DIV_Mantissa and DIV_Fraction. Both of these values form a fixed point number: VAL = DIV_Mantissa,DIV_Fraction. However, the formulas and rules for calculating the DIV_Mantissa and DIV_Fraction values presented in the manual are very confusing, so simplifying these calculations we get the following formula for calculating the BRR value:

BRR = (uint16_t)(BUS_FREQ / BAUD)

BUS_FREQ - USART module clocking frequency (bus frequency)

BAUD - baud rate.

By the way, in the manual for other STM32 microcontrollers, for example, STM32F030, the formula for calculation is given immediately in a digestible form:
image.png
image.png (5.23 KiB)
Viewed 3540 times
I/O ports

Let's find out which GPIO pins the USARTs in the STM32F103C8 microcontroller are connected to. We open the Datasheet and find Table 5: Medium-density STM32F103xx pin definitions. It contains the following:

For USART1:

TX: PA9, Remap PB6
RX: PA10, Remap PB7

For USART2:
  • TX: PA2
  • RX: PA3
For USART3:
  • TX: PB10
  • RX: PB11
For USART1, remap of TX and RX pins to other I/O ports is available if the default pins are busy.

Let us now refer to section 9.1.11 GPIO configurations for device peripherals in the Reference manual to understand how to configure the I/O ports for USART operation:
image.png
image.png (32.7 KiB)
Viewed 3540 times
For the simplest full duplex mode without hardware flow control we need only TX and RX pins. The other pins can be used as normal GPIO ports.

So, the setup will be as follows:

TX: alternate function mode, push-pull or open collector output type
RX: input with no pull-up or pull-up type

USART registers
Status register (USART_SR) - status register

image.png
image.png (11.67 KiB)
Viewed 3540 times
TXE: Transmitter register empty. This bit is set in hardware when the contents of the TDR transmitter register (TDR is not directly accessible from the program, but it is accessed when writing to USART_DR) have been transferred to the shift register. If the TXEIE interrupt enable bit was set in USART_CR1, a USART interrupt request is generated at this point. TXE is reset when the value is written to the USART_DR data register.

TC: transmission complete. This bit is set by hardware if the UART has completed data transfer, with the TXE bit set to one. This bit can be useful for RS485 interface implementations to switch the direction of the RS485 driver. If the TCIE bit is set in the USART_CR1 register, a USART interrupt is generated when the TC bit is set. The TC bit is reset by the following program sequence: reading the USART_SR register followed by a write to the USART_DR register. In addition, the TC bit can be reset by writing to it the value 0, but it is recommended to do this only in the mode of joint work with DMA.

RXNE: the receiver register is not empty. This bit is set to one when the contents of the receiver shift register are transferred to the USART data register. If the RXNEIE bit in the USART_CR1 register is set, a USART interrupt request is generated. The RXNE bit is reset when the USART_DR data register is read. In addition, RXNE can be reset by writing a 0 to it, but it is recommended to do this only in DMA co-operative mode.

ORE: overflow error. Set to 1 if the data in the receiver shift register is ready to be transferred to the data register, but the RXNE bit is set. In other words, we have already received the next byte on USART, but have not yet read the previous byte. If the RXNEIE flag is set in the USART_CR1 register, a USART interrupt request is generated. The ORE bit is reset by the following program sequence: reading the USART_SR register followed by reading the USART_DR register.

Data register (USART_DR) - data register
image.png
image.png (9.56 KiB)
Viewed 3540 times
DR[8:0]: data. This register contains 2 shadow registers: TDR and RDR. When reading from DR the value of the receiver data register RDR will be read, when writing to DR the value will be written to the transmitter data register TDR. If parity control is used (the PCE bit in the USART_CR1 register is set to 1), then when writing to the DR the value of the high bit will be ignored, as it will be replaced by the parity bit during transmission. When receiving with parity enabled, the high bit will contain the parity bit.

Baud rate register (USART_BRR) - USART baud rate register
image.png
image.png (13.04 KiB)
Viewed 3540 times
The BRR register contains a division factor that sets the baud rate of USART.

BRR = (uint16_t)(BUS_FREQ / BAUD)

where BUS_FREQ is the frequency of the bus, on which hangs this USART

BAUD - the desired baud rate.

Control register 1 (USART_CR1) - configuration register 1



UE: enable USART.
  • 0: USART predividers and outputs are disabled
  • 1: USART enabled
M: data word length. This bit determines the length of the data to be transmitted. It is set and cleared by software.
  • 0: 1 start bit, 8 data bits, n stop bits
  • 1: 1 start bit, 9 data bits, n stop bits
PCE: Enable parity check. Set and cleared by program

PS: parity check type selection. This bit selects the parity option when the PCE bit is set. Set and cleared by software.
  • 0: Even
  • 1: Odd
TXEIE: Enable interrupt when the transmitter buffer is empty. If set to 1, a USART interrupt request is generated when the TXE bit of the USART_SR register is set.

TCIE: enable transmit end interrupts. If 1, a USART interrupt request is generated when the TC flag in the USART_SR register is set.

RXNEIE: enable interrupts when data appears in the receiver register. If 1, a USART interrupt request is generated when the RXNE or ORE flag is set in the USART_SR register.

TE: enable the USART transmitter

RE: enable USART receiver
image.png
image.png (13.04 KiB)
Viewed 3540 times
Control register 2 (USART_CR2) - configuration register 2
image.png
image.png (13.14 KiB)
Viewed 3540 times
STOP: number of STOP bits
  • 00: 1 stop bit
  • 01: 0.5 stop bits
  • 10: 2 stop bits
  • 11: 1.5 stop bits
0.5 and 1.5 stop bits are not available for UART4 and UART5 (UART4 and UART5 are not available in the STM32F103C8 microcontroller).

Conclusion

In order not to clutter the reader's head with unnecessary information, I did not give a description of each flag and each register USART, as for most tasks it is not necessary. Perhaps, in the future I will add descriptions of bits responsible for joint work with DMA.