Skip to main content
Graduate II
September 22, 2025
Question

printf and puts function not working in release build firmware

  • September 22, 2025
  • 3 replies
  • 774 views

Hi everyone,

I’m working on an STM32 firmware project (HAL + CubeIDE). I’m trying to output debug messages to Tera Term via UART using printf and puts.

Here’s the situation:

  • Debug build: Both printf and puts work perfectly.

  • Release build: Calling printf or puts causes the MCU to reset immediately. Maybe due to watchdog reset and these function call cause the MCU freezing.

I also retarget the printf function by implemented the following: 

int __io_putchar(int ch) {
 while (!(huart1.Instance->ISR & USART_ISR_TXE));
 huart1.Instance->TDR = (uint16_t)ch;
 return ch;
}

int _write(int file, char *ptr, int len) {
 for (int i = 0; i < len; i++) {
 __io_putchar(ptr[i]);
 }
 return len;
}

My questions:

  1. Why do printf and puts crash/reset in Release but work in Debug?

  2. Are there known issues with _write or __io_putchar in Release builds?

  3. Any recommended approach to safely use printf/puts in Release firmware for UART output?

Thanks in advance!

 

    This topic has been closed for replies.

    3 replies

    Explorer
    September 22, 2025

    Compare the build settings for debug and release.
    Normally you have semihosting enabled for debug, which includes additional code and these outputs are routed via JTAG/SWD or an UART line.

    Relase build setting do usually not.
    This is why you have debug and release builds in the first place - you don't do debug printf()s in release versions.


    I'm not using CubeIDE, so I don't know why it crashes.
    With my toolchain, the  _write and __io_putchar calls are empty functions in the release version, and thus printf()s in the release build amount to nothing.

    chai2145Author
    Graduate II
    September 22, 2025

    The thing is my application support CLI function, accept commands from console like tera term and response accordingly.

    Explorer
    September 22, 2025

    Then don't use the semihosting interface for that, but a separate UART.

    Or extend the release build settings accordingly.

    Super User
    September 22, 2025

    You can still run the Release version in the debugger to see what's happening.

     


    @chai2145 wrote:
    • Maybe due to watchdog reset and these function call cause the MCU freezing


    Maybe instrument your code so that you can see if that actually is the case ...

     

    As @Ozone said, check what's different between the builds - Optimisation level is another common one.

    When increasing the optimisation level breaks your code, that usually indicates flaws in the code.

    eg, failure to use 'volatile' where required...

    chai2145Author
    Graduate II
    September 23, 2025

    Hi Andrew, 

     

    I'd tried to debug the code, found that it actually stuck at while loop. 

    while (!(huart1.Instance->ISR & USART_ISR_TXE)); 

    and cause the watchdog reset.

    int __io_putchar(int ch) {
    	while (!(huart1.Instance->ISR & USART_ISR_TXE));
    	huart1.Instance->TDR = (uint16_t) ch;
    	return ch;
    }

     

    Explorer
    September 23, 2025

    To wich pins is UART1 routed, and what are these pins connected to externally ?

    Is UART1 initialized anywhere in your release code ?
    I suppose not.