Skip to main content
Graduate II
January 7, 2021
Question

How to setup printf to print message to console

  • January 7, 2021
  • 12 replies
  • 99282 views

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?

    This topic has been closed for replies.

    12 replies

    ST Employee
    January 7, 2021

    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.1Author
    Graduate II
    January 7, 2021

    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.1Author
    Graduate II
    January 7, 2021

    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.

    Graduate II
    June 7, 2024

    Including the \n\r in the printf string worked for me on a NUCLEO-H753ZI. Another tricky thing was that my Nucleo board arrived with the solder bridges configured for using LPUART1 outputting to Arduino pins D0/D1 despite the documentation indicating the default configuration is USART3 outputting to the STLink virutal com port.

     

    LPetr.1Author
    Graduate II
    January 7, 2021
    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.1Author
    Graduate II
    January 8, 2021

    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.1Author
    Graduate II
    January 8, 2021

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

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

    Visitor II
    January 20, 2022

    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..

    Visitor II
    January 20, 2022

    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)

    ST Employee
    January 20, 2022

    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

    Visitor II
    January 24, 2022

    Thanks @suads​ and @Christophe VRIGNAUD​, I got the STlink UART working.