Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Redefining fputc function when using arm-none-eabi toolchain

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?

like image 466
Ril Dank Avatar asked Oct 30 '25 00:10

Ril Dank


2 Answers

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;
}
like image 92
Pavel Avatar answered Nov 01 '25 18:11

Pavel


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.

like image 29
followed Monica to Codidact Avatar answered Nov 01 '25 19:11

followed Monica to Codidact



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!