cancel
Showing results for 
Search instead for 
Did you mean: 

How to get printf example working in another project

Drake Miller
Associate II

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;

}

1 ACCEPTED SOLUTION

Accepted Solutions
Piranha
Chief II

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

View solution in original post

10 REPLIES 10
john doe
Lead

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

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.

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 Venmo
Up vote any posts that you find helpful, it shows what's working..
Piranha
Chief II

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

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
Chief II

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

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
Chief II

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
Senior III