STM32 USART sending and receiving data

Using USART for sending and receiving data

USART is the same in ‘Arduino world’ and Keil programming, but getting message out is bit different – instead using “Serial.print” we are using here custom made function “printMsg” which uses ‘vsprintf’ function for formatting whole message which is then transferred to the data register and shifted out by shift register.
For formatted print, there is cplusplus reference fro programmers.

Diagram from Reference manual RM0008:


No DMA yet, just manual TX/RX-ing

DMA on USART can help a lot, but for now I did not learn enough to give you an example how to use it. As I cover part by part of STM32 programming in Keil, I am trying to make it simple so that everyone can understand. DMA (Direct Memory Access) is one way to move data from one part of the MCU to another. But also, there is old ‘manual’ ways.

Using HTerm console


Instead Putty or Serial monitor from Arduino, I like rather to use HTerm, it is free and has everything one programmer need. You can debug your program and see output data in various formats: ASCII, decimal, hexadecimal and binary form. There are other things as is flow control, saving received data, sending saved or generated file out over the USART and many other nice things.

Here are example codes, you should to include all three files into your Keil project: main.c, pringMsg.c and printMsg.h – make it so that all three files are in the same folder. Don’t forget that we need FTDI adapter.

Example codes

main.c file:

printMsg.c file:

printMsg.h file:

In printMsg.c file is RCC->APB2ENR register with everything we need to provide clock to the USART and GPIO pins (A9 is TX, A10 is RX):

Note that this time GPIO port A9 uses ‘alternate’ function instead ‘general purpose’. If you set it incorrectly, it will not send data.

Next thing is setting USART speed in Bauds.  Here is example for 9600 Baud:

To get this number needed for Bit Rate Register BRR, You need to divide your clock with 9600, 72000000/9600=7500, but it is less confusing to use hexadecimal value at this place, so use your programmers calculator and convert 7500 into 0x1D4C. In printMsg.c file I calculated all mostly common using USART speeds, plus few not so common. The maximum speed HTerm can transmit and receive is 3000000 Bauds (~ 3 megabauds). Putty can’t cope with that, and did not tried Arduino serial monitor.

Inside printMsg() function, there is final sending part:

What id does, it send first byte from our array buff[] into register USART1->DR, then we should wait until it is transferred into shift register and send out. This means that we should make waiting while loop and ‘watch’ TXE flag to appear – sending of one byte is done, now we can continue loading next byte into USART1-DR data register.

Receiving part is little bit different. We first wait flag RXNE that told us that data register is filled with one byte and ready for read.

To recap: for sending byte out, we first send one byte, then wait flag XE, for receiving byte in, we first wait flag RXNE, then we can read.

On the console, there should be enabled one of three options – after typing message, when we press enter, all data are send, but we need extra byte or two to tell MCU that there is end of the message. Else, our loop may wait until whole buffer is full. So, enabling CR and/or LF (Carriage Return / Line Feed), with decimal values of 13 and 10 respectively. Inside for loop, there is:

Which checking whether received byte is either of those two options, CR and/or LF, then it exit or break loop. After that it just returns length of the message “return len;”. Since ‘buff[256]’ is global array, after returning back from readMsg() function, this buffer is filled with our data, and we need to know how much. Variable ‘len’ gives us exactly that number.

I made simple test ‘loopback’ code that sends everything back to the console:

Note that inside for() loop, there is ‘len+1’, that is because length of array is certain number, then we ad our CR and/or LF character that tells HTerm to go in new line.

Custom USART function

Sometimes we need just send data from our MCU inputs. For example potentiometer data. Then we have no need for formatted print or anything, just making some loop that read ADC for example, and send byte by byte out (and waiting TXE flag):

Where ‘pot_value’ is some data from ADC which measure voltage on your potentiometer.

If you want to externally change something by typing, then use this:


One thought on “STM32 USART sending and receiving data”

  1. Can you please tell me that, from where do you get the reference, syntax and basic examples of the CMSIS or low-level APIs?

    Most of the folks teach about HAL or STMcube(there are tons of them, I hate STMcube BTW!!), but only a few sites, like yours, teach true programming.

    Please mail me the references you use for your development

    thank you in advance!

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.