A USART is a universal synchronous asynchronous receiver transmitter. A serial port if you like. On the STM32 however, it really is universal. This peripheral has a raft of features for a huge range of serial protocols including all the usual asynchronous modes plus IrDA, LIN, Smartcard Emulation and the ability to function as an SPI port…
Typical STM32 parts have between 2 and 5 USART peripherals. The STM32F103RE is described as having 5 USART/UART devices. USART1 live on the high-speed APB2 bus while USART2, USART3, UART4 and UART5 are connected to the lower-speed APB1 bus. The UARTs differ from the USARTs in that they do not provide hardware flow control or synchronous operation or smartcard emulation. All other functions appear to be supported [RM0008 – sec 25.5].
It will come as no surprise that the USART, being a complex peripheral, has a lot of configuration options and registers. Here is the register map, taken from the Dec. 2009 reference manual:
Notice that, although the registers themselves are on 32-bit boundaries, they are no more than 16-bits wide. When you try and find where all these peripherals get connected to the outside world, it can be quite a challenge what with the sheer variety of peripherals and the finite number of pins available. Here, I shall concern myself with just USART1 on the STM32F103RE part. (code is at the foot of the page) Much the same techniques are used with any of the USARTs. This is a list of the main USART/UART pins on the STM32:
BGA100 | LQFP100 | LQFP48 | LQFP64 | main function | USART/UART |
D9 | 67 | 29 | 41 | PA8 | USART1_CK |
C10 | 70 | 32 | 44 | PA11 | USART1_CTS |
B10 | 71 | 33 | 45 | PA12 | USART1_RTS |
C9 | 68 | 30 | 42 | PA9 | USART1_TX |
D10 | 69 | 31 | 43 | PA10 | USART1_RX |
G3 | 29 | 14 | 20 | PA4 | USART2_CK |
G2 | 23 | 10 | 14 | PA0 | USART2_CTS |
H2 | 24 | 11 | 15 | PA1 | USART2_RTS |
J2 | 25 | 12 | 16 | PA2 | USART2_TX |
K2 | 26 | 13 | 17 | PA3 | USART2_RX |
K8 | 51 | 25 | 33 | PB12 | USART3_CK |
J8 | 52 | 26 | 34 | PB13 | USART3_CTS |
H8 | 53 | 27 | 35 | PB14 | USART3_RTS |
J7 | 47 | 21 | 29 | PB10 | USART3_TX |
K7 | 48 | 22 | 30 | PB11 | USART3_RX |
B8 | 79 | – | 52 | PC11 | UART4_RX |
B9 | 78 | – | 51 | PC10 | UART4_TX |
B7 | 83 | 54 | PD2 | UART5_RX | |
C8 | 80 | – | 53 | PC12 | UART5_TX |
For my purposes, I want to set up USART1 at 9600,N,8,1 with no hardware flow control. For that I only want to configure pins PA9 and PA10 as TX and RX respectively. Pins PA8, PA11 and PA12 will be left as GPIO pins.
Bus Setup
As with all the peripherals on the STM32, the first thing to do is make sure that the peripheral is getting a suitable clock signal and that the pins are properly setup. USART1 is connected to the APB2 peripheral bus and uses pins on GPIOA. Thus, we need to enable the clock for GPIOA. Since this example will only use the TX and RX pins (PA9 and PA10 respectively) we need only configure them. The TX pin, PA9 should be set up as a push-pull output using the alternate function at low frequencly (0b1010). RX is a floating input (0b0100) which is its default state although you may wish to enable the pullup/down feature if it suits your application. Lastly, the APB2 peripheral clock will need to be enabled for the USART.
BAUD rate:
A common issue with micro controllers is that the baud rate generator is a simple division of the main processor clock. That leads to ‘strange’ system clock frequencies like 4.9152MHz just to get easy divisors for the baud rate generator. The STM32 has a fractional generator that means that pretty well any baud rate can be derived from the system clock whatever its value. Each USART has a register, USART_BRR, that holds the divisor, stored as a 12.4 unsigned fixed point number. The reference manual is a bit awkward on the matter of what value to store in here but the simple answer is to calculate it from
USART_BRR = Fck/BAUDRATE
This will get you close enough although you should probably use a rounding factor and do it properly. I have no trouble with baudrates up to 115,200
So, with a clock rate, SystemFrequency, of 64,000,000 Hz and a baud rate of 115200, I need
USART_BRR = 64000000/115200 = 555.5555 = 555 truncated
(note that only USART1 can be clocked with the full system clock, the others get Fck/2)
This example generates almost a worst-case error, being wrong by half the least significant bit. The actual baud rate generated will be 115,315.3. Since the next nearest value for USART_BRR would be 556, giving a baud rate of 115107.9, this will certainly be close enough.
Register setup
Spend enough time with the reference manual and you will see that the processor puts the USART registers into a very handy state after a reset. The default settings give you no hardware flow control, 8 data bits, no parity and one stop bit – exactly what you need when talking to a common-or-garden terminal program. At present, I have no intention of using the serial ports for anything else so, I am afraid, I shall not bother to delve into the deeper mysteries of the USART configuration registers. Before the USART can be used, however, the USARTx_CR1_UE bit must bet set to enable the peripheral.
Transmit and Receive
Each USART has a single data register (USARTx_DR). This is a 9-bit register to cater for longer characters. Here only 8 bits are used. Writing to this register will put data into the outgoing shift register and reading from here will fetch the most recently received data.
Before data can be sent, the transmitter must first be enabled by setting the USARTx_CR1_TE bit in USARTx_CR1. According to the reference manual, immediately after setting this bit, an idle frame will be sent automatically. I could not observe this when repeatedly clearing and setting the TE bit. Before sending a character to the data register, you should test the USARTx_SR_TXE bit. This bit indicates that data register holds data not yet sent to the TDR shift register. There is no need to directly set or clear the TXE flag, it is cleared when data is written to USARTx_DR and set when that data is transferred to the TDR. An interrupt can be connected to this bit if you want to be sending data under interrupt control.
If you write to USARTx_DR when the shift register is empty, the data will go straight into the shift register, transmission will begin immediately and the TXE flag will will be immediately set.
After sending the last character in a string, it will be a good idea to test the USARTx_SR_TC bit. This bit will be cleared after transmission of the last frame and thus indicates that it is safe to shut down the USART without data loss.
Getting hold of the received data is a simple matter of reading the same data register (USARTx_DR) that is used to send. The flag, USARTx_CR1_RE, must be set to enable the receiver. When a character is received, the USARTx_SR_RXNE bit will be set indicating that data is waiting in the data register (USARTx_DR). An interrupt can be generated if suitably enabled. Reading the data register will clear the RXNE flag automatically. When reading a character, it is a good idea to read the error flags from USARTx_SR. For basic asynchronous operation, the key flags are located in the least significant 4 bits. They are:
- USARTx_SR_ORE: Overrun Error
- USARTx_SR_NE: Noise Error
- USARTx_SR_FE: Framing Error
- USARTx_SR_PE: Parity Error
Code Examples
Right, let’s see some simple code:
void usartSetup (void) { // make sure the relevant pins are appropriately set up. RCC_APB2ENR |= RCC_APB2ENR_IOPAEN; // enable clock for GPIOA GPIOA_CRH |= (0x0BUL < < 4); // Tx (PA9) alt. out push-pull GPIOA_CRH |= (0x04UL << 8); // Rx (PA10) in floating RCC_APB2ENR |= RCC_APB2ENR_USART1EN; // enable clock for USART1 USART1_BRR = 64000000L/115200L; // set baudrate USART1_CR1 |= (USART1_CR1_RE | USART1_CR1_TE); // RX, TX enable USART1_CR1 |= USART1_CR1_UE; // USART enable } int SendChar (int ch) { while (!(USART1_SR & USART1_SR_TXE)); USART1_DR = (ch & 0xFF); return (ch); } int GetChar (void) { while (!(USART1_SR & USART1_SR_RXNE)); return ((int)(USART1_DR & 0xFF)); }
Yes, it really is that simple in the end. Of course, none of the clever tricks that the USART specialises in have been used. Maybe some other time.
Hello Peteh,
I am running my et-stamp with the PLLMUL *16, 2 wait states. USART1,USART3 and generally all peripheral functions I tried so far run just fine. I know that is out of the specs but I need as much speed as I can get since I am controlling a big LCD screen(not relevant to uMouse).
I am using KEIL uVISION4 and the PULLMUL option was there in a dropdown box that allowed me to chose up to 16.
Is there anything bad that might happen by having it on those speeds?
Thanks!!
-Marios
Generally, I believe you will have no trouble as long as the resulting clock frequency is withing the limits described in the data sheet. Pretty clearly, you are going to have trouble if you tried to use a 16MHz exernal clock and a multiplier of 16. The datasheet states that the PLL output frequency must not exceed 72MHz.
If it could reliably do better than that, it would say so in the datasheet. I am sure that ST would love to be able to quote a higher operating frequency.
While your particular device may function because it is at the outer edge of some tolerance band, others probably will not. Thus, your only safe option is to stay withing the limits on the datasheet.
Hi,
how can i used 2 uart?
thank you..
It should not be a problem. the easiest way would be to have two sets of all the important functions. Perhaps if you come up with a good method, you could post it here
I have an application with a STM32F103 where it is sometimes putted in lowpower mode, when i wake up the STM32 with datas on USART1, i get an overrun error (when debugging).
I’ve set the clock properly before to read the data,
I can read datas but they are half wrong,
Have you some ideas ?
Thanks.
Is it the data on the UART that is bringing the processor out of sleep?
Pingback: STM32: работа с UART | MyLinks
Pingback: Why is the USART receiver pin configured as “input floating”? | Q&A System
Pingback: An STM32F4 Project Template for Rowley Crossworks
I am new user of STM32F103, I am facing a problem while sending and receiving data through USART1 , I have seen the out put on logic analyzer, there I found frame error. Please help me to resolve the issue. here is my code :-
What a super-easy way of calculating the “baud rates” ….Thankyou so much