Using <iostream> in an MBED Project

Hello everyone! I am trying to figure out how to integrate std C++ functionality into the console for a micro:bit.

Here is a sample program demonstrating such but it does not compile and the errors are not terribly revealing.

Thoughts?

Error: No space in execution regions with .ANY selector matching ../../build/main.NRF51_MICROBIT.o(.bss).
Info: Unable to download. Fix the reported errors...


#include "MicroBit.h"
#include <iostream>

MicroBit uBit;

int main()
{
    // Initialise the micro:bit runtime.
    uBit.init();

    // Insert your code here!
    uBit.display.scroll("HELLO WORLD! :)");
    
    std::cout << "Hi there!" << std::endl;

    // If main exits, there may still be other fibers running or registered event handlers etc.
    // Simply release this fiber, which will mean we enter the scheduler. Worse case, we then
    // sit in the idle task forever, in a power efficient sleep.
    release_fiber();
}

the iostream will add more than 200 kB stuff, that might not fit into your flash. The streams are not optimized for microcontrollers, many people even avoid to use printf in embedded envrionment.

Thanks @JojoS I had that in mind but wanted to confirm as it is a massive lib. What are the best solutions to working with I/O in the console UART here any thoughts?

I’m still using good old printf(), the Cortex-M have usually enough resources for this. Mbed uses now also a minimal-printf implementation with some limits to save space, but that can be adjusted in mbed_app.json.

https://os.mbed.com/docs/mbed-os/v6.5/apis/printf-and-reducing-memory.html

Thanks again @JojoS i just found the serial class as well so I think that might be a good solution as well as I can send and read which should accomplish my uart functionality. I will check out your printf API as I will be using that as well than you so kindly for the help!

Hello,

You can overload the << operator for the BufferedSerial and/or the UnbufferedSerial classes to have the same syntax as in case of the std::cout iostream. The data types you can print will depend on what you implement. The overhead should be small compared to the std::cout as explained by Johannes.

#include "mbed.h"

#define endl    "\r\n"

DigitalOut      led1(LED1);
BufferedSerial  cout(USBTX, USBRX);
int             i = 0;
float           f = 0;

// Overloaded to print C style strings
BufferedSerial &operator<<(BufferedSerial& obj, const char* arg)
{
    obj.write(arg, strlen(arg));
    return obj;
}

// Overloaded to print "int" type
BufferedSerial &operator<<(BufferedSerial& obj, int arg)
{
    char buf[5] = { 0 };

    sprintf(buf, "%i", arg);
    obj.write(buf, strlen(buf));
    return obj;
}

// Overloaded to print "float" type
BufferedSerial &operator<<(BufferedSerial& obj, float arg)
{
    char buf[10] = { 0 };

    sprintf(buf, "%f", arg);
    obj.write(buf, strlen(buf));
    return obj;
}

int main()
{
    cout << "HELLO WORLD! :)" << endl;
    
    while (true) {
        led1 = !led1;
        cout << "blink" << endl;
        cout << "i = " << i++ << endl;
        cout << "f = " << f++ << endl;
        ThisThread::sleep_for(500);
    }
}

To print float data types add a mbed_app.json configuration file with the following content to your project:

{
    "target_overrides": {
        "*": {
            "target.printf_lib": "minimal-printf",
            "platform.minimal-printf-enable-floating-point": true,
            "platform.minimal-printf-set-floating-point-max-decimals": 6
        }
    }
}

Otherwise it will print f = %f.

Best regards, Zoltan

1 Like

Thanks @hudakz!