It’s been a while since I posted the tutorial on using STM32F0’s timer and counter. I’ve recently started my MSc course in NUS and found it quite challenging. I almost forgot all the maths, formula, calculation that I studied in university after 2 years working. I’ve been spending most of my time reviewing old lessons, absorbing new lectures. But today I’ll set them aside and enjoy my time here with the STM32F0 UART tutorial.

Ok, so if you have already worked with arduino before, you must be very familiar with “Serial.print” command. For those who don’t know what it is, it’s simply a way of communication between two or more devices using serial interface, which means data will be transmitted and received one by one bit sequentially using typically lest than 4 wires. Wikipedia has a very detailed knowledge on this if you want to understand more. In this tutorial, we will use this serial interface to transfer data, make a communication bridge between our device (STM32F0) to a computer or other devices such as arduino, pic,…

1. Hardware connection

Before going to details, there are two terms we need to clarify: RS232 and UART. What are the differences between two? Take a look at the following picture:

RS232 vs UART

RS232 vs UART source: http://www.crifan.com

We can clearly see the difference in voltage between two, one is +-12V, one is 0-5V (or 0-3.3V). What your PC has (hopefully it still has nowadays) is RS232 port (COM port shown in Manager), which is the 9-pin connector usually above those USB ports. To use this port to connect your STM32F0 to the computer, we need something to translate +-12V into 3.3V and MAX232 was born to do that job. So, if you intend to use the RS232 port on your PC as a way to connect to STM32F0 or any kind of microcontroller, remember to use MAX232 or you will burn your devices.

rs232

MAX232 - Source:robomart.com

MAX232 – Source:robomart.com

However, this RS232 port is no longer existing on those new laptops, tablets,… but only USB port. So, to make it easier, we try to use the next method which uses USB port as a virtual RS232. All you need to do is to get one USB-UART converter to continue with this tutorial. This USB-UART converter can be found easily from one of those sources: Ebay or Sparkfun. This board will create a virtual serial port on your computer (COM port).

FT232 USB-UART

No matter what version of FT232 USB to serial board or any kinds of USB to UART board you have, PL2303, CP2012 or CH340, there will be those similar pins:

  1. GND : Ground
  2. VCC (5V or 3.3V) : Power supply
  3. TX (TXD) : Transmit (from computer to device)
  4. RX (RXD) : Receive (from device to computer)

Since STM32F051 on the Discovery kit has 2 UART modules (UART1 and UART2), we can try using both in this tutorial. They are identical to each other in the sense of function, command, … and can be mapped to different pins easily. The picture below shows how to connect the STM32F0 kit to the FT232 Board. For the first time, we will use UART1 mapped with pin PA9 and PA10. In order to send or receive data through Serial port on computer, I would recommend Hercules Terminal that you can download here: http://www.hw-group.com/products/hercules/index_en.html

STM32F0 Uart connection

STM32F0 Uart connection

2. Set up in CubeMX

After having everything connected, we can start playing with the configuration part in CubeMX. The following video shows you how to initialize the typical configuration for UART interface, transmit and receive data.

There are few things we need to pay attention to when setting up the UART function:

  • Baud rate: this parameter decides how fast the communication is. The standard baud rates are: 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200, 250000, , 230400, 460800, 921600, 1.5Mbps, 3Mbps… The bigger the number is, the faster your communication is. FT232 supports up to 3Mbps and that is really fast. Normally, we just use up to 115200bps for all applications.
  • Word length: usually 8bit will do the job, unless you want to do multi-slaves communication then we can use 9bit length. However, multi-slave communication can also be done with 8bit.

3. Send data to computer

There are two common ways to send data to computer or other devices: one, we can take advantage of the “printf” function that is available in Keil and two, using the built-in HAL library. Before using HAL library with cubeMX, I personally preferred the first choice. Now I just change to use the second method, combine between HAL library and “sprintf” function. You should check both functions in cplusplus.com to know which parameter is used to transmit which type of variable. For example, “%i” is for integer; “%.2f” is for floating number with 2 digits after decimal point; “%s” for string; “\r” equal to acsii 13; “\n” equal to acsii 10…

This example was extracted from cplusplus.com for your reference on how to use ‘printf’ and ‘sprintf’

Output will be

Back to the transmission part in the video clip, for the first method, the configuration code is quite complicated, but the transmission part is very simple:

Wherever you want to send data to computer, just use the following command

For the second method, there is no configuration part, but the sending part needs to be:

4. Receive data using Interrupt

In the video, I have shown you one possible way to use UART interrupt to receive data from computer in a string finalized by a CR (acsii 13 or Enter). There are also many ways to receive UART data using timer or other method. Here, for this method, the basic mechanism is storing each received byte into an array until receiving a CR. After that, a variable called “Transfer_cplt” is trigger to announce that receiving is completed. Therefore, after reading out the data, you should reset this “Transfer_cplt” for a new session.

The UART interrupt routine in the clip is as follow:

Rx_Buffer is the array that stores received data.

I hope you like it. More tutorials on ADC, SPI, I2C… will be available after I finish all my exams this May (sorry for all the procrastination!)

67 Thoughts on “STM32F0 UART – Tutorial 5

  1. Iran Espinoza on 27/09/2015 at 2:30 AM said:

    Jejeje, i like the last part: “I couldn’t open my eyes to write anything else”, we are waiting for when you have time. I am currently stuck in writing a data in flash memory, turn off the device, turn it on and read the data (such as EEPROM of the pics), without success, with HAL libraries. Greetings!

    • Le Tan Phuc on 27/09/2015 at 11:53 AM said:

      Last time I tried that FLASH HAL as well, it’s quite confusing but it’s not difficult. You’re moving really fast 😀

      • Iran Espinoza on 28/09/2015 at 1:16 AM said:

        Hi Le Tan Phuc, for me is an honor your comment, hehe. you think you could give me some help? so far, I’ve drawn in VGA 800×600 @ 85 Hz, and after that step, intercepts a signal, and makes OSD interimposer using timers interlaced, SPI port as a draftsman pin, and interruptions to full HD (1080p). I must tell you, at first, did not know where to start, but your tutorials have helped me, as you can not imagine. Thank you! returning to the subject of flash, I used functions:
        // THIS IS GOING TO START
        FLASH_EraseInitTypeDef erase_pages;
        erase_pages.PageAddress = 0x0800FC00;
        erase_pages.NbPages = 1;
        erase_pages.TypeErase = TYPEERASE_PAGES;
        uint32_t * Error;
        // To write this done BEFORE
        HAL_FLASH_Unlock ();
        HAL_FLASHEx_Erase (& erase_pages, error);
        /*
        HERE, i used also:

        SET_BIT(FLASH->CR, FLASH_CR_PER);
        WRITE_REG(FLASH->AR, 0x0800FC00);
        SET_BIT(FLASH->CR, FLASH_CR_STRT);

        Without luck…

        */
        HAL_FLASH_Lock ();
        / * Do things * /
        // WRITE ONLY AFTER AN ERASE PAGE
        HAL_FLASH_Unlock ();
          HAL_FLASH_Program (TYPEPROGRAM_HALFWORD, 0x0800FC00, 0x1234);
        HAL_FLASH_Lock ();

        // READ
        Data_config = * ((uint16_t *) 0x0800FC00); // Read flash memory address at 0x0800FC00

        And as you read Data_config, is not 0x1234 … I’m frustrated, hehe …

  2. Iran Espinoza on 29/09/2015 at 3:57 AM said:

    Le Tan Phuc, as I did, thank you very much for everything!

  3. sowa on 29/09/2015 at 5:11 AM said:

    Le Tan Phuc, could you help me with SPI in HAL library? I can’t get it working. Could you check my project?

    • Iran Espinoza on 30/09/2015 at 4:23 AM said:

      Hi sowa, put it here, to take a look.

      • Iran Espinoza on 02/10/2015 at 2:47 AM said:

        sowa????

        • sowa on 04/10/2015 at 6:13 PM said:

          Hi, sorry for delay, I was out of space due my job 🙁 Here is my project:
          http://217.144.209.166:18080/MyWeb/http/SPI_TIMER.rar
          Basically, function TM_ILI9341_Init() should fill the ili9341 based LCD with red color, but nothing happens. I guess problem may be here:
          (…)
          TM_ILI9341_SendData(0x39); //example how data is send
          (…)

          void TM_ILI9341_SendData(uint8_t data) {
          ILI9341_WRX_SET;
          ILI9341_CS_RESET;
          HAL_SPI_Transmit(&hspi2, data, sizeof(data), 5000);

          //TM_SPI_Send(ILI9341_SPI, data);

          ILI9341_CS_SET;
          }

          I guess something is messed up with sizeof(data), but I’m not sure.

          Thank you

        • Le Tan Phuc on 12/10/2015 at 12:47 AM said:

          sowa, I think your problem is in the void TM_ILI9341_SendCommand(uint8_t data) and void TM_ILI9341_SendData(uint8_t data). Instead of using HAL_SPI_Transmit(&hspi2, data, sizeof(data), 5000); you can try this old method: create a function like this
          uint8_t SPI_Send(SPI_TypeDef* SPIx, uint8_t data) {

          /* Fill output buffer with data */
          *(__IO uint8_t *)&SPIx->DR = data; //
          /* Wait for transmission to complete */
          while ((SPIx->SR & SPI_FLAG_TXE) == 0);
          /* Wait for received data to complete */
          while ((SPIx->SR & SPI_FLAG_RXNE) == 0);
          /* Wait for SPI to be ready */
          //while ((SPIx->SR & SPI_FLAG_BSY) == 1);
          /* Return data from buffer */
          return SPIx->DR;
          }

  4. Noam on 03/10/2015 at 11:56 PM said:

    Le Tan Phuc,
    I like you blog. it’s great and I learnt from it. I am waiting for the next part….

  5. Sukru on 08/10/2015 at 5:57 PM said:

    C’mon maaan where is the new video ? :))

  6. Noam on 14/10/2015 at 2:21 PM said:

    when will you continue this post?
    I don’t think that you sleep for 17 days 😛

  7. Sukru on 18/10/2015 at 5:35 PM said:

    Hey le tan phuc i got questions for you, i’ve tried to communicate stm32f0 and lm35 tempureture sensor but i cant do it so far.Can give some tricks.

    • Sukru on 20/10/2015 at 4:21 PM said:

      There are some codes you copied from notepad.Where did they come from ? They seem so complicated

    • Le Tan Phuc on 22/10/2015 at 9:08 AM said:

      Hi, for ADC reading, my suggestion is using with interrupt or DMA for easy data reading. Next tutorial will be about ADC but I think I can only make it after November 🙂 The code in the notepad I have put in the post as well, it’s just some configuration to let Keil know we are redirecting ‘printf’ function to the uart transmit function we want.

  8. sowa on 21/10/2015 at 4:18 AM said:

    you are the man 🙂

  9. saeed on 23/10/2015 at 9:50 PM said:

    hi, your tutorials are the best…,
    we are waiting for next one.
    thanks man.

  10. mostafa on 14/11/2015 at 9:51 PM said:

    Hello, Le Tan Phuc . I need to make two STM32f4 to communicate via SPI… can i use that code .. you written it above in comments:

    /* Fill output buffer with data */
    *(__IO uint8_t *)&SPIx->DR = data; //
    /* Wait for transmission to complete */
    while ((SPIx->SR & SPI_FLAG_TXE) == 0);
    /* Wait for received data to complete */
    while ((SPIx->SR & SPI_FLAG_RXNE) == 0);
    /* Wait for SPI to be ready */
    //while ((SPIx->SR & SPI_FLAG_BSY) == 1);
    /* Return data from buffer */
    return SPIx->DR;
    }

    i want to send from Master and the slave receive only ( i don’t want from the slave to send again to master ) … in this case i will use two wires only , isn’t that? (MOSI and SCK)

    • Le Tan Phuc on 21/11/2015 at 12:09 AM said:

      Hi, you can try that way, it should work. I recommend you getting a cheap logic analyzer from Ebay so that you can visually monitor your SPI signal and debug it easily.

  11. Chào a Phúc,
    Những hướng dẫn của anh về lý thuyết lẫn code rất dễ hiểu. Em có 1 vấn đề khi sử dụng CubeMX tạo ra giao tiếp, em có làm về ngoại vi (OLED SSD1306) em có tham khảo chương trình và viết theo thư viện hàm HAL ở 1 file user.c khác. Khi em build thì bị lỗi do biến ở 2 chương trình giống nhau. Vì ở main.c khởi tạo biến I2C_HandleTypeDef hi2c1; ở file user.c em cũng phải sử dụng biến này để sử dụng với hàm HAL. Em chưa có cách giải quyết, a có cách gì về vấn đề này ko ạ?

    • Le Tan Phuc on 18/03/2016 at 10:03 PM said:

      hi bạn, bạn có thể link qua file main.c bằng cấu trúc extern hoặc đơn giản hơn, bạn khai báo hi2c1 ở main.h, sau đó main.c và user.c đều import main.h

  12. YOBE on 17/03/2016 at 11:35 PM said:

    Hi,
    your video’s are very interesting.
    But 1 question I have concerning Keil and Uart: why can you not use the “Uart viewer” in the debugger from Keil to visualize the send data?
    Is it only possible to use the serial to USB adapter?
    What is than the use of having the Uart-viewer in Keils debug environment?

    Thanks a lot!!!

    • Le Tan Phuc on 18/03/2016 at 10:07 PM said:

      Hi, I used external usb-uart adapter and external program to demonstrate in the tutorial because I would like to show a more generic case when you are doing with the chip itself directly, not the STM32F0 kit which already has the internal connection. Therefore, when you design your own circuit including STM32, you will know clearly which pins are used for uart and how to connect them out.
      Hope you enjoy it! cheers 🙂

  13. Anh cho e hoi: Nếu em muốn gửi ký tự từ STM32f4 sang 1 vi điều khiển khác qua UART thì cách gửi như thế nào ạ

  14. hichem on 15/04/2016 at 9:14 PM said:

    thank you for this tuto. you are really a hump 🙂

  15. Thank you so much.

  16. thank u so much how we can use PUTCHAR_PROTOTYPE for cmsis spl.
    that means how i have to change “HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 100);”??

  17. Mark on 02/05/2016 at 4:09 PM said:

    Thanks for your tutorials, Can you make a manual how to start a project with CubeMX on a discovery or other demo board using the build in gyro or touch sensor. I am trying but when selecting one of the devices of the demo board in CubeMX it only sets the devices and names. No links to the drivers, no functions availabe

  18. D. W. on 13/05/2016 at 7:24 AM said:

    Thank you for your very helpful tutorial

  19. Mac on 15/05/2016 at 1:36 AM said:

    Hi, I’ve got my own header file ,with funcktions to SSD1306. Do you know ,how to include this file into “source insight” ,and use it in my project?

  20. Gibson486 on 27/06/2016 at 9:00 PM said:

    Does not seem to work with the F4 for receiving. I think something is missing…maybe enabling the actual interrupt?

  21. hello, the most important thing is that you are good, but i have the same problem with Gibson486, and i promise i have enable the UART interrupt in NVIC Setting tab!!my problem is that the serial port only can printf one word, after you press it can sent one word again, two words are the same. what is the wrong with it???

    • Le Tan Phuc on 14/07/2016 at 9:47 AM said:

      Hi Aires, which UART did you use to test? it seems that you used the ‘printf’ method, not the ‘HAL_UART_Transmit’ right? The interrupt I mentioned in reply to Gibson486 was about receiving data from computer. For sending data to computer, interrupt was not discussed in the post. Would you try using ‘HAL_UART_Transmit’ which was demonstrated in the video from 7:35. If there is still problems with this method then let me know.

      • Thank you for your reply!!! I need to send data from computer to computer by Serial debugging assistant, reference to your video write my program, still have the problem. The difference is that i used the STM32L051C8T6. After ask some else, he tell me that my data the problem is the HAL library files, now i can receive data normally. p.s now i have another problem, i can’t receive correct data by spi and mda. Le Tan Phuc, Do you have this aspect of the routine? wait for your answer~

  22. Maarten van Dootingh on 24/07/2016 at 2:12 PM said:

    I have seen this is more or less the standard way to receive a stream of data from a uart using the HAL. It is unfortunately broken: especially on slow mcu’s (low clock speed = low power) you will miss received bytes due to the need to restart the receive after byte. Worse: you will not even see an overrun error because of receiving 1 byte at a time!

    • Le Tan Phuc on 25/07/2016 at 8:59 AM said:

      hi, thank you for pointing out the possible drawbacks of this method. I used to code with standard library and it doesn’t require to restart the uart every time such as what HAL library does. I would suggest using DMA to speed up the process.

      • Mohammad on 26/07/2016 at 8:36 AM said:

        Hi 🙋, can tell us the principle of implementation of dma uart receiving ?
        Never i tried to do that but I just could change your code by substituting uart.receive.it by something like uart.receive.dma , I think this is wrong way and standard method is different .(may be that is multi buffering communication?!)

  23. Rodriguez on 26/08/2016 at 11:32 PM said:

    Hi Le Tan Phuc,

    thank you for this work. I have a problem and i think you can help me. I have two warnings, (implicite declaration for strlen) and (type char* is imcompatible…). I’m work on SW4STM32(AC6), and i dont know how i can override like you in your video at 9″30
    What’s this button you click?

    Thank you!

    • Le Tan Phuc on 27/08/2016 at 11:38 PM said:

      Hi, you can just ignore the warnings, as long as you can compile the code, it should be fine. You just need to compile (shortcut is F7) and load the program into the microcontroller (shortcut is F8).

  24. Tmx on 27/10/2016 at 11:52 PM said:

    if (Rx_data[0]!=13)
    {
    Rx_Buffer[Rx_indx++]=Rx_data[0]; //add data to Rx_Buffer
    }

    Using this you will overflow, if received data is 100+ bytes before CR…

    Better use
    if (Rx_data[0] != 13 && Rx_indx < 100)

  25. Sergio on 03/11/2016 at 5:47 AM said:

    Wonderful job. I have a question if in the same program i want send message on UART or LCD or SPI what can i do ?
    Thanks Sergio

    • Le Tan Phuc on 07/11/2016 at 12:32 AM said:

      Could you be more specific?

      • Sergio on 09/11/2016 at 4:47 AM said:

        Hi, my question is how i can use printf for send data in the same program to one uart or lcd, how i can choose the peripheral
        Thank you

        • Le Tan Phuc on 16/11/2016 at 4:43 PM said:

          For this kind of situation, I think you’d better use the HAL_UART_Transmit function directly rather than printf. It will be more flexible

  26. Olivia Christy on 05/11/2016 at 12:21 PM said:

    Nice work…But where is your IRQ handler. is it just calling HALIRQHandler() ? I am working with STM32F0Nucleo now . Do you think I can follow this tutorial for my board using HAL library in IAR.

    • Le Tan Phuc on 07/11/2016 at 12:26 AM said:

      Hi, in HAL library, all the Interrupt routines are handled for you so no need to use IRQ handler and manually clear all the interrupt flags any more. You absolutely can follow this tutorial for your Nucleo board.

  27. Olivia Christy on 07/11/2016 at 3:33 PM said:

    Thank you Le. I made it…Thank you so much

  28. Olivia Christy on 07/11/2016 at 6:42 PM said:

    Hi I have a problem.I am making a GSM UART interface on STM32 nucleo board. I am successfully transmitting and receiving data but I want to know how much data received and when the receive ends. How to know that.
    The amount of data received varies each time and i cannot use a ring buffer also
    Any Suggestions regarding this?

    • Le Tan Phuc on 16/11/2016 at 4:50 PM said:

      Hi Olivia, in the post I have shown 1 method, which uses the CR character to determine when the transmission is finished. Another method is using one timer to determine the timeout duration of the transmission. For example, you have 1 timer interrupt every 50ms. Each time you receive the data from UART, you just reset the timer, which means that only after the transmission is done, timer interrupt will occur and tell you that transfer is completed.

  29. JonasB on 15/11/2016 at 10:56 PM said:

    Hi, how can i use the Transfer_cplt flag in my ‘main’ function to process the received data and to clear the flag? Thanks in advance. Gr Jonas

    • JonasB on 15/11/2016 at 11:15 PM said:

      Nevermind, already solved it, had to make my flag volatile so i could change it in the callback and in the main method as well.

  30. Abi on 05/12/2016 at 8:19 PM said:

    Could you make tutorials on Stmf0 std library functions? As in without using stm32cubeMX for generating code.

    • Le Tan Phuc on 20/12/2016 at 5:01 PM said:

      hi, it’s better and faster to generate the code from CubeMX. I used to use std library and it required a lot of effort to initialize the code at the beginning.

  31. Eren ERASLAN on 30/12/2016 at 8:59 PM said:

    First of all thank you for tutorials le tan phuc. They are really helpfull appreciate that.
    But I have a few questions. I’d be gratefull if you answer them.

    I am having trouble to understand this Hal functions. Some guy from youtube showed to getting data from Interrupt was completely different then yours. He was putting receiving code which is “HAL_UART_Receive_IT(&huart3,(uint8_t*)Rx_data,lenght); ” into the USART3_IRQHandler. I tried that method but I faced the problem that I couln’t get the whole data to buffer. I dont know why exactly maybe It was trying to get whole buffer at one code in USART3_IRQHandler. Some people just put the HAL_UART_Receive_IT function in to the while loop. This in nonsense. Why can I find proper documents for this kind of tricks. OK HAL library configures all init codes but there is a lack of explaned documents for the using peripharels. Where did you learn all this stuff for this lesson ?

    • Le Tan Phuc on 04/01/2017 at 11:30 PM said:

      Hi, thank you for your interesting question. If you notice, in my example code, I also used “HAL_UART_Receive_IT(&huart1, Rx_data, 1)” function to receive the data. However, I only put the data length as ‘1’ so that the receiving function will complete after receiving 1 byte. Hence, we can vary the length of the data we want to receive with the only condition to stop receiving is the character ‘CR’ (or ‘enter’ or acsii 13).
      In case you already fix the number of byte you want to receive each time, you can just use HAL_UART_Receive_IT(&huart1,(uint8_t*)Rx_data,lenght) with ‘length’ is the fixed number of byte to receive. This method, however is not commonly used as you usually don’t know how much data you’re gonna receive.
      If you want to receive data in a loop, then just use ‘HAL_UART_Receive’, it will work as long as nothing else in the loop causes delay to the function.
      And finally, I just learnt it by trial and error. I also look into the function to see how it works and then, check the reference manual for information about important register used in the function. Hope it help.

  32. guillermo on 20/01/2017 at 12:12 AM said:

    Hi Le Tan Phuc, because the structure of my project, all UART functions are in one “uart.c” and is here where I have to put my function prototype. But then print f is not working. Do you know how what to do to export the prototype function from “uart.c, uart.h) so I can use printf anywhere.

    /* Includes ——————————————————————*/
    #include “usart.h”
    #include “gpio.h”

    /* Private function prototypes ———————————————–*/
    #ifdef __GNUC__
    /* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf
    set to ‘Yes’) calls __io_putchar() */
    #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
    #else
    #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
    #endif /* __GNUC__ */

    /**
    * @brief Retargets the C library printf function to the USART.
    * @param None
    * @retval None
    */
    PUTCHAR_PROTOTYPE
    {
    /* Place your implementation of fputc here */
    /* e.g. write a character to the USART */
    HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 100);
    return ch;
    }
    /* USER CODE END PFP */

    UART_HandleTypeDef huart1;

    /* USART1 init function */

    void MX_USART1_UART_Init(void)
    {

    ..
    ..

    thanks for your help!!

Leave a Reply

Post Navigation