cancel
Showing results for 
Search instead for 
Did you mean: 

Trouble with printf and sprintf with float in STM32Cube + VS Code (CMake)

umut373
Associate

Hi everyone,

I'm working on an STM32 (Nucleo-F446RE to be spesific) project using the STM32Cube extension for VS Code, not CubeIDE. I'm using CMake for building the project.

I encountered a few issues:

  1. printf doesn't print anything to the serial monitor, so I switched to using HAL_UART_Transmit.

  2. When I try to print a float using sprintf(msg, "value: %f\n", var);, it doesn’t work. The output just skips the float value (e.g., "value: \n").

  3. After some research, I found out I need to add "-u _printf_float" to the linker flags to enable float formatting support with printf and sprintf.
    However, I'm new to CMake and I couldn’t figure out which CMake file I need to modify in the project folder to add this flag.

I'd really appreciate it if someone could guide me:

  • Where exactly should I add the "-u _printf_float" flag?

  • Is there anything else I should do to make printf work properly over UART?

Thanks in advance for your help.

1 ACCEPTED SOLUTION

Accepted Solutions
manolo_embedded
Associate

@umut373 wrote:
  • Where exactly should I add the "-u _printf_float" flag?


As a beginner, I faced the same problem.

I also use CMake, but I generate the project with STM32CubeMX, so I don't know what your configuration is. I use a NUCLEO-F439ZI board, so things might also be different on that side.

On my end, I have a toolchain configuration file ./cmake/gcc-arm-none-eabi.cmake and I added the following line to be able to use snprintf with floats (however, i'm not sure if it's the best way to do it) :

set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -u _printf_float")

 


@umut373 wrote
  • Is there anything else I should do to make printf work properly over UART?

For printf, I chose not to use it and instead created a custom function that resembles it and uses UART as you did.

void print_to_uart(UART_HandleTypeDef huart, const char *format, ...)
{
    char buffer[256];
    int cx;

    va_list args;
    va_start(args, format);
    cx = vsnprintf(buffer, sizeof(buffer), format, args);
    va_end(args); 

    if (cx >= 0 && cx < static_cast<int>(sizeof(buffer)))
    {
        HAL_UART_Transmit(&huart, (uint8_t*) buffer, cx, 1000);
    }
}

And I use it like this :

print_to_uart(huart3 ,"This is PI value : %f \n", 3.141592);



View solution in original post

4 REPLIES 4
Andrew Neil
Super User

@umut373 wrote:
  1. printf doesn't print anything to the serial monitor


Have you followed the instructions:

https://community.st.com/t5/stm32-mcus/how-to-redirect-the-printf-function-to-a-uart-for-debug-messages/ta-p/49865

 

A complex system that works is invariably found to have evolved from a simple system that worked.
A complex system designed from scratch never works and cannot be patched up to make it work.
manolo_embedded
Associate

@umut373 wrote:
  • Where exactly should I add the "-u _printf_float" flag?


As a beginner, I faced the same problem.

I also use CMake, but I generate the project with STM32CubeMX, so I don't know what your configuration is. I use a NUCLEO-F439ZI board, so things might also be different on that side.

On my end, I have a toolchain configuration file ./cmake/gcc-arm-none-eabi.cmake and I added the following line to be able to use snprintf with floats (however, i'm not sure if it's the best way to do it) :

set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -u _printf_float")

 


@umut373 wrote
  • Is there anything else I should do to make printf work properly over UART?

For printf, I chose not to use it and instead created a custom function that resembles it and uses UART as you did.

void print_to_uart(UART_HandleTypeDef huart, const char *format, ...)
{
    char buffer[256];
    int cx;

    va_list args;
    va_start(args, format);
    cx = vsnprintf(buffer, sizeof(buffer), format, args);
    va_end(args); 

    if (cx >= 0 && cx < static_cast<int>(sizeof(buffer)))
    {
        HAL_UART_Transmit(&huart, (uint8_t*) buffer, cx, 1000);
    }
}

And I use it like this :

print_to_uart(huart3 ,"This is PI value : %f \n", 3.141592);



Pavel A.
Super User

Instead of adding options to the linker command line (can be tricky with cmake) you can do this in your linker script (.ld file): add

EXTERN(_printf_float);

 

/* or even reference _printf_float in your C source file, but make sure it won't be discarded as unreferenced */

 

vincent_grenet
ST Employee

Be aware latest update is promoting some semihosting feature !
Let's have a try enriching your launch.json relying on serverSemihosting parameter.

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.