To_string(double): Operator new out of memory

I am developing for a STM32 Nucleo F103RB. This code:

#include <mbed.h>
#include <string>

BufferedSerial pc(USBTX, USBRX); // tx, rx

int main() {
  AnalogIn a1(PC_0);
  a1.set_reference_voltage(3.3);

  while(1) {
    string buf = "";
    buf = to_string(a1.read_voltage());
    pc.write(buf.c_str(), buf.length());
    wait_us(1e6);  
    }
}

causes the F103 to crash at line buf = to_string(a1.read_voltage()); with the following error message:

++ MbedOS Error Info ++
Error Status: 0x8001011F Code: 287 Module: 1
Error Message: Operator new out of memory

Location: 0x80022F9
Error Value: 0x80060E6
For more info, visit: https://mbed.com/s/error?error=0x8001011F&tgt=NUCLEO_F103RB
-- MbedOS Error Info --

the same error is thrown for code like

double val = a1.read_voltage();
buf = to_string(val);

I have similar code in an application for a STM32 F407, where no such error occurs. Is this a known issue on STM32F1s?

CONFIGURATION: https://docs.platformio.org/page/boards/ststm32/nucleo_f103rb.html
PLATFORM: ST STM32 (8.0.0) > ST Nucleo F103RB
HARDWARE: STM32F103RBT6 72MHz, 20KB RAM, 128KB Flash
DEBUG: Current (stlink) On-board (stlink) External (blackmagic, jlink)
PACKAGES:
 - framework-mbed 6.60200.200722 (6.2.0)
 - tool-dfuutil 1.9.200310 
 - tool-openocd 2.1000.200628 (10.0)
 - tool-stm32duino 1.0.2
 - toolchain-gccarmnoneeabi 1.90201.191206 (9.2.1)

The STM32F103RB has only 20kbyte of SRAM on board. This is very little and much of it will be used by mbed-os. When you call the std::to_string function it needs to claim some work space. It looks like it wants to claim more than is available.
To solve this you can do two things: get a device with more onboard memory (STM32F103RD) or write your own to_string function which uses a buffer on the stack.

I know that memory on the F103RB is quite limited - but with a static memory useage of just about 10% I wasn’t expecting problems when formatting a number as a string.

RAM:   [=         ]  10.5% (used 2144 bytes from 20480 bytes)
Flash: [==        ]  23.3% (used 30532 bytes from 131072 bytes)

I have tried using sprintf() instead of to_string() and found that this produces no output for the number. for example:

char number[32];
double val = a1.read();
sprintf(number, "x %f x\n", val);

results in the string x x.
I am using the bare metal profile with std as printf lib:

{
    "requires": ["bare-metal"],
    "target_overrides": {
      "*": {
        "target.printf_lib": "std"
      }
    }
}

Hello Gregor,

To save memory try to enable floating point support with printf-minimal rather than with the memory hungry std. For example, in mbed_app.json:

{
    "requires": ["bare-metal"],
    "target_overrides": {
        "*": {
            "target.printf_lib": "minimal-printf",
            "platform.minimal-printf-enable-floating-point": true,
            "platform.minimal-printf-set-floating-point-max-decimals": 3
        }
    }
}

To save some additional flash memory you can try to use the small C library:

{
    "requires": ["bare-metal"],
    "target_overrides": {
        "*": {
            "target.printf_lib": "minimal-printf",
            "platform.minimal-printf-enable-floating-point": true,
            "platform.minimal-printf-set-floating-point-max-decimals": 3,
            "target.c_lib": "small"
        }
    }
}

Event queue can be handy with bare-metal too. Have a look for example at Bare-metal Event Queue with BLUEPILL.

Best regards, Zoltan

Bare-metal is using the small-c lib already, in the case of gcc it is newlib-nano. But the default for this lib is not to use float for printf and scanf. That must be enabled by additional Compiler Switches.
So Zoltans hint maybe a solution, but another caveat is that minimal-printf does not support precision specifiers.

thank you, this solves both the operator new out of memory issue and the issue of missing output of sprintf.

Interesting, do you know why this is? I cound not find any mention in the documentation. I would be ok with using the same precision setting in my whole application, but the "platform.minimal-printf-set-floating-point-max-decimals" option seems to be ignored. (also, the output is 3 decimal places regardless of "platform.minimal-printf-enable-floating-point" being set to true or false)