cancel
Showing results for 
Search instead for 
Did you mean: 

How to setup printf to print message to console

LPetr.1
Senior

Hello. I have STM32F767ZI nucleo board. I have created a new project and used default setup for the nucleo board. It have automatically set up some peripherals for me

0693W000006HnM9QAK.png 

In my code, I want to print the debug messages to the console:

 while (1)
 
 {
 
  /* USER CODE END WHILE */
 
 HAL_Delay(1000);
 
 printf("hello");
 
  /* USER CODE BEGIN 3 */
 
 }
 
 /* USER CODE END 3 */
 
}

But the printf is not working. I remember doing simmilar excersise in the class and it did not require any additional setup.

Can someone help me understand how printf works and how to set it up? Do I need to dedicate USART port for it?

11 REPLIES 11
Tilen MAJERLE
ST Employee

See example on link below:

https://github.com/STMicroelectronics/STM32CubeH7/blob/master/Projects/STM32H743I-EVAL/Examples/UART/UART_Printf/Src/main.c

You have to create output function that sends character parsed by printf to your stream.

LPetr.1
Senior

Hello. Thank you very much for your fast answer. From the example above, I copied the following and pasted in to my code:

#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__ */

and then further down the main.c

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

I have replaced the uart handle as huart3 because I have configured only USART3 on my cubemx.

The printf is still not working. I have noticed a lot of people talking about syscalls.c, do I have to implement anything there as well? My syscalls.c :

/**
 ******************************************************************************
 * @file      syscalls.c
 * @author    Auto-generated by STM32CubeIDE
 * @brief     STM32CubeIDE Minimal System calls file
 *
 *            For more information about which c-functions
 *            need which of these lowlevel functions
 *            please consult the Newlib libc-manual
 ******************************************************************************
 * @attention
 *
 * <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
 * All rights reserved.</center></h2>
 *
 * This software component is licensed by ST under BSD 3-Clause license,
 * the "License"; You may not use this file except in compliance with the
 * License. You may obtain a copy of the License at:
 *                        opensource.org/licenses/BSD-3-Clause
 *
 ******************************************************************************
 */
 
/* Includes */
#include <sys/stat.h>
#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
#include <signal.h>
#include <time.h>
#include <sys/time.h>
#include <sys/times.h>
 
 
 
 
/* Variables */
//#undef errno
extern int errno;
extern int __io_putchar(int ch) __attribute__((weak));
extern int __io_getchar(void) __attribute__((weak));
 
register char * stack_ptr asm("sp");
 
char *__env[1] = { 0 };
char **environ = __env;
 
 
/* Functions */
void initialise_monitor_handles()
{
}
 
int _getpid(void)
{
	return 1;
}
 
int _kill(int pid, int sig)
{
	errno = EINVAL;
	return -1;
}
 
void _exit (int status)
{
	_kill(status, -1);
	while (1) {}		/* Make sure we hang here */
}
 
__attribute__((weak)) int _read(int file, char *ptr, int len)
{
	int DataIdx;
 
	for (DataIdx = 0; DataIdx < len; DataIdx++)
	{
		*ptr++ = __io_getchar();
	}
 
return len;
}
 
 
__attribute__((weak)) int _write(int file, char *ptr, int len)
{
	int DataIdx;
 
	for (DataIdx = 0; DataIdx < len; DataIdx++)
	{
		__io_putchar(*ptr++);
	}
	return len;
}
 
 
 
 
int _close(int file)
{
	return -1;
}
 
 
int _fstat(int file, struct stat *st)
{
	st->st_mode = S_IFCHR;
	return 0;
}
 
int _isatty(int file)
{
	return 1;
}
 
int _lseek(int file, int ptr, int dir)
{
	return 0;
}
 
int _open(char *path, int flags, ...)
{
	/* Pretend like we always fail */
	return -1;
}
 
int _wait(int *status)
{
	errno = ECHILD;
	return -1;
}
 
int _unlink(char *name)
{
	errno = ENOENT;
	return -1;
}
 
int _times(struct tms *buf)
{
	return -1;
}
 
int _stat(char *file, struct stat *st)
{
	st->st_mode = S_IFCHR;
	return 0;
}
 
int _link(char *old, char *new)
{
	errno = EMLINK;
	return -1;
}
 
int _fork(void)
{
	errno = EAGAIN;
	return -1;
}
 
int _execve(char *name, char **argv, char **env)
{
	errno = ENOMEM;
	return -1;
}

 Also, might be worth to mention that I have got a warning message under the printf:

0693W000006Ho0AQAS.png 

In syscalls.c I have placed breakpoints on functions _write and _read. None of these functions are invoked after calling printf. I am not sure whethet thats the expected behaviour. Also, I have placed a breakpoints in HAL_UART_Transmit function and it never gets called either

LPetr.1
Senior

Just a quick update:

I have replaced my printf("hello") with another printf message that includes line termination character /n/r.

Now I can see that _write function is being called, however message still does not appear in the console.

LPetr.1
Senior
int main(void)
{
  /* USER CODE BEGIN 1 */
	uint8_t uart3_data[20] = "hello from uart3";
  /* USER CODE END 1 */
 
  /* MCU Configuration--------------------------------------------------------*/
 
  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();
 
  /* USER CODE BEGIN Init */
 
  /* USER CODE END Init */
 
  /* Configure the system clock */
  SystemClock_Config();
 
  /* USER CODE BEGIN SysInit */
 
  /* USER CODE END SysInit */
 
  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_USART3_UART_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */
 
  /* USER CODE END 2 */
 
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */
 
    /* USER CODE BEGIN 3 */
	  HAL_Delay(1000);
	  printf("UART Printf Example: retarget the C library printf function to the UART \n\r");
	  printf("** Test finished successfully. ** \n\r");
	  HAL_UART_Transmit(&huart3,uart3_data, sizeof(uart3_data), 50); // just to see what happens
	  
	
 
  }
  /* USER CODE END 3 */
}

I have been examinating it further and tested UART using terminal "termite".. From the datasheet I have found out something about usart3:

0693W000006HqMbQAK.pngAnd I am able to see the usart messages on the terminal

0693W000006HqMvQAK.png 

I am not sure whether thats a good sign or not, but I am still not able to see any messages on the debugging console window on the cubeIDE.

LPetr.1
Senior

Further update on my printf research (Still not able to print to console)

I have read this discussion:

https://electronics.stackexchange.com/questions/445815/stm32-swd-printf-not-working

And I have tried what they have suggested:

  1. Enabling the tracing and setting the sysclk frequency

0693W000006I02WQAS.png 

However, still no luck doing printf to the console.

Also, I would like to ask whether there is a difference which debugging option I chose?:

0693W000006I03oQAC.png 

LPetr.1
Senior

I have also tried this completely different aproach with no luck:

https://www.youtube.com/watch?v=sPzQ5CniWtw&ab_channel=ControllersTech

mneg
Associate

Same problem here. Trying official example projects for the NUCLEO-L552ZE-Q (e. g. RTC_Alarm) but seeing nothing in the debug console although this is said to be the case in the documentation. sprintf() seems to print into nothing. I invested some hours in research and tests (SWV etc) without success. Isn't there some official documentation about this? Can't be so hard to get this running..

suads
Associate III

Hi,

Include this into your project retarget.c and retarget.h and in main.c call this function  RetargetInit(&huart1), this needs to be called after MX_USART1_UART_Init(), this is if you are using uart1. You can use printf after calling RetargetInit

#ifndef _RETARGET_H__
#define _RETARGET_H__
 
//#include "stm32f0xx_hal.h"
#include <sys/stat.h>
 
void RetargetInit(UART_HandleTypeDef *huart);
int _isatty(int fd);
int _write(int fd, char* ptr, int len);
int _close(int fd);
int _lseek(int fd, int ptr, int dir);
int _read(int fd, char* ptr, int len);
int _fstat(int fd, struct stat* st);
 
#endif //#ifndef _RETARGET_H__

retarget.c

#include <_ansi.h>
#include <_syslist.h>
#include <errno.h>
#include <sys/time.h>
#include <sys/times.h>
#include <limits.h>
#include <signal.h>
#include <retarget.h>
#include <stdint.h>
 
#if !defined(OS_USE_SEMIHOSTING)
 
#define STDIN_FILENO  0
#define STDOUT_FILENO 1
#define STDERR_FILENO 2
 
UART_HandleTypeDef *gHuart;
 
void RetargetInit(UART_HandleTypeDef *huart) {
  gHuart = huart;
 
  /* Disable I/O buffering for STDOUT stream, so that
   * chars are sent out as soon as they are printed. */
  setvbuf(stdout, NULL, _IONBF, 0);
}
 
int _isatty(int fd) {
  if (fd >= STDIN_FILENO && fd <= STDERR_FILENO)
    return 1;
 
  errno = EBADF;
  return 0;
}
 
int _write(int fd, char* ptr, int len) {
  HAL_StatusTypeDef hstatus;
 
  if (fd == STDOUT_FILENO || fd == STDERR_FILENO) {
    hstatus = HAL_UART_Transmit(gHuart, (uint8_t *) ptr, len, HAL_MAX_DELAY);
    if (hstatus == HAL_OK)
      return len;
    else
      return EIO;
  }
  errno = EBADF;
  return -1;
}
 
int _close(int fd) {
  if (fd >= STDIN_FILENO && fd <= STDERR_FILENO)
    return 0;
 
  errno = EBADF;
  return -1;
}
 
int _lseek(int fd, int ptr, int dir) {
  (void) fd;
  (void) ptr;
  (void) dir;
 
  errno = EBADF;
  return -1;
}
 
int _read(int fd, char* ptr, int len) {
  HAL_StatusTypeDef hstatus;
 
  if (fd == STDIN_FILENO) {
    hstatus = HAL_UART_Receive(gHuart, (uint8_t *) ptr, 1, HAL_MAX_DELAY);
    if (hstatus == HAL_OK)
      return 1;
    else
      return EIO;
  }
  errno = EBADF;
  return -1;
}
 
int _fstat(int fd, struct stat* st) {
  if (fd >= STDIN_FILENO && fd <= STDERR_FILENO) {
    st->st_mode = S_IFCHR;
    return 0;
  }
 
  errno = EBADF;
  return 0;
}
 
#endif //#if !defined(OS_USE_SEMIHOSTING)

Christophe VRIGNAUD
ST Employee

The debug printf is one of the functionality of the Serial Wire Viewer.

An article exists on this topic: How to redirect the printf function to a UART for debug messages

https://community.st.com/s/article/how-to-redirect-the-printf-function-to-a-uart-for-debug-messages

Videos are also available covering the SWV functionalities:

STM32CubeIDE Advanced Debug Features: Part1 to Part5

https://www.youtube.com/watch?v=4wT9NhlcWP4&list=PL7tUZeMaichqrlJN4PGu3-n6DbYrvoG-s