USB freezes when not reading serial data, bug or by design?

Discussions and support about ChibiOS/HAL, the MCU Hardware Abstraction Layer.
Post Reply
Engemil
Posts: 37
Joined: Thu Dec 19, 2024 12:50 am
Has thanked: 13 times
Been thanked: 10 times

USB freezes when not reading serial data, bug or by design?

Post by Engemil »

Hi!

Using ChibiOS Stable release 21.11.x
Microcontroller: STM32C071RB

I've been testing the USB driver for a while now, and have come to discover a situation where the microcontroller (STM32C071RB) freezes.

Steps:
- Simple example code, loop every 1 second print with chprintf the text "Test #<number>" to USB Driver 1 (USBD1)
- Listen to the serial communication from computer (Linux with minicom).
- When I stop listening to the serial communication, after a while, the microcontroller freezes.
- When I listen to the serial communication again, it continues like nothing happened.

Question: Is this by design or is this considered a bug?

The simple example code:

Code: Select all

/*
 * Simple USB serial communication example.
 * Listen on the USB serial port and print a message with:
 * $ sudo minicom -D /dev/ttyACM0 -b 115200
 * (or the appropriate device on your system).
*/

#include "ch.h"
#include "hal.h"
#include "chprintf.h"
#include "usbcfg/usbcfg.h"

int main(void) {
    halInit();
    chSysInit();
    sduObjectInit(&PORTAB_SDU1);
    sduStart(&PORTAB_SDU1, &serusbcfg);
    usbDisconnectBus(serusbcfg.usbp);
    usbStart(serusbcfg.usbp, &usbcfg);
    usbConnectBus(serusbcfg.usbp);
    
    uint32_t test_serial_usb = 0;
    while (true) {
        chprintf((BaseSequentialStream*)&PORTAB_SDU1, "TEST SERIAL OVER USB. Count: %U\r\n", test_serial_usb);
        test_serial_usb++;
        palToggleLine(LINE_LED_GREEN);
        chThdSleepMilliseconds(1000);
    }
}
Notes:
- I also tried to check if the USB state was USB_ACTIVE, and it seems as it was. Checking for USB_ACTIVE before writing with chprintf did not seem sufficient for avoiding the freezing.
- Quick fix test 1: In the os/hal/src/hal_serial_usb.c file I replaced all TIME_INFINITE with TIME_IMMEDIATE, which made it continue to run, with the expected result of seeing the "old data" from the filled up buffer queue (obqueue) with new data being printed when I listened to serial com again.
- Quick fix test 2: I used chnWriteTimeout() and it seems to work well. Should this be considered the standard solution?
User avatar
Giovanni
Site Admin
Posts: 14892
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 996 times

Re: USB freezes when not reading serial data, bug or by design?

Post by Giovanni »

Hi,

I think you should work with timeouts, if the host stops polling for data (buffers full) then packets are not sent. USB_ACTIVE means that the device has been enumerated not that it is under active polling.

You may try writing with a timeout, on timeout add a delay before retrying. The timeout is your signal that the host is not actively fetching data.

I imagine that just the write loop is freezing, the other threads should be unaffected.

Giovanni
Engemil
Posts: 37
Joined: Thu Dec 19, 2024 12:50 am
Has thanked: 13 times
Been thanked: 10 times

Re: USB freezes when not reading serial data, bug or by design?

Post by Engemil »

Giovanni wrote: Tue Feb 24, 2026 4:52 am Hi,

I think you should work with timeouts, if the host stops polling for data (buffers full) then packets are not sent. USB_ACTIVE means that the device has been enumerated not that it is under active polling.

You may try writing with a timeout, on timeout add a delay before retrying. The timeout is your signal that the host is not actively fetching data.

I imagine that just the write loop is freezing, the other threads should be unaffected.

Giovanni
Alright, thank you for the clarification!

I'll leave a small example code with the chnWriteTimeout() here for other people to see as well:

Code: Select all

/*
 * Simple USB serial communication example.
 * Listen on the USB serial port and print a message with:
 * 
 * $ sudo minicom -D /dev/ttyACM0 -b 115200
 * 
 * (or the appropriate device on your system).
 * 
*/

#include "ch.h"
#include "hal.h"
#include "chprintf.h"
#include "usbcfg/usbcfg.h"
#include <string.h>

int main(void) {
    halInit();
    chSysInit();
    sduObjectInit(&PORTAB_SDU1);
    sduStart(&PORTAB_SDU1, &serusbcfg);
    usbDisconnectBus(serusbcfg.usbp);
    chThdSleepMilliseconds(1500);
    usbStart(serusbcfg.usbp, &usbcfg);
    usbConnectBus(serusbcfg.usbp);
    
    uint32_t test_serial_usb = 0;
    
    while (true) {

       //chprintf((BaseSequentialStream*)&PORTAB_SDU1, "TEST SERIAL OVER USB. Count: %U\r\n", test_serial_usb);
        
        char buf[64];
        int len = chsnprintf(buf, sizeof(buf), "Count: %u\r\n", test_serial_usb);
        
        // Timeout: TIME_MS2I(x) (timeout in x ms), TIME_IMMEDIATE (immediate timeout), TIME_INFINITY (no time out)
        size_t written = chnWriteTimeout(&PORTAB_SDU1, (uint8_t*)buf, len, TIME_MS2I(100));  // 100ms timeout
        
        if (written < (size_t)len) {
            // Handle timeout or buffer full (host not reading)
        }
        
        test_serial_usb++;
        
        palToggleLine(LINE_LED_GREEN);

        chThdSleepMilliseconds(1000);
    }
}
Post Reply