During improving and porting my isochronous USB example to new USB API, I've found problem with usbGetReceiveTransactionSizeX() function.
For STM32 this function looks like
Code: Select all
#define usb_lld_get_transaction_size(usbp, ep) \
((usbp)->epc[ep]->out_state->rxcnt)
So, as you can see, it returns rxcnt from endpoint state.
Now, here's simplified version of how STM32 driver works:
- Interrupt comes from USB core
- IRQ handler clears interrupt registers, resumes driver's pump thread, calls OUT callback
- ...Some time...
- Driver's pump thread resumed
- Data pumped from RX FIFO to buffer, rxcnt updated
So, as you can see, rxcnt updated only after data is being pumped out to RX buffer. That sounds quite reasonable, but results problems in some cases. We can't use usbGetReceiveTransactionSizeX() in OUT callback.
First, in case of isoc transfers, I have to start next transaction right after current transaction finished/failed (i.e. in IRQ handler / callback). If I'm using some kind of buffer, I need information about how much data was received (and will be pumped into buffer, isoc transfers can vary in size) in current transaction to get next buffer pointer. I can't do that now.
Second, new synchronous (usbReceive()) USB API isn't working properly (if I'm not missing something important). Look at code called during IRQ handler:
Code: Select all
#define _usb_isr_invoke_out_cb(usbp, ep) { \
(usbp)->receiving &= ~(1 << (ep)); \
if ((usbp)->epc[ep]->out_cb != NULL) { \
(usbp)->epc[ep]->out_cb(usbp, ep); \
} \
osalSysLockFromISR(); \
osalThreadResumeI(&(usbp)->epc[ep]->out_state->thread, \
usbGetReceiveTransactionSizeX(usbp, ep)); \
osalSysUnlockFromISR(); \
}
That code has issues:
- usbReceive() will return invalid size, because usbGetReceiveTransactionSizeX() is called in IRQ handler.
- If driver's pump thread will have lower priority than user thread (in which usbReceive() was called) usbReceive() will return before data actually being pumped into buffer.
One way to (half-)fix that - somehow get transacrion size in IRQ handler, but I can't find any way to get RX size before reading data from RX FIFO at F4. My intuition says that XFRSIZ field in OTG_FS_DOEPTSIZx register should store real transfer size after it has been received, but I can find any proof for that. But this will not help in case of sync. API.
Another way - make additional callback, that's called only after data has actually been pumped out to buffer, and use it for synchronous API. But this will not help in case of isoc transactions.
What do think about that?