How to replace standart printf with printf-stdag.c implementation

Hi!
my project uses the printf implementation in this way:

 #ifdef __CC_ARM
  #pragma import(__use_no_semihosting)
  struct __FILE
  {
    int handle;
  };
  FILE __stdout;
	FILE __stdin; 
  void _sys_exit(int x)
  {
    x = x;
  }
  /* __use_no_semihosting was requested, but _ttywrch was */
  void _ttywrch(int ch)
  {
    ch = ch;
  }
 #endif
#endif

#if defined (__GNUC__) && !defined (__clang__)
  #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
  #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
	#define GETCHAR_PROTOTYPE int fgetc(FILE *f)	
#endif

/**
  * @brief  retargets the c library printf function to the usart.
  * @param  none
  * @retval none
  */
PUTCHAR_PROTOTYPE
{
  while(usart_flag_get(PRINT_UART, USART_TDBE_FLAG) == RESET);
  usart_data_transmit(PRINT_UART, (uint16_t)ch);
  while(usart_flag_get(PRINT_UART, USART_TDC_FLAG) == RESET);
  return ch;
}


GETCHAR_PROTOTYPE
{
   // while(usart_flag_get(PRINT_UART, USART_RDBF_FLAG) == RESET);
   // return(usart_data_receive(PRINT_UART));
	char ch;
	extern StreamBufferHandle_t stream_console;
	xStreamBufferReceive(stream_console,&ch,1,portMAX_DELAY);
	return (ch);
}

I implemented the functions as follows, but judging by the log, the output has not changed.
How to change the code for redirecting the print via printf-stdarg.c?

void vOutputChar( const char cChar,
                         const TickType_t xTicksToWait ) 
{

  while(usart_flag_get(PRINT_UART, USART_TDBE_FLAG) == RESET);
  usart_data_transmit(PRINT_UART, (uint16_t)cChar);
  while(usart_flag_get(PRINT_UART, USART_TDC_FLAG) == RESET);

}

/*
 * Return 1 for readable, 2 for writeable, 3 for both.
 * Function must be provided by the application.
 */

BaseType_t xApplicationMemoryPermissions( uint32_t aAddress )
{
	if( ( aAddress >= SRAM_BASE ) && ( aAddress < SRAM_BASE + SRAM_BASE_SIZE ) )
		return 3;

	if( ( aAddress >= FLASH_BANK1_START_ADDR ) && ( aAddress < FLASH_BANK1_END_ADDR ) )
		return 1;
    
    if( ( aAddress >= FLASH_BANK2_START_ADDR ) && ( aAddress < FLASH_BANK2_END_ADDR ) )
		return 1;
    
    
	return 0;
}

You probably need to write a wrapper which uses snprintf to write the formatted string to a buffer and then transmit this buffer -

Then redirect FreeRTOS_debug_printf and FreeRTOS_printf to your wrapper function - freertos_plus_projects/STM32H747_cube/CM7/Core/Inc/FreeRTOSIPConfig.h at master · htibosch/freertos_plus_projects · GitHub.

We got fed up with all the library stuff the printf and friends in newlib pulled in, and we needed to redirect the output, so we use an adapted implementation of printf in our projects. It’s at RRFLibraries/src/General/SafeVsnprintf.cpp at 3.5-dev · Duet3D/RRFLibraries · GitHub. It doesn’t guarantee to print doubles to the full available precision, but is otherwise fairly complete and doesn’t use heap memory (unlike the standard one). Then we define printf-like functions in a way similar to this:

int printf(const char * _ecv_array fmt, ...) noexcept
{
	va_list vargs;
	va_start(vargs, fmt);
	const int ret = vprintf(fmt, vargs);
	va_end(vargs);
	return ret;
}

int vprintf(const char * _ecv_array fmt, va_list vargs) noexcept
{
	return vuprintf([](char c)->bool
					{
						return c == 0 || write(c) >= 0;
					},
					fmt, vargs);
}

where ‘write(c)’ does whatever we want to do with each character.

2 Likes

Thank you David for sharing this, it looks good.

I maintain another branch of printf-stdarg.c here.

It is 100% C, uses no heap, is interrupt-proof. Floating point support still needs some work.

It does have 2 special formats to print an IP-address:

    /* IPv4 = 192.168.1.100 */
    FreeRTOS_printf( ( "IPv4 = %xip\n", FreeRTOS_htonl( IPAddress ) ) );

    /* IPv6 = fe80::7007 */
    FreeRTOS_printf( ( "IPv6 = %pip\n", ipv6.xIPAddress.ucBytes ) );

When you include printf-stdarg.c into a project, the newlib printf() stuff will get replaced automatically.

I added but the function was not automatically replaced. I got the correct output only after such a code.

#define ipconfigHAS_PRINTF			1
#if( ipconfigHAS_PRINTF == 1 )
	#define FreeRTOS_printf(X)			tiny_printf X
#endif

Thank you for sharing this Hein! I see that it is much easier to use.

That is correct - thank you for sharing!