cancel
Showing results for 
Search instead for 
Did you mean: 

STM32G0 redirect printf() to _write() and use UART - How to?

AAnth.1
Senior

Hi,

I know the question has been asked before, and there is some information (to some extent) on the internet, though I cannot seem to make it happen. My question is:

How can I use print() for debugging purpose? I have an UART peripheral up and running fine. I have a syscalls.c file that has a _write() function defined:

__attribute__((weak)) int _write(int file, char *ptr, int len)
{
	int DataIdx;
 
	for (DataIdx = 0; DataIdx < len; DataIdx++)
	{
		__io_putchar(*ptr++);
	}
	return len;
}

So to my understanding, I should have the UART transmit implementation inside my _write function. So the modified _write function would look like this:

__attribute__((weak)) int _write(int file, char *ptr, int len)
{
	int DataIdx;
 
	for (DataIdx = 0; DataIdx < len; DataIdx++)
	{
		// __io_putchar(*ptr++);
		while (!LL_USART_IsActiveFlag_TXE(USART2)) {}
        LL_USART_TransmitData8(USART2, ptr[DataIdx]);
	}
	return len;
}

So when using

printf("Hello, world");

somewhere in my code, I would expect my _write function to be called.

However, doing step-by-step debugging, I can see that my printf() never calls the _write function.

Please find below my linker arguments:

-mcpu=$(MACH) -mthumb -mfloat-abi=soft --specs=nano.specs --specs=nosys.specs -TSTM32G031K8TX_FLASH.ld -Wl,-Map=$(OUTPUT)/$(BIN).map -Wl,--gc-sections -static

Can anyone guide me on what I am doing wrong?

Thank you,

1 ACCEPTED SOLUTION

Accepted Solutions
Peter BENSCH
ST Employee

Depending on the compiler, printf uses the function __io_putchar() or fputc.

If you use e.g. STM32CubeIDE (based on GNU GCC), you would have to adapt the function __io_putchar.

Please note that __io_putchar has the attribute weak, so you should define the new __io_putchar in your main.c for example.

Good luck!

Regards

/Peter

In order to give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.

View solution in original post

8 REPLIES 8
Peter BENSCH
ST Employee

Depending on the compiler, printf uses the function __io_putchar() or fputc.

If you use e.g. STM32CubeIDE (based on GNU GCC), you would have to adapt the function __io_putchar.

Please note that __io_putchar has the attribute weak, so you should define the new __io_putchar in your main.c for example.

Good luck!

Regards

/Peter

In order to give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.

Thank you, Peter. It somewhat works, but not entirely. I have posted my full minimalistic code below, where I also show my modification of __io_putchar(). I am using arm-none-eabi-gcc as you mentioned

AAnth.1
Senior

Managed to got it work. Following __io_putchar(int ch) implementation does the job:

int __io_putchar(int ch)
 
{
 
    while (!LL_USART_IsActiveFlag_TXE(USART2)) {}
 
    LL_USART_TransmitData8(USART2, ch);
 
 return ch;
 
}

 Thank you,

This guide and a video I found on YouTube suggest overring weak functions _write or __io_putchar() or fputc.

I have done that and cant get UART output using printf but it is working with

HAL_UART_Transmit(&huart1, (uint8_t *)szMsg, counter++, 1000);

User defined versions of _write or __io_putchar never get hit.

I walked through the disassembly of printf and these functions are never called. ANy Ideas?

Qye
Associate II

Started working when I added fflush(stdout);

CCend.2
Associate III

Thank you! I was pulling my hair out trying to override __io_putchar() and _write() and fputc() and not seeing any of those functions getting called by printf(). Adding fflush(stdout) made it work.

> Adding fflush(stdout) made it work.

Just disable buffering stdout.

setbuf(stdin, NULL);
setbuf(stdout, NULL);

 Also, the GNU library has function dprintf. It is like printf but prints to a file descriptor instead of FILE, without any buffering.