Only process DOEPINT.XferCompl on data packet as DOEPINTn.SetUp can occur with or without DOEPINT.XferCompl. When DOEPINT.SetUp occurs with DOEPINT.XferCompl, only DOEPINT.SetUp needs to be handled.
Moreover, ignore DOEPINT.XferCompl when it occurs with DOEPINT.StupPktRcvd as driver needs to wait for DOEPINT.SetUp to continue.
Maybe my patch can be refactored more elegantly taking into account this information.
+ /* Don't process XferCompl interrupt if it is a setup packet. */ + if (ep == 0 && (epint & (DOEPINT_SETUP_RCVD | DOEPINT_STUP))) { + epint &= ~((uint32_t)DOEPINT_XFRC); + } + if ((epint & DOEPINT_STUP) && (otgp->DOEPMSK & DOEPMSK_STUPM)) { /* Setup packets handling, setup packets are handled using a specific callback.*/
Apparently the patch is not sufficient, I am compiling using -O2 and it works (even without patch), using -O0 triggers an assertion with or without patch (host is Linux Mint).
Note that I already added code to prevent handling of DOEPINT_XFRC for EP0:
/* Receive transfer complete, checking if it is a SETUP transfer on EP0, than it must be ignored, the STUPM handler will take care of it.*/ if ((ep == 0) && (usbp->ep0state == USB_EP0_WAITING_SETUP)) return;
But it was not sufficient. You patch (second) does the same thing in another way.
I tested the 2nd patch again. No issues with debug checks, no issues without debug checks. Tested using -O2 -ftlo as well as -O0.
My build environment looks like this: GNU Tools for ARM Embedded Processors 6-2017-q2-update -specs=nano.specs -ggdb -fomit-frame-pointer -falign-functions=16 -falign-loops=16 usb host: Linux Mint 18.1
What else can i do?
Vinz
edit: Also did the cross check by reverting the patch which leads to the expected failure.
I did another test and modified the 2nd patch to only clear DOEPINT_XFRC when DOEPINT_STUP bit is set which fails. When only checking for DOEPINT_SETUP_RCVD bit it works. So you original code seems not to handle DOEPINT_SETUP_RCVD. I didn't find any documentation regarding the difference between DOEPINT_SETUP_RCVD and DOEPINT_STUP but i could imagine that DOEPINT_SETUP_RCVD is kind of an intermediate state and can just be ignored. But that also requires to ignore the respective DOEPINT_XFRC.
I think that there are 3 different problems with this dumb device:
1) The DOEPINT_XFRC interrupt arrives before the STUP interrupt: this can be handled by checking the current state of EP0 like the code I posted does. 2) The DOEPINT_XFRC interrupt arrives when the STUP interrupt is also pending, your 2nd patch handles this. 3) The DOEPINT_XFRC interrupt arrives after the STUP interrupt: We cannot tell if this is a normal OUT transaction following the SETUP packet or a leftover of the setup packet.
I think it is case 3 that is causing the problem.
The fun thing is that I don't even understand what this new OTG was supposed to fix...
For me, patch #2 without disabling assert inside _usb_ep0out makes Serial-over-USB working. I tried -Os, -O2, -O0 with success. Hardware: custom board with stm32L476RCT6 Firmware: chibios 17.6 Host: Windows 8.1 64bit