How to use STM32 Nucleo serial port

As we have seen in the previous tutorial about this new developing board from ST, the STM32 Nucleo provides an integrated ST Link v2.1 interface. ST Link is mainly designed to allow flashing of target MCU trough the mini-USB interface. But, it provides at least another really useful feature: a Virtual COM port. When you install the ST-Link drivers, a new device appears in your hardware devices list: the ST-Link Virtual COM port.

If you use a Linux PC or a Mac, you'll find a new terminal in the /dev directory. Usually, this device is named something similar to tty.usbmodemXXXX, as shown below.

The serial port is mostly useful for two reasons: if you want to debug your firmware printing messages (not strictly necessary with the ARM architecture, since we can also use ARM semihosting) or if you want to exchange commands and messages between your Nucleo board and your PC (perhaps, using a dedicated application you are building).

In this post I'll show you how to properly configure and use the integrated virtual COM port of STM32 Nucleo board. But, before we start coding, it could be really useful take a look to the hardware. ST provides the full hardware project of the STM32 Nucleo (the board is designed using the Altium Designer CAD, a professional CAD used in the electronics industry, but you are not required to have a so expensive piece of software to use your Nucleo). I'll assume the Nucleo-F401RE model, but it should be really easy to rearrange instructions to properly use your specific Nucleo.

First: pinout

A complex yet flexible MCU like the STM32 provides I/Os that have "overloaded" functionalities.This means that, before we can use a peripheral (in our case, the USART), we need to configure the peripherals associated to corresponding pins. Looking to STM32CubeMX tool, we discover that the STM32F401RETx processor has 3 different USARTs: USART1, USART2 and USART6.

[lightbox full="http://www.carminenoviello.com/wp-content/uploads/2015/01/2015-01-24-08_52_46-STM32CubeMX-uart2.ioc_-STM32F401RETx.png"]

[/lightbox]

Now we have to take a look to the Nucleo schematics. As we can see in the following picture, the USART_TX and USART_RX ports are connected to PA2 and PA3 pins. This means that the Nucleo board is configured to use the USART2 peripheral of target MCU.

[lightbox full="http://www.carminenoviello.com/wp-content/uploads/2015/01/stm32-nucleo-usart-pinout.jpg"][/lightbox]

Ok. We've grabbed all the necessary information related to the hardware needed to start coding.

Second: the code

Before we start configuring the USART2 peripheral, we need a test project. We'll generate an empty project using the GCC ARM Eclipse plug-in, as shown in my series about the GCC toolchain for the STM32 platform. When you generate the test project, you can using the following configuration parameters.

If you have followed my previous tutorial about GNU Eclipse plug-in, you already know that the plug-ins generates an incorrect clock configuration for the Nucleo-F4 board. I've shown how to use the STM32CubeMX tool to generate the right clock initialization code. For the sake of simplicity, this is the code you have to put inside the _initialize_hardware.c file.

void
configure_system_clock(void)
{
	RCC_OscInitTypeDef RCC_OscInitStruct;
	RCC_ClkInitTypeDef RCC_ClkInitStruct;

	__PWR_CLK_ENABLE();

	__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE2);

	RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
	RCC_OscInitStruct.HSIState = RCC_HSI_ON;
	RCC_OscInitStruct.HSICalibrationValue = 6;
	RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
	RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
	RCC_OscInitStruct.PLL.PLLM = 16;
	RCC_OscInitStruct.PLL.PLLN = 336;
	RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV4;
	RCC_OscInitStruct.PLL.PLLQ = 7;
	HAL_RCC_OscConfig(&RCC_OscInitStruct);

	RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_PCLK1;
	RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
	RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
	RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
	RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
	HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2);
}

Next, we have to add a function to configure the USART interface. We call it MX_USART2_UART_Init, as shown below.

UART_HandleTypeDef huart2;
...
void MX_USART2_UART_Init(void)
{
	huart2.Instance = USART2;
	huart2.Init.BaudRate = 115200;
	huart2.Init.WordLength = UART_WORDLENGTH_8B;
	huart2.Init.StopBits = UART_STOPBITS_1;
	huart2.Init.Parity = UART_PARITY_NONE;
	huart2.Init.Mode = UART_MODE_TX_RX;
	huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
	HAL_UART_Init(&huart2);
}

The function is really self-explaining. huart2 is an instance of UART_HandleTypeDef descriptor. It's a struct used to configure the UART peripheral. However, this code is still not sufficient to use the UART. We need to configure the hardware part, setting the right pins and initializing the right clocks associated to UART peripheral. This work is done with the following hook function:

...
void HAL_UART_MspInit(UART_HandleTypeDef* huart)
{
  GPIO_InitTypeDef GPIO_InitStruct;
  if(huart->Instance==USART2)
  {
    __GPIOA_CLK_ENABLE();
    __USART2_CLK_ENABLE();

    /**USART2 GPIO Configuration
    PA2     ------> USART2_TX
    PA3     ------> USART2_RX
    */
    GPIO_InitStruct.Pin = GPIO_PIN_2|GPIO_PIN_3;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
    GPIO_InitStruct.Alternate = GPIO_AF7_USART2;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
  }
}
...

Even in this case, the code is really self explaining. First, we need to initialize peripheral clock for PORTA GPIOs. Next, we need to enable the clock associated to UART2 peripheral. Finally, we have to proper configure PIN2 e PIN3 as UART2 TX and UART2 RX.

An important aspect to remark is that we don't need to explicit call this function in the initialization section. This is an hook function automatically called by the HAL_UART_Init() function which we call inside the function MX_USART2_UART_Init().  The right place to call this initialization function is inside the __initialize_hardware() function in the  _initialize_hardware.c file.

Ok. Now we only need to write a simple main() function to test the UART.

int main(int argc, char* argv[])
{
  char *msg = "Hello Nucleo Fun!\n\r";

  HAL_UART_Transmit(&huart2, (uint8_t*)msg, strlen(msg), 0xFFFF);
  while(1);
}

The main() is really simple: it simply prints a message on the UART and hangs for ever.

Before we can compile the whole project, we need to do another final operation. By default, the GNU-ARM plugin for Eclipse disables unused STM32 HAL files, in order to speed up compile operation. So, we need to enable the compilation of stm32f4xx_hal_uart.c file.
Go in Project Explorer->system->src->stm32f4-hal and click with mouse right button on the stm32f4xx_hal_uart.c file, as shown in the following picture:

[lightbox full="http://www.carminenoviello.com/wp-content/uploads/2015/02/Schermata-02-2457080-alle-13.25.27.png" title=""]

[/lightbox]

Click on "Properties" and go to C/C++ Build and uncheck "Exclude from build", as shown below.

[lightbox full="http://www.carminenoviello.com/wp-content/uploads/2015/02/Schermata-02-2457080-alle-14.10.44.png" title=""][/lightbox]

Ok. Now we can compile the test project and upload on our Nucleo board using GDB and OpenOCD.

To see messages on the UART you have several options according the Operating System you use. On the Eclipse Marketplace you'll find several terminal emulator plug-ins. TCF is one of these. Another option for Windows OSes is to use putty. On Mac and Linux ckermit is a suitable option.

[lightbox full="http://www.carminenoviello.com/wp-content/uploads/2015/02/Schermata-02-2457080-alle-15.08.19.png" title=""][/lightbox]

You can download the whole project from my github repository.

In a next article, I'll show you how to use the others Nucleo UARTs. Stay tuned 😉


Related posts

Upgrading Grove-UART Wifi V2 to latest ESP-AT firmware

Elegoo Car Kit V4

Correct way to perform re-annotation of designators in Altium

39 comments

Marius June 9, 2015 - 8:34 pm
I guess there just aren't any tutorials which touches Eclipse IDE, just aren't!. This is due the inconsistency mess that comes with any Java tools.... I consider I am an experienced engineer (coinscode.com) and I was struggling entire day to get one simple ST Micro compiled under Linux and I could not. I gave up. Though, the tutorial is complete but Eclipse screw it up totally, and screws up any decent programmer.
Carmine Noviello June 10, 2015 - 1:34 pm
Hi Marius, I agree with you: Eclipse can transform every programmer in a serial killer, especially if you have a non so recent PC. I've also successfully setup a complete working toolchain based on a Makefile and a simple text editor like VIM. I'll spend two words about this soon.
tinkerer August 25, 2016 - 3:03 pm
But there's also Code::Blocks which runs much more smoothly than eclipse - and guess what, it's not Java based ;) I've read about some people using it for gcc arm embedded work, have not tried embedded dev in c::b myself
Merelda August 27, 2015 - 6:41 am
Hey, just want to say thanks for the post. Clear explanation and great write-up. I'm actually using Keil uvision but it's still very relevant, thanks
Merelda August 27, 2015 - 11:29 am
Is it possible for you to add HAL_UART_Receive() function? I tried to look everywhere but can't find any examples on Receiving from Serial monitor/keybaord.. Thanks!
Kacper October 18, 2015 - 9:47 pm
Hello, thanks for all tips. I'm trying to get UART working for quite some time now and it's driving me nuts I can't do it. I'm using CUBE + IAR and HAL. Any tips why instead of getting normal characters I'm receiving garbage? I'm using HAL_UART_Transmit. What I'm missing?
Carmine Noviello October 19, 2015 - 6:24 am
Hi, to give a better help I need to know the type of your Nucleo board. Moreover, past here the clock and UART configuration routines.
RaulP December 23, 2015 - 5:09 pm
Hi Carmine, Its a great tutorial I must say. But do you have a an example to interact with the STM32 Nucleo over serial port.I am trying it out using the Serial APIS on windows and can get the data on the STM32 Nucleo (with few glitches).Just wondering if you have a working - clean example for the same. Eager to hear from your side.! Rgds, Rp
Carmine Noviello December 23, 2015 - 5:45 pm
Hi RaulP, Take a look to this repository: https://github.com/cnoviello/mastering-stm32 You should find what you are looking for under the "CH8" examples.
RaulP December 26, 2015 - 3:49 pm
Hi Carmine, OK , I followed the instructions from your book and able to create the Eclipse Environment. I am able to build and flash the hello-nucleo image and see the LED in action. Just wondering is it that simple to use the projects you have uploaded on git.I tried with CH8 chapter for f401re to test the serial port application. But I am getting this error : make all Building file: ../system/src/stm32f4xx/stm32f4xx_hal.c Invoking: Cross ARM C Compiler arm-none-eabi-gcc -mcpu=cortex-m4 -mthumb -Og -fmessage-length=0 -fsigned-char -ffunction-sections -fdata-sections -fno-move-loop-invariants -Wextra -g3 -DDEBUG -DOS_USE_SEMIHOSTING -DTRACE -DOS_USE_TRACE_SEMIHOSTING_DEBUG -DSTM32F401xE -I/Users/cnoviello/STM32Toolchain/mastering-stm32/nucleo-f401RE/include -I/Users/cnoviello/STM32Toolchain/mastering-stm32/nucleo-f401RE/system/include -I/Users/cnoviello/STM32Toolchain/mastering-stm32/nucleo-f401RE/system/include/cmsis -I/Users/cnoviello/STM32Toolchain/mastering-stm32/nucleo-f401RE/system/include/stm32f4xx -I/Users/cnoviello/STM32Toolchain/mastering-stm32/nucleo-f401RE/system/include/cmsis/device -std=gnu11 -MMD -MP -MF"system/src/stm32f4xx/stm32f4xx_hal.d" -MT"system/src/stm32f4xx/stm32f4xx_hal.o" -c -o "system/src/stm32f4xx/stm32f4xx_hal.o" "../system/src/stm32f4xx/stm32f4xx_hal.c" ../system/src/stm32f4xx/stm32f4xx_hal.c:54:27: fatal error: stm32f4xx_hal.h: No such file or directory compilation terminated. make: *** [system/src/stm32f4xx/stm32f4xx_hal.o] Error 1 system/src/stm32f4xx/subdir.mk:213: recipe for target 'system/src/stm32f4xx/stm32f4xx_hal.o' failed Or I may be missing something very minuscule here. While I try to figure it out can you please tell if you have any serial Application running on windows(even a console line will do) which can send a string pattern ( N number of times - different string with different length). C:\STM32Toolchain\projects\nucleo-f401RE\src\ch8 is the file I am referring to currently to test the serial communication (reception part mostly). C:\STM32Toolchain\projects\nucleo-f401RE is the project I am referring to . Thanks and Rgds, Rp And yes Merry X-Mas !!
RaulP December 26, 2015 - 7:35 pm
OK I fixed this one by fixing the Include Paths for GNU C and C++.But I am really looking for a way(a windows application which can send data as I said previously) to STM32 and later can also process it. Thanks in advance ! Rgds, Rp
Carmine Noviello December 31, 2015 - 10:21 am
Hi, For the Windows application you can take in consideration to create a simple Python script with pyserial module. It would be really easy to do the app you need.
RaulP January 1, 2016 - 8:18 am
ok thanks for the info /I will try it out. can it also send the end of line characters at the end of the line read form the text file?
Carmine Noviello January 1, 2016 - 10:43 am
Yes, for sure. It's just a byte sent over the serial interface.
tiwag February 23, 2016 - 10:10 pm
thanks, very useful! got it to work faster than feared. do you have also examples using the interrupt driven uart?
Carmine Noviello February 24, 2016 - 6:45 am
Take a look to examples of my book: https://github.com/cnoviello/mastering-stm32
 In Chapter 8 examples you'll find also how to UART in interrupt mode.
DEM May 16, 2016 - 10:47 pm
Hello Carmine. All great posts. Great Job. I have followed these instructions to get this working with my STM32F401RE and could build it. I did veer from the path a but by enabling TIM1 in CubeMX using FreeRTOS as my OS. What I am getting is a TIM6_DAC_IRQn is undeclared in the stm32f4xx_hal_tim_template.c file and TIM6 undeclared in the in the same file. How can I be able to clear this up so can build the project?
DEM May 16, 2016 - 10:53 pm
My previous post should have read "...and could not build it." Apologize.
DEM May 17, 2016 - 2:26 am
I actually Excluded the file above from the project and it build. Not sure if this was the correct course of action.
Carmine Noviello May 17, 2016 - 6:06 am
Yes, this is the right procedure ;-)
Chandan Mishra May 27, 2016 - 11:33 am
I facing compilation error : ./src/_initialize_hardware.o: In function `MX_USART1_UART_Init': C:\Users\wi2wi\stm4f32xx\test\Debug/../src/_initialize_hardware.c:152: undefined reference to `HAL_UART_Init' I have check hal_uart.h file properties exclude resource from build Please help me to solve this error.
Carmine Noviello May 27, 2016 - 11:37 am
Ensure that the macro HAL_UART_MODULE_ENABLED is uncommented inside the file stm32fxxx_hal_conf.h.
Tyler June 10, 2016 - 7:13 pm
Hi Carmine, First I would like to say that your book has been very helpful! Definitely worth the $20. But when I got to chapter 8 and couldn't get the serial communication to work. I used the code from this tutorial (not the one in the book) and compiled it successfully, opened ckermit (I'm using Ubuntu), and realized my device is not showing up in the dev folder shown here: http://pastebin.com/sxyJVJQJ
 I tried "set line stlinkv2_5" and "set line /dev/tty" in ckermit and neither one worked. Any help would be great!
Carmine Noviello June 11, 2016 - 6:08 am
Hi Tyler, can you post the output from the "dmesg" command? I'm interested to the part when the ST-LINK interface is attached to the USB port. It looks an issue related to drivers.
Tyler June 13, 2016 - 4:54 am
I am working on a STM32F4 Disco board on Ubuntu with OpenOCD and Eclipse. I have read that I cannot do this via the usb cable connected to CN5 because I do not have a nucleo board. Would it work if I bought a USB to UART or USB to Serial? Would my computer recognize it as a COM device? I am trying to get it to work like the output of this 20 second video: https://www.youtube.com/watch?v=hHdDslVI7O0 I have already changed the nucleo code to fit the disco board by changing the pins and baud rate. I will post a link to the source and the output of "dmesg" tomorrow morning. Thank you for taking the time to help me. It means a lot.
Carmine Noviello June 13, 2016 - 1:45 pm
Hi Tyler, Like all ST development boards (Nucleo, Disco, Eval), the STM32F4-Disco has an integrated ST-LINK interface, which also provides a VCP. So, by connecting it to the USB you should be able to send UART message to the PC. It's a matter of drivers. The CN5 allows you to test USB OTG features, but it's not what you are looking for (it doesn't help having a UART to USB cable).
Tyler June 13, 2016 - 2:51 pm
I'm confused because I am getting different answers between you and the ST forums: https://goo.gl/B2IKXN This is the output of "dmesg" when just the CN1 cable is connected. When CN1 and CN5 are connected to the computer, all of the LEDs on the board turn off (even when in DFU mode). Regardless of the configuration, I cannot get the device /dev/tty* to appear.
Carmine Noviello June 13, 2016 - 3:00 pm
Ummm, I don't have direct experience with the STM32F4-Discovery board. I thought it has the VCP as the most of ST dev boards, but it seems that this feature is only possibile in the "more recent" STM32F4-DISC1. But it is also required do modify the board, as described here at page 13. You so need an external UART-to-USB dongle to interface one of the 407VG UARTs.
Tyler June 13, 2016 - 3:39 pm
I will purchase one. Thanks for the help!
Carmine Noviello June 13, 2016 - 3:42 pm
Yes, I think it's the best option. Because the other solution suggested by the user markt on the ST forum requires that you have a quite good knowledge of this platform, and that you are able to configure the USB stack from ST to create a "custom" VCP port. A 5$ UART->USB converter is the best choice in this phase.
Tyler June 13, 2016 - 2:52 pm
I apologize, I did not link the output. This is the output of "dmesg" http://pastebin.com/FuTf7NW4
Chandan Mishra August 22, 2016 - 1:48 pm
controller : STM32F411RE I am using USART2 as serial port with interrupt based. I enable NVIC in stmcubemx, its generated code whenever data is transferred from terminal interrupt is coming but uart state is HAL_UART_STATE_READY. Because of that its going to receive function UART_Receive_IT function and came out. Please help solve this issue and also I need guidance how to make uart as a interrupt mode.
Sumit January 16, 2017 - 10:30 am
Hello, I have one query. Can we use multiple uart to receive data using STM 32F207 Nucleo 144 board?? If yes do we Need to use multiple bufferes or Need to use timers?? I want to initilaise UART1,2,3 to receive data flowing through communication bus System.
Carmine Noviello January 16, 2017 - 11:18 pm
Yes, you are free to use as many UARTs as you need. Clearly, the application needs to be designed accordingly. Using multiple buffers is a possible solution (and probably the simplest one), but it depends a lot on the way you arrange your application. There is no need to use timers, I guess.
Manikandan March 24, 2017 - 10:53 am
Hi carmine, I'm using Nucleo F207ZG board in that i tried to make USB_CDC I attached St in build link with USB Micro B cable (CN1) to ubuntu machine and also connected Micro B cable (CN13) to another USB port of same ubuntu machine but it not showing properly , Ubuntu machine detect only St-link. In usbd_conf.c I did hpcd_USB_OTG_FS.Init.vbus_sensing_enable = DISABLE; And Heap size as 4000 and stack size as 2000 Then aslo it's STM Target board not detect , what i want to do ? Is there is problem in USB Cable whic i fixed Micro B usb cable in CN13 And what about jumper JP4 , (I'm using USB as device only so i OFF it )
Teo Maras September 5, 2017 - 4:39 pm
Hi Carmine, I'm trying to connect a STM32 board (on which VCOM is used and seen as UART on standard PC), to a Raspberry pi. Do you know if there is any driver for STM32 VCOM for Raspbian? Matteo
Samantha Bowman July 3, 2018 - 5:50 pm
Would this work the same for Nucleo F446RE board or would there be a different process?
Adición de conectividad Ethernet a un STM32-Nucleo - Electronica April 9, 2019 - 3:29 am
[…] para enviar algunos mensajes en el puerto COM virtual. Puedes encontrar más sobre esto aquí . Antes de que podamos imprimir mensajes en la serie, debemos configurar la interfaz […]
Rami August 13, 2019 - 5:04 pm
Hello Carmine, I am using NucleoF401RE I am facing two issues. 1 - When I run the code on my OSX, it works with no problem in polling mode. However, if I run the same code on windows 10, I get garbage output to the terminal. I checked that the Baud rate is matching for both terminal (eclipse) and my code. I have also tried all the possible available Baud rates and same issue. 2- When I follow your example from the book and try to use interrupts, the code gets stuck and I dont receive any output. I can't figure out how to make interrupts work. Thanks for the help.
Add Comment