Page 1 of 2

[F103] USB_RAW: Assertion "already receiving" after PC sleep and resume

Posted: Thu Sep 26, 2019 10:15 pm
by l0ud
Hi,
I've build USB-MIDI adapter with two endpoints based on USB-RAW example. I have 2 threads for USB processing: one for receiving data in a loop, one for sending when there is a need to do that.
Everything works without problems until I put the computer to sleep while the device is connected. It crashes right away after resuming from sleep (I made a led blink thread to catch the moment of crash).
MCU used: stm32f103c8t6.
My OS is Linux Manjaro, I didn't test that on Windows.

Assertion happens in receiving thread, inside usbStartReceiveI function:

Code: Select all

osalDbgAssert(!usbGetReceiveStatusI(usbp, ep), "already receiving");

In fact, usbp->receiving is equal to 2.

Beginning of thread loop:

Code: Select all

THD_FUNCTION(usb_out_thread_loop, p)
{
    (void)p;

    while (!chThdShouldTerminateX())
    {
        //get free item from jack queue
        midi_packet_s transaction_packets[16]; //64 bytes in endpoint / sizeof packet(4) = 16
        msg_t size;
        //receive from usb
        while ((size = usbReceive(&USBD1, 1, (uint8_t*)transaction_packets, sizeof(transaction_packets))) <= 0)
        {
            //todo: sleep?
            chThdSleepMilliseconds(100);
        }
        ... packet processing...


USB event callback is similar to one in USB_RAW example.

Code: Select all


static const USBEndpointConfig ep1config = {
    USB_EP_MODE_TYPE_BULK, // Bulk EP
    NULL,                  // SETUP packet notification callback
    NULL,                  // IN notification callback
    NULL,                  // OUT notification callback
    0x0040,                // IN maximum packet size
    0x0040,                // OUT maximum packet size
    &ep1instate,           // IN Endpoint state
    &ep1outstate,          // OUT endpoint state
    1,                     // Reserved?
    NULL                   // SETUP buffer (not a SETUP endpoint)
};

static void usb_event_cb(USBDriver* usbp, usbevent_t event)
{
    (void)usbp;
    switch (event)
    {
        case USB_EVENT_RESET:
            return;

        case USB_EVENT_ADDRESS:
            return;

        case USB_EVENT_CONFIGURED:

            chSysLockFromISR();
            usbInitEndpointI(usbp, 1, &ep1config);
            chSysUnlockFromISR();
            return;

        case USB_EVENT_SUSPEND:
            return;

        case USB_EVENT_WAKEUP:
            return;

        case USB_EVENT_STALLED:
            return;

        case USB_EVENT_UNCONFIGURED:
            return;
    }
}


I suspect there is a bug inside HAL, or at least USB_RAW example. What may be causing this?

Thank you for your help

Re: [F103] USB_RAW: Assertion "already receiving" after PC sleep and resume

Posted: Fri Sep 27, 2019 7:33 am
by Giovanni
Apparently the USB driver is in the middle of a receive operation when the host goes to sleep. Does the USB device get a reset when the host wakes up?

Giovanni

Re: [F103] USB_RAW: Assertion "already receiving" after PC sleep and resume

Posted: Fri Sep 27, 2019 5:47 pm
by l0ud
There is no USB_EVENT_RESET after host sleep nor after resume. The only reset event I got happens directly after connecting USB cable first time. Maybe there is reset after wakeup, but firmware is already crashed on assertion so I couldn't catch it.

Re: [F103] USB_RAW: Assertion "already receiving" after PC sleep and resume

Posted: Fri Sep 27, 2019 6:15 pm
by Giovanni
When the host exits sleep does it re-enumerate devices? enumeration should reset the device.

Anyway, wow can I reproduce this? can I use one of the existing demos?

Giovanni

Re: [F103] USB_RAW: Assertion "already receiving" after PC sleep and resume

Posted: Fri Sep 27, 2019 10:29 pm
by l0ud
It doesn't seem to reenumerate any devices at all. I can leave openocd st-link session open and after resume it just go on like it was before sleep. Also, I don't see any dmesg messages about reenumeration, except when my device is connected. In that case I see multiple URB errors and then failed enumeration triggered by that errors (I think) and it is of course failed because firmware is already crashed.

To be honest I don't know how to reproduce problem on your side without much effort. I think USB_RAW demo is sufficient, keeping in mind I'm running it on STM32F1 mcu. I would connect board with that demo to PC, then put that PC to sleep (not hibernate) and resume. If it doesn't trigger problem I would download Linux Manjaro (which I'm using right now) and then try to do the same. Maybe it's some incompatibility between newest linux releases and chibios?

Re: [F103] USB_RAW: Assertion "already receiving" after PC sleep and resume

Posted: Mon Sep 30, 2019 10:41 am
by l0ud
I connected my board at work to a PC with windows 10 with USB analyzer between. It crashed after resume too. I'm not sure about exact reason, because I don't have a debugger here.

However, on analyzer I can see there is ongoing IN transaction (with corresponding NAK-s because there are no midi events) and then Suspend, some time later Resume and Resume EOP. Then there is immediately continuation of IN transaction (again, with NAK-s) but I suspect firmware is crashed here.

So I think that USB Suspend and Resume events are a problem here.

Re: [F103] USB_RAW: Assertion "already receiving" after PC sleep and resume

Posted: Mon Sep 30, 2019 10:56 am
by Giovanni
I understood the scenario, thanks. I need to understand how to reset the transaction on the device side, there is no reset event to do that.

Moving this topic in "bug reports" for processing.

Giovanni

Re: [F103] USB_RAW: Assertion "already receiving" after PC sleep and resume

Posted: Mon Sep 30, 2019 9:20 pm
by l0ud
Thanks for confirming issue. I've made a quick workaround in _usb_suspend function.

Code: Select all

    for (i = 0; i <= (unsigned)USB_MAX_ENDPOINTS; i++) {
      if (usbp->epc[i] != NULL) {
        osalSysLockFromISR();
        if (usbp->epc[i]->in_state != NULL) {
          usbp->transmitting &= ~(1 << (i));
          osalThreadResumeI(&usbp->epc[i]->in_state->thread, MSG_RESET);
        }
        if (usbp->epc[i]->out_state != NULL) {
          usbp->receiving &= ~(1 << (i));
          osalThreadResumeI(&usbp->epc[i]->out_state->thread, MSG_RESET);
        }
        osalSysUnlockFromISR();
      }
    }


With this I have no longer any issue with sleep on my Linux PC, after resume it just works like it worked before.

Re: [F103] USB_RAW: Assertion "already receiving" after PC sleep and resume

Posted: Sun Oct 27, 2019 8:36 am
by Giovanni
Hi,

I have committed a slightly different fix in trunk, could you verify this fixes the problem on your side?

In general, about the suspend state, I wonder if the LLD should also reset the state of endpoints in order to terminate ongoing transactions, perhaps this is on required for USBv1 on the F103 but the matter is more complex on OTGv1 (there are FIFOs to be considered).

To be checked.

Giovanni

Re: [F103] USB_RAW: Assertion "already receiving" after PC sleep and resume

Posted: Wed Oct 30, 2019 12:45 am
by l0ud
Now it seems to be working correctly without any modifications in ChibiOS source on master branch.