2021-01-07 12:51 AM
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
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?
2021-01-07 12:54 AM
See example on link below:
You have to create output function that sends character parsed by printf to your stream.
2021-01-07 01:23 AM
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>© 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:
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
2021-01-07 02:14 AM
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.
2021-01-07 05:06 AM
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:
And I am able to see the usart messages on the terminal
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.
2021-01-08 04:55 AM
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:
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?:
2021-01-08 05:20 AM
I have also tried this completely different aproach with no luck:
https://www.youtube.com/watch?v=sPzQ5CniWtw&ab_channel=ControllersTech
2022-01-20 12:55 AM
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..
2022-01-20 08:30 AM
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)
2022-01-20 09:27 AM
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