cancel
Showing results for 
Search instead for 
Did you mean: 

STM32CubeIDE & C++ - Redirected printf no longer works - How to use cout?

NW27
Associate III

Hi,

I have a "C" project where the printf detailed below works for outputting to a UART.

When I change the STM32IDE compiler to a C++ project, the printf no longer works.

/****************************************************
 * 			UART Redirect							
 * Re-directs printf() to the UART8 for display 	
 * on the console									
 ****************************************************/
int __io_putchar(int ch)
{
  HAL_UART_Transmit(&huart8, (uint8_t *)(&ch), 1, 0xFFFF);
  setbuf(stdout, NULL);
  return 1;
}
 
int __io_getchar(void)
{
  uint8_t ch;
  HAL_UART_Receive(&huart8, (uint8_t *)(&ch), 1, 0xFFFF);
  return (int)ch;
}

My understanding is that COUT should be used for C++ projects.

How do I get the cout (& cin) operational (Redirect) ??

// main.cpp
 
using namespace std;
 
#include <iostream>
 
int main()
{
// Usage
cout << "Some String";
}

Thanks.

11 REPLIES 11
TDK
Guru

printf should work just fine in C++. I doubt cout is going to perform better.

Make sure you put those functions within "extern C" or within a C source file so they have the right linkage.

If you feel a post has answered your question, please click "Accept as Solution".
NW27
Associate III

Thanks,

I have tried the extern "C" and it made no difference. Still on output.

COUT would still be preferable because it handles C++ strings better.

Hi TDK,

I have exactly the same problem as NW27,

"printf should work just fine in C++" ... it sounds for me that there is not verification of this issue on the g++ compiler yet

Nobody can diagnose what’s going on with the little info you provided. There is unlikely to be an issue with using printf in C++ using GCC in general. More likely to be with what your implementation does with it. Microprocessors don’t have a built in stdout channel.
If you feel a post has answered your question, please click "Accept as Solution".

Hi Piranha,

thank four your reply,

finally, i got that think working somehow..

as a take_home_message: io_redirect compiles with g++ but does not work on reality. It must be done with gcc

HSh..2
Associate II

Hi every body.

I have a crazy problem and I`m stuck in a nerve-racking simple work.

working with STM32CubeIDE 1.5.1, code created from stm32cubemx 6.5.0

project converted to c++

wanna retarget printf to uart

in a .h file have this:

#ifdef __GNUC__

 #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)

#else

 #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)

#endif

and in the .cpp file with the same name, have this:

PUTCHAR_PROTOTYPE

{

while( !(USART1->ISR & 0x80) ); //TXE = 0: data is not transferred to the shift register

USART1->TDR = ch;

 return ch;

}

apart from the odd problem of jumping into HardFault_Handler() when using HAL_UART_Transmit()

I can never build the project successfully, I do have lots of different errors when changing all files to .cpp. the only file I dont change to .cpp is syscall.c, with that I get the first_error.

0693W00000SvlBWQAZ.png 

and when changing to syscalls.cpp, I get the second_error.

0693W00000SvlBRQAZ.png 

Kamil Duljas
Senior III

Try it. It works for me:

/* USER CODE BEGIN 0 */

extern "C" {

int __io_putchar(int ch) {

if (ch == '\n') {

__io_putchar('\r');

}

HAL_UART_Transmit(&huart2, (uint8_t*) &ch, 1, HAL_MAX_DELAY);

return 1;

}

int _write(int file, char *ptr, int len)

{

__io_putchar(*ptr);

}

}

/* USER CODE END 0 */

Dudo
Cave Salamander
Associate II

Worked in my C but not in (the same in fact) C++ project. Solution:

1) declare __io... function as "C". Otherwise name of function will be "C++ decorated" and linker doesn't use it instead of default empty stub. OK, now it works at least but stops after some printed chars.

2) use setbuf(stdout, NULL); as suggested here to disable buffering.

3) enjoy! 🙂

DbgConsole.h

#ifndef INC_DBGCONSOLE_H_
#define INC_DBGCONSOLE_H_
 
#include "usart.h"
 
#ifdef __cplusplus
extern "C" {
#endif
 
// Serial port to use. Pass NULL to disasable output
void SetConsole(UART_HandleTypeDef* huart);
 
#ifdef __cplusplus
}
#endif
 
#endif /* INC_DBGCONSOLE_H_ */

DbgConsole.c

#include <stdio.h>
#include "usart.h"
#include "DbgConsole.h"
 
static UART_HandleTypeDef* huart;
 
void SetConsole(UART_HandleTypeDef* huart_)
{
 huart=huart_;
 setbuf(stdout, NULL);
}
 
#ifdef __GNUC__
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif
 
PUTCHAR_PROTOTYPE
{
 if(huart)
  HAL_UART_Transmit(huart, (uint8_t*)&ch, 1, HAL_MAX_DELAY);
 return ch;
}

Usage:

/* USER CODE BEGIN Includes */
...
#include "DbgConsole.h"
...
/* USER CODE END Includes */
...
int main(void)
{
...
 /* Initialize all configured peripherals */
...
  MX_USART1_UART_Init();  // for example
...
  /* USER CODE BEGIN 2 */
  //--------------------------------------------------------------------
  SetConsole(&huart1);
 
  printf("Hello World\n");
...
}