We have an STM32 C/C++ project and we have redefined the weak fputc(int, FILE *) function in order to redirect printf output to some UART channel.
Up until now, we were building the project under IAR with the IAR compiler. The logging through UART was working fine.
We have now switched to the arm-none-eabi toolchain and are building the project with g++. But it looks like the redefinition of the fputc function is not linked anymore and so the UART logging is not working.
How can I force the use of the redefined function by printf?
Just had the same problem converting project from Keil to Cube. Found this elegant STM32 printf retarget to UART solution on GitHub (and please forgive the copy-paste):
/*# 7- Retarget printf to UART (std library and toolchain dependent) #########*/
#if defined(__GNUC__)
int _write(int fd, char * ptr, int len)
{
HAL_UART_Transmit(&huart1, (uint8_t *) ptr, len, HAL_MAX_DELAY);
return len;
}
#elif defined (__ICCARM__)
#include "LowLevelIOInterface.h"
size_t __write(int handle, const unsigned char * buffer, size_t size)
{
HAL_UART_Transmit(&huart1, (uint8_t *) buffer, size, HAL_MAX_DELAY);
return size;
}
#elif defined (__CC_ARM)
int fputc(int ch, FILE *f)
{
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, HAL_MAX_DELAY);
return ch;
}
#endif
// OR:
// Add syscalls.c with GCC
#ifdef __GNUC__
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif /* __GNUC__ */
/**
* @brief Retargets the C library printf function to the USART.
* @param None
* @retval None
*/
PUTCHAR_PROTOTYPE
{
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, HAL_MAX_DELAY);
return ch;
}
This may or may not work in your particular case, but you get the Idea...
In my case, I had to prepend function type with extern "C" :
extern "C" int _write(int fd, char * ptr, int len)
{
HAL_UART_Transmit(&huart1, (uint8_t *) ptr, len, HAL_MAX_DELAY);
return len;
}
The arm-none-eabi- toolchain is using newlib, which lets you redefine _write(int fd, const void *buf, size_t count) instead, all stdio output functions would then use that interface. fd==1 would correspond to stdout, fd==2 to stderr. You must provide a few more stub functions, like
void _exit(int) {
while(1)
;
}
etc. Most of them are trivial, but printf() requires a working _sbrk() too, because it uses malloc() internally.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With