Skip to main content
Drake Miller
Associate II
November 14, 2018
Solved

How to get printf example working in another project

  • November 14, 2018
  • 9 replies
  • 13897 views

Hi, 

I am working with the Nucleo-F401RE board and I am trying to implement the printf function to work with UART2. I can load and run the example project, but implementing the same code does not work in a separate project.  

I have had zero luck getting this work after having read and implementing everything that I can find. 

I have the following code in the main function taken from the example. 

I am missing something crucial here and could use some insight. 

Thanks,

/* USER CODE END PFP */

#ifdef __GNUC__

 /* With GCC, 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__ */

/* USER CODE BEGIN 0 */

PUTCHAR_PROTOTYPE

{

 /* Place your implementation of fputc here */

 /* e.g. write a character to the EVAL_COM1 and Loop until the end of transmission */

 HAL_UART_Transmit(&huart2, (uint8_t *)&ch, 1, 0xFFFF);

 return ch;

}

This topic has been closed for replies.
Best answer by Piranha

Newlib library definitely calls _write() for standard output. So it has to be implemented somewhere. It seems that the original example had a file syscalls.c like this one:

https://github.com/joeferner/stm32-utils/blob/master/syscalls.c

It has function _write() implemented and calls __io_putchar() from there. You have to implement _write() in Your code.

Although my previous post is still valid, it is not complete. Output gets flushed on reaching newline character or calling fflush(stdout) function. Additionally there is an option to disable buffering entirely by calling setbuf(stdout, NULL). Examples rely on newline, but... For example, I'm looking at examples for STM32F7 and there they use "\n\r". There is no platform using that sequence, the correct one is "\r\n". Examples are not examples of high quality... =)

9 replies

john doe
Senior III
November 14, 2018

add syscalls.c to your project. copying the one from your other project should work just fine.

i tend to put the putchar prototype in user code 4, but thats just me.

Drake Miller
Associate II
November 14, 2018

Thank you for the quick reply. I have put the syscalls.c in my src folder and the putchar prototype after main( ) and still does not work.

If I put a break point in _write( ) it never gets there. Seems the printf call is not linked to the syscalls functions.

It is mind boggling why it won't work.

Seems like a setting or something fundamental not setup correctly. I am using STM32 Workbench.

Tesla DeLorean
Guru
November 14, 2018

Make sure you initialize the USART somewhere, it's clocks, pins, and settings, etc.

Clocks and pins might be hiding in MSP or BSP files.

Tips, Buy me a coffee, or three.. PayPal VenmoUp vote any posts that you find helpful, it shows what's working..
Piranha
Principal III
November 14, 2018

To ensure that all data gets written out (_write() called) before internal buffers reach some threshold, after a sequence of output operations You have to call:

fflush(stdout);

https://en.cppreference.com/w/c/io/fflush

Drake Miller
Associate II
November 14, 2018

Thank you Clive and Piranha.

Clive: I can get output using HAL_UART_TRANSMIT with no problem. So I am confident everything is setup correctly. I am also using the STMCubeMX tool which automates much of this.

Piranha: The example code does not do a flush. It simple adds the prototype for io_putchar and uses the HAL_UART_TRANSMIT to send out the individual characters.

I have done everything that the example does from a code perspective. Everyone else seems to have no problem getting this to work.

I've just written my own printf statement instead and now up and running with no issues, but it is not as elegant as this solution. Really frustrating cause I am not an expert but no slouch either.

Oh well kludge and move forward...

Piranha
PiranhaBest answer
Principal III
November 15, 2018

Newlib library definitely calls _write() for standard output. So it has to be implemented somewhere. It seems that the original example had a file syscalls.c like this one:

https://github.com/joeferner/stm32-utils/blob/master/syscalls.c

It has function _write() implemented and calls __io_putchar() from there. You have to implement _write() in Your code.

Although my previous post is still valid, it is not complete. Output gets flushed on reaching newline character or calling fflush(stdout) function. Additionally there is an option to disable buffering entirely by calling setbuf(stdout, NULL). Examples rely on newline, but... For example, I'm looking at examples for STM32F7 and there they use "\n\r". There is no platform using that sequence, the correct one is "\r\n". Examples are not examples of high quality... =)

Drake Miller
Associate II
November 15, 2018

You nailed it sir!!! OK. So now I understand that they have provided a handy capped version of printf as an example (SHAME).

I added the escape characters and WHA LA!

Luckily my new implementation does not have these limitations and behaves just like we'd expect from a printf statement.

THANKS! Now I can breath.

Piranha
Principal III
November 16, 2018

Newlib is not made by ST. And _write() function is actually a performance improvement, because writing chunks of data is more effective than writing single characters. You can disable buffering and then it writes out everything immediately. :)

dungeonlords789
Associate III
November 6, 2021
HSh..2
Associate
September 20, 2022

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.pngand when changing to syscalls.cpp, I get the second_error.

0693W00000SvlBRQAZ.png