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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
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.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
... 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.
1 2 3 4 5 6 7 |
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 😉
39 comments
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.
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.
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
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
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!
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?
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.
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
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.
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 !!
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
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.
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?
Yes, for sure. It's just a byte sent over the serial interface.
thanks, very useful! got it to work faster than feared.
do you have also examples using the interrupt driven uart?
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.
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?
My previous post should have read "...and could not build it." Apologize.
I actually Excluded the file above from the project and it build. Not sure if this was the correct course of action.
Yes, this is the right procedure 😉
I facing compilation error :
./src/_initialize_hardware.o: In function
MX_USART1_UART_Init':
HAL_UART_Init'C:\Users\wi2wi\stm4f32xx\test\Debug/../src/_initialize_hardware.c:152: undefined reference to
I have check hal_uart.h file properties exclude resource from build
Please help me to solve this error.
Ensure that the macro HAL_UART_MODULE_ENABLED is uncommented inside the file stm32fxxx_hal_conf.h.
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!
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.
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.
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).
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.
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.
I will purchase one. Thanks for the help!
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.
I apologize, I did not link the output. This is the output of "dmesg" http://pastebin.com/FuTf7NW4
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.
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.
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.
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 )
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
Would this work the same for Nucleo F446RE board or would there be a different process?
[…] 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 […]
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.