Wanted to capture this in case it helps others.
Problem: remapping printf()
debugging output to a USB OTG Serial port (on a custom board but should also apply to standard supported boards.)
I thought this would be a simple problem that others had solved a long time ago as it must quite a common problem. Turned out it wasn’t so simple.
I was able to get some hints from the post Remaping printf on custom boards in Mbed 6 and the excellent Hitchhiker’s Guide to Printf in Mbed 6.
This got it basically working but not in all situations.
‘Blocking’ mode was fine: whenever debug output is flushed it waits for a terminal to be (re)connected before continuing the app. However, this means the board never runs without a terminal connected!
In ‘non-blocking’ mode, when the USB serial terminal is disconnected and reconnected the terminal would (re)connect but not get any data. Without a delay at the start of the app, there wasn’t time for the serial terminal to be connected for any output to be displayed. And disconnecting/reconnecting while the app is running stops any further output.
A further detail was that with the CCG compiler non-blocking mode worked fine. Seemed to be an issue with the Arm 6 compiler.
With help from Don Garnier at Arm, I now have a a solution that appears to work fine. The problem was that the Arm runtime library closes the console on the first error (CGG I assume just carries on.) The fix is to override the USBSerial _putc()
method to always return a success.
Example code: add to e.g. main.cpp
to redirect to USB Serial:
#include "USBSerial.h"
static constexpr auto UsbSerialBlocking = false;
static bool isConsoleInitialised = false;
class MyConsole : public USBSerial {
using USBSerial::USBSerial;
virtual int _putc(int c) override {
USBSerial::_putc(c);
return c;
}
};
static USBSerial* get_console() {
static MyConsole console(UsbSerialBlocking);
if(!UsbSerialBlocking && !isConsoleInitialised) {
console.init();
console.connect();
ThisThread::sleep_for(5s);
isConsoleInitialised = true;
}
return &console;
}
namespace mbed
{
FileHandle *mbed_override_console(int fd)
{
return get_console();
}
}
The 5s delay is optional. It enables the terminal to be connected or reset before main()
runs so the initial debug info isn’t missed when restarting the app/board.
Info: on Windows the _Tera Term _ serial terminal app works well as it handles the virtual COM port going away and coming back whenever the app/board is restarted by automatically reconnecting. Most other apps I tried (including Putty) just flag an error and need manual reconnecting every time.
Mbed OS 6.12.0
Board: STM32L4+ B-L4S5I-IOT01A