0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

[STM32] printf/scanf implementation in CubeIDE console by UART with USB connection over ST-link

Last updated at Posted at 2023-10-25

This article explains how to implement printf and scanf in console of CubeIDE like the following image. Target of this article is just beginner in STM32.

image.png

Communication is conducted by UART with USB connection over ST-link.

Total procedure is composed of the following steps.

  • Hardware configuration
  • Software configuration
  • Terminal configuration

In this article, Nucleo-H743ZI2 is used as an example board.

Hardware Configuration

At the beginning, it is necessary to identify which pins are capable of UART communication through ST-link.
Check 'USART communication' section in the datasheet of Nucleo board.
The name of each Nucleo board is written on back-side of the board as "MB----".

image.png

You can find the user manual by searching "datasheet MB1364B" in this case for example.
In the document UM2407 of MB1364, you can find USART communication section on pp. 26-27.

image.png
image.png
(STMicroelectronics, User Manual UM2407)

Note that you need to confirm settings if your Nucleo has jumpers for ST-link configurations.

Now you have found out PD8 and PD9 are the pins for UART over ST-link from the above document (it depends your board).
According to the datasheet, you can set the pinout for communication in CubeIDE.

image.png

The configuration of UART is as follows.

image.png

Change Mode to Asynchronous and leave the rest as default.
Keep Basic Parameters for setting terminal later.

Software Configuration

The next step is implementing printf and scanf in the main.c file.

Read/Write by HAL is possible once UART is activated as the following code.

HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, const uint8_t *pData, uint16_t Size, uint32_t Timeout)
HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout)

Those are defined in "stm32xxxx_hal_uart.c" that is located at \Drivers\STM32xxxx_HAL_Driver\Src\ folder when you conduct code generation.

The following steps just will have the compiler connect standard input/output to the UART stream.

First, you need to include "stdio.h" for using printf/scanf in USER CODE Includes in the main.c file.

/* USER CODE BEGIN Includes */
#include <stdio.h>
/* USER CODE END Includes */

The following code will have the compiler connect standard output to UART for printf.

/* USER CODE BEGIN PFP */
#ifdef __GNUC__
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif

PUTCHAR_PROTOTYPE
{
  HAL_UART_Transmit(&huart3, (uint8_t *)&ch, 1, HAL_MAX_DELAY);
  return ch;
}
/* USER CODE END PFP */

Make sure to change the number of UART written as "huart3" in the code according to your configuration.

Also, the following code will have the compiler connect standard input to UART for scanf.

/* USER CODE BEGIN PFP */
#ifdef __GNUC__
#define GETCHAR_PROTOTYPE int __io_getchar(void)
#else
#define GETCHAR_PROTOTYPE int fgetc(FILE *f)
#endif

GETCHAR_PROTOTYPE
{
    uint8_t ch = 0;
    __HAL_UART_CLEAR_OREFLAG(&huart3);
	HAL_UART_Receive(&huart3,(uint8_t *)&ch, 1, HAL_MAX_DELAY);
	HAL_UART_Transmit(&huart3, (uint8_t *)&ch, 1, HAL_MAX_DELAY); //echo output for console
	return ch;
}
/* USER CODE END PFP */

If you plan using both of printf/scanf, then merged code can be used.

/* USER CODE BEGIN PFP */
#ifdef __GNUC__
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#define GETCHAR_PROTOTYPE int __io_getchar(void)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#define GETCHAR_PROTOTYPE int fgetc(FILE *f)
#endif

PUTCHAR_PROTOTYPE
{
  HAL_UART_Transmit(&huart3, (uint8_t *)&ch, 1, HAL_MAX_DELAY);
  return ch;
}

GETCHAR_PROTOTYPE
{
    uint8_t ch = 0;
    __HAL_UART_CLEAR_OREFLAG(&huart3);
	HAL_UART_Receive(&huart3,(uint8_t *)&ch, 1, HAL_MAX_DELAY);
	HAL_UART_Transmit(&huart3, (uint8_t *)&ch, 1, HAL_MAX_DELAY); //echo output for console
	return ch;
}
/* USER CODE END PFP */

It is known that the default syscalls.c file automatically generated by STM32CubeIDE results in unexpected behavior when internal buffering of the input stream is enabled [1].

To avoid this issue, you need to disable buffering before any call to scanf() as the following code.

int main(void)
{
  /* USER CODE BEGIN 1 */
	setvbuf(stdin, NULL, _IONBF, 0); //disable buffering for input stream
...

Now you can use printf and scanf by UART.

Terminal Configuration

Open the device manager and check the COM port of ST-link. In the following case, COM8 is the port.

image.png

In the console window, push "open console" button and choose"3 Command Shell Console".

image.png

Set the Connection Type to "Serial Port", then create new connection pushing "New..." button.

image.png

Set the all parameters according to hardware configurations.

image.png

Now you can use printf/scanf and the built-in terminal console in CubeIDE.

image.png

Example of changing PWM parameter while running

Enable timer and set parameters of it.
The PWM frequency are defined with prescaler (PSC) and counter period (ARR) as
$$f_\mathrm{PWM} = \frac{f_\mathrm{clock}}{PSC\times (ARR-1)}.$$

image.png

You can use the following code to activate PWM timer.

  HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);
  HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_1);

The following code allow you to update PWM frequency while runnning.

  printf("\033[H\033[J"); // Clear console window
  while (1) {
         printf("Enter new frequency in kHz: ");
         scanf("%d", &f_ref);
         printf("\r\nCurrent frequency: %d kHz\r\n",f_ref);
         TIM1->ARR = (int) f_clock/f_ref-1;
         TIM1->CCR1 = (int) (f_clock/f_ref-1)*duty;

    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }

Reference

This article were written based on the following forum contents.

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?