Open lefebvresam opened 2 months ago
USB support for STM32U5 was not available in the official Mbed OS. I have implemented some basic USB functionality for STM32U5. The code is not well tested but at least USBSerial is working on these targets. You may have a look at the code: USB FS support on Nucleo-U545RE-Q, Nucleo-U575ZI-Q, B-U585I-IOT02A: https://github.com/wdx04/mbed-os/commit/77a7bade380adb4c3760269e0982e278fd7c3705 USB HS support on Nucleo-U5A5ZJ-Q and STM32F723E-Disco: https://github.com/wdx04/mbed-os/commit/5a9b1261157997cf70d3f00149881d059f3f4415
Is there a plan to create a merge request for adding those feature in the mbed-os master branch? I think this is a common use case. Later I also want to use the same usb connection for firmware upgrades. If I can get it working maybe we can create a branch for it?
And is there a way to use this virtual com port as the default uart (std::printf)?
And is there a way to use this virtual com port as the default uart (std::printf)?
Yes, it is but you have to use an app with auto control of DTR signal.
https://forums.mbed.com/t/hitchhikers-guide-to-printf-in-mbed-6/12492/1 https://forums.mbed.com/t/redirecting-printf-to-usb-serial-in-mbed-os-6/14279
I'm still struggeling with the error fatal error: USBSerial.h: No such file or directory
. Should I have to add something in the CMakeLists somewhere in the targets folder? Next, I will use the demo of @wdx04 and change it for HSE use.
I'm still struggeling with the error
fatal error: USBSerial.h: No such file or directory
. Should I have to add something in the CMakeLists somewhere in the targets folder? Next, I will use the demo of @wdx04 and change it for HSE use.
Yes, you should link your application to the mbed-usb library:
target_link_libraries(mbed-app mbed-os mbed-usb)
Wow this looks better. Is there a reason that you need to link only this library and not others for SPI, IIC, storage, etc? And where this is documented?
target_link_libraries(${APP_TARGET} PRIVATE
mbed-os
mbed-usb
RA8875
dmaflash
widgets
interpreter
apprunlight
appbutton
appfogger
commandinterface
)
In general it is not a part of MbedOS core but it is an Mbed library - https://github.com/mbed-ce/mbed-os/wiki/MbedOS-configuration#mbed-libraries.
I created a branch for testing. https://github.com/mbed-ce/mbed-os/tree/feature/stm32u575xG_usb-support
After some small modifications in the clock settings file it's already working but there is:
It is VCP so the baudrate should be changed only on PC side.
Ah ok. I also see that the firnware is blocking until you open a terminal. I was searching on the internet for better examples how to dynamically load/unload the driver when connecting the cable, but examples are very poor. In the real world, the user will connect the USB cable and must see the logging information without resetting the device.
Is there any example how you can connect when cable is attached/detached without blocking the firmware?
My colleague used it like this
USBSerial serial(false);
template<typename... Args> void debugPrint(const char *msg, Args... args){
if(!serial.configured()){
serial.connect();
}
if(serial.configured()){
if(!serial.connected()){
serial.init();
}
}
if(serial.connected()){
serial.printf(msg, args...);
}
//else
printf(msg, args...);
}
Looks nice. I will test this. In my case, the printf should be 'routed' to the usb (for debug in the field) and other serial port is used for commands (application board connector). I wil also check for a way to upload the FW trough the same usb cable without using a programmer. Do you suggest one of the upload methods described on mbed ce (like using cube programmer) or can I use the 'default' bootloader from ST and use a dedicated tool like you have with an arduino board?
I understand, and i believe you can achieve that via combination of the code above and the method mentioned in topic what i posted few post above via.
I will check it in detail tomorrow. Thanks for all this useful information.
My colleague used it like this
USBSerial serial(false); template<typename... Args> void debugPrint(const char *msg, Args... args){ if(!serial.configured()){ serial.connect(); } if(serial.configured()){ if(!serial.connected()){ serial.init(); } } if(serial.connected()){ serial.printf(msg, args...); } //else printf(msg, args...); }
I couldn't resist to check this, seems to need the following setting in the USBPhy_STM32.cpp under USE_USB_OTG_FS:
hpcd.Init.vbus_sensing_enable = ENABLE;
Because the USB is automatically connecting when I enable vbus sensing with resistor divider I don't need the connect call. I only use this to rewire the stdout:
class MyConsole : public USBSerial {
// inherit all constructors
using USBSerial::USBSerial;
// override putc
virtual int _putc(int c) override {
USBSerial::_putc(c);
return c;
}
};
#ifdef STDOUT_USB
namespace mbed {
FileHandle *mbed_override_console(int fd) {
static MyConsole console(false); // non blocking
return &console;
}
}
#endif
However I was searching for a way to give a welcome text as soon as the terminal is connected, because you cannot connect the terminal first and startup the board secondly like you can do with a hardware serial port. Because it's USB the terminal connection breaks after each reset.
I tried something like this in the MyConsole class, but this is doing nothing:
virtual void callback_state_change(USBDevice::DeviceState new_state) override { // ISR?
switch (new_state) {
case Attached:
printf("Attached\n");
break;
case Powered:
printf("Powered\n");
break;
default:
break;
}
};
Alternatively I could create a new thread and wait for connected().
Secondly, to create a firmware upload method over usb, how do you see that? Is it creating a virtual drive where you copy paste the hex file like you have with nucleo boards? Or is it a protocol? Or do you expose the sd card as a drive? Is there any example of this or are there some more hints?
However I was searching for a way to give a welcome text as soon as the terminal is connected, because you cannot connect the terminal first and startup the board secondly like you can do with a hardware serial port. Because it's USB the terminal connection breaks after each reset.
Yeah, that is strange but I am not USB expert so I am not able say what is wrong. However my logic says this is not normal.
About Bootloader: I have some experiences with Bootloader under ARM Mbed and I did not tested this under MbedCE and I am also not sure this is worked feature at this moment, probably not. So as an alternative you can try Mcuboot. Here is an example from the past - https://github.com/AGlass0fMilk/mbed-mcuboot-demo
Maybe some points from discussing about - https://github.com/ARMmbed/mbed-os/issues/15156
About transfer and storage of binary: I do not know, from my point of view it depends on many things. For example if your on-chip flash is enough big for two binary then you do not need any external memory probably but if you already have SD card for something else then why not. I do not know about any protocol for transfer but you can do it by your self. A python script that will split whole binary to a chunks with crc and send it one by one over USB is possible i think.
This is working in my case:
class MyConsole : public USBSerial {
public:
MyConsole(bool b, RA8875& lcd) : USBSerial(b), _lcd(lcd),
_thread(osPriorityBelowNormal, 1024, nullptr, "usbserial") {
_thread.start(callback(this, &MyConsole::run));
}
~MyConsole() {
_thread.terminate();
}
// override putc
virtual int _putc(int c) override {
USBSerial::_putc(c);
return c;
}
private:
void run() {
bool connected = false;
bool previousconnected = false;
int c;
while(true) {
connected = this->connected();
if (!previousconnected && connected) {
print_welcome();
print_settings(_lcd);
print_menu();
this->printf("\n");
}
if (connected && this->readable()) {
int last;
last = _getc();
if (last != '\n' && last != '\r') {
c = last; // store the last char
} else {
switch(c) {
case 's':
print_settings(_lcd);
break;
case 'i':
print_welcome();
break;
case 'h':
print_menu();
break;
default:
break;
}
this->printf("\n");
c = '\0';
}
}
fflush(stdout);
previousconnected = connected;
ThisThread::sleep_for(100ms);
}
}
Thread _thread;
RA8875& _lcd;
};
#ifdef STDOUT_USB
namespace mbed {
FileHandle *mbed_override_console(int fd) {
static MyConsole console(false, lcd); // non blocking
return &console;
}
}
#endif
I did also some tests with available(), but the strange thing is that if you don't use _getc() the number always stays at 1. If you fastly type characters and to _getc() in a loop then the number increases and decreases by one after each _getc(). It looks like this counter is not 'the buffer' but maybe something that is filled after you do _getc() and new characters arrive. Because this is fuzzy, unclear, not specified and may be buggy I don't use it.
For the FW update let me further investigate.
Is there any option to forward crash info also to that virtual serial port? I have a lot of MBED_ASSERT(pointer) in my code and when an initialization is not OK of a pointer I normally should get a crash report. After the 'serial port forwarding trick' to USB, crash reports are never popping up anymore and the program just hangs.
I started some tests with the serial USB (OTG) on the STM32u575 to get a virtual com port on a Windows PC.
After fixing some issues with the clock config file (because it was never used and tested before), I have the following situation:
In main.cpp I include the driver:
And I always get:
/home/sam/git/hmipanel/source/main.cpp:10:10: fatal error: USBSerial.h: No such file or directory
In the custom targets file I use:
I'm not sure if I have to add also something in the "components" section? Is this anywhere described?
I also tried to add this in the mbed_app.json:
But in that case I get: