Hitchhiker's Guide to Printf in Mbed 6

It seems like there’s a problem with scanf() if I declare a BufferedSerial object using USBTX, USBRX (but without redirecting the console). An example code below:

    BufferedSerial serial_port(USBTX, USBRX, 9600);

    int main() {
      char buffer[1024];
      printf("helloworld\n");
      while(1) {
        scanf("%s", buffer);
        printf("got:\n");
        printf("%s\n", buffer);
}

When I send a short string over serial, scanf() does not pick up anything. If I send a really long string, scanf() pick up the last few characters and printf() back. But after a few times sending, scanf() start acting like normal again (pickup whole string and printf() back whole string).
If I have to guess, the BufferedSerial object I defined is swallowing up the serial buffer to fill up its own circular buffer, preventing the scanf()'s DirecSerial object to get any. But once my own BufferedSerial object circular buffer filled up, somehow it relax the priority and let DirectSerial have the priority.

Adding override make everything works normally:
FileHandle *mbed::mbed_override_console(int fd) {
return &serial_port;
}

Yeah your analysis sounds about right. Having two serial port objects active seems to be a recipe for trouble.

Useful thread, thanks.
Simple question about buffer sizes,
/** Software serial buffers
* By default buffer size is 256 for TX and 256 for RX. Configurable
* through mbed_app.json
*/

What exactly do I need to insert into mbed_app.json ?

Wait you mean you didn’t get your psychic powers? They were supposed to be included with each download of Mbed OS, that’s how you’re supposed to find these config option names. /s

Looking through the source code (mbed-os/drivers/mbed_lib.json), the option names seem to be drivers.uart-serial-txbuf-size and drivers.uart-serial-rxbuf-size.

3 Likes

For those who don’t work with Mbed frequently it could take some effort and time (linked with frustration) to figure out which parameters can be configured and what to put into the “mbed_app.json”.

The configuration system is documented at The configuration system - Program setup | Mbed OS 6 Documentation but the info below might help.

  1. Search the actual “mbed-os” (including subfolders) for “mbed_lib.json” files (189 in Mbed OS 6.9.0).

  2. Filter out those related to “test” (139 remain in Mbed OS 6.9.0).

  3. If you are looking for something very specific (target, device etc.) you can easily narrow the list.

  4. For “common options” it’s worth to check:

    mbed-os/drivers/mbed_lib.json
    mbed-os/events/mbed_lib.json
    mbed-os/platform/mbed_lib.json

  5. To set a parameter listed in a “mbed_lib.json” file it is important to know also the name of the associated library. That’s indicated as first field in the “mbed_lib.json” file. In your “mbed_app.json” file first put the library’s name followed by a dot and the parameter’s name. The new value you’d like to use goes after a colon.

    For example, to set the “uart-serial-txbuf-size” which is listed in the “mbed-os/drivers/mbed_lib.json”
    and the “stdio-baud-rate” listed in the “mbed-os/platform/mbed_lib.json” file
    put the following into your “mbed_app.json” file located in the root directory of your project:

{
    "target_overrides": {
        "*": {
            "drivers.uart-serial-txbuf-size": 128,
            "platform.stdio-baud-rate": 115200
        }
    }
}

You can add any number of parameters. The order doesn’t matter. However, make sure they are separated by a comma.
There is also indicated a “help” field for each parameter in the “mbed_lib.json” which provides a description and a “value” showing it’s default value.

You can verify your settings after compilation by checking the “mbed_config.h” file. It is automatically generated and saved to the root directory of your project. Parameters are defined as upper case macros preceded by “MBED_CONF_”.

2 Likes

Thanks Jamie, thanks Zoltan.

I have a similar problem with USBSerial. I override the console to use the USBSerial and printf works without issues. However with scanf and getchar, it seems to buffer the inputs and return them all at once (around 1000 chars). It works when I use the USBSerial::getc() method instead. So it seems to be an issue with the combination of getc() redirection and USBSerial. Does anybody have an idea what is causing this?

Thanks for the great posts. very helpful.
One question mbed-app.json does not seem to be used when compiling a library (e.g. mbed compile --library --source=mbed-os …). Looking at the source mbed.py it is only included when building a complete application. Is the only option to manual change in the different mbed_lib.json files or is there an other possibility?

The mbed_app.json seems to be used when building a library too.

mbed-os/tools/build_api.py:

def build_library(src_paths, build_path, target, toolchain_name,
                  dependencies_paths=None, name=None, clean=False,
                  archive=True, notify=None, macros=None, inc_dirs=None, jobs=1,
                  report=None, properties=None, project_id=None,
                  remove_config_header_file=False, app_config=None,
                  build_profile=None, ignore=None, resource_filter=None, coverage_patterns=None):

    ...

    Keyword arguments:
    dependencies_paths - The location of libraries to include when linking

    ...

    app_config - location of a chosen mbed_app.json file

    ...

    # Pass all params to the unified prepare_toolchain()
    toolchain = prepare_toolchain(
        src_paths, build_path, target, toolchain_name, macros=macros,
        clean=clean, jobs=jobs, notify=notify, app_config=app_config,
        build_profile=build_profile, ignore=ignore, coverage_patterns=coverage_patterns)

    ...

I realize I should have been more specific about the Library. Mbed is having 2 “versions.” I mend that Mbed_app.json is not included when you build a static library (.a / .ar) instead of a linked executable. You then use the command: mbed compile --library. It is then using build.py to create one

The build_api.py build_library seems to be creating a source library that can be included in a future project .lib file.

Any help/advice on including the changes in a static library appreciated.

regards,
Paul

Hello Paul,

Now I see your point. However, since it doesn’t directly relate to printf, in order to avoid kidnapping this thread I’d suggest to open a new one and continue there, if you don’t mind.

Best regards, Zoltan

Thanks.

It is related, as the changes to enable printing to serial/printf must be done now be in mbed_app.json which is NOT included in a static library. However it is a separate and much broader issue than only this serial/printf issue.

i’ll raise a new issue.
regards,
Paul

Great post! Is there a way to get an ´mbed::FileHandle´ or similar out of a ´std::FILE´, that I can e.g. use together with int ´FATFileSystem::file_sync(fs_file_t file)´ ?

You can get the FileHandle of std by defining your own console.

For example:

...
FileHandle* stdFileHandle;  // declare a global variable
...
FileHandle* mbed::mbed_override_console(int)
{
    static BufferedSerial myConsole(STDIO_UART_TX, STDIO_UART_RX, 115200);
    stdFileHandle = &myConsole;  // get the std file handle
    return &myConsole;
}
...
int main()
{
   // FileHandle of std is available as 'stdFileHandle`
1 Like

How have you override the console to use USBSerial with printf ?
Any USBSerial methode doesn’t give you BufferedSerial class/object.

mbed_override_console is the function that redirects printf and it requires a FileHandle, not a BufferedSerial.

USBSerial itself derives from FileHandle, so you can just return the USBSerial object in that function.

As explained by @ boraozgen :

#include "mbed.h"
#include "USBSerial.h"

FileHandle* mbed::mbed_override_console(int)
{
    static USBSerial   myConsole(false, 0x1f00, 0x2012, 0x0001);
    return &myConsole;
}

Edit: To make this work

  • either create the myConsole as myConsole(true, 0x1f00, 0x2012, 0x0001);
  • or call myConsole.connect(); before returning from the function.

See below @ boraozgen’s tip.

I was my problem. Thanks for your answers.
Have you solved the getc redirection ?

I am using v6.12 and have found the same effect with getc.

I don’t remember solving it, it was just a PoC and I didn’t work further on it.