Page 8 of 12
Re: example interfacing a STM32F4 with libusb
Posted: Mon Aug 13, 2012 2:09 pm
by kjellhar
Giovanni wrote:The transmission is split in "transactions", the driver cannot push the packets of the next transaction in the TXFIFO until the previous transaction is over and the application submits the next transaction buffer.
So the worst between FIFO size and transaction size is what limits the usable bandwidth.
I don't think there is a workaround for this, it is how the USB peripheral works (and may be intrinsic to the USB protocol).
Giovanni
As far as I understand, the transaction buffer is something related to the driver, while the TxFIFO is related to the hardware.
I can see that the driver code does not allow a new transaction to be started until the previous is ended, but what I understand from the RM0090-Reference manual p1054 is that the Transfer size can be larger than the TxFIFO as long as the TxFIFO is long enough to contain more 2 or more packets, and that the application (driver) writes data into the TxFIFO when it starts to deplete. (The following is something I have read somewhere else in the reference manual). The OTG hardware will continue to transmit packets as long as transfer size is not counted down to 0, and the TxFIFO contains at least one full packet. If the TxFIFO contains less data than a full packet while there are more data to be transmitted (according to the transfer size), it will be sent, and the transaction will be continued in the next frame.
As far as I understand, this is exactly what the "Half empty" interrupt is for. To enable the driver to refill the TxFIFO in the middle of a transfer, and by that ensure that there is always at least a full packet present in the buffer when the previous packet is finished.
Kjell
Re: example interfacing a STM32F4 with libusb
Posted: Mon Aug 13, 2012 2:12 pm
by kjellhar
I posted the last one before I saw your last Giovanni. Anyway, I'm reading the reference manual, but the USB part of it is incredibly dense.
Re: example interfacing a STM32F4 with libusb
Posted: Mon Aug 13, 2012 2:16 pm
by Giovanni
One possible explanation is that the "half empty" interrupt is not served fast enough to refill the FIFO in time, this way the time slot is lost.
If this is true then it would be a problem, there is not much that can be done, now I try to set optimisations to maximum and see if it makes any difference.
Edit: It doesn't, just a marginal improvement, it gets closer to 256KB by a small fraction.
Giovanni
Re: example interfacing a STM32F4 with libusb
Posted: Mon Aug 13, 2012 2:23 pm
by kjellhar
Giovanni wrote:One possible explanation is that the "half empty" interrupt is not served fast enough to refill the FIFO in time, this way the time slot is lost.
If this is true then it would be a problem, there is not much that can be done, now I try to set optimisations to maximum and see if it makes any difference.
Giovanni
But that should be solved by making the TxFIFO larger than 2x. Then the half empty interrupt would come when there is more than one packet left.
Re: example interfacing a STM32F4 with libusb
Posted: Mon Aug 13, 2012 2:26 pm
by Giovanni
Now it is 4X and the application sends transactions of 1024 bytes, so it should be 1MB/sec but it is still 256kB/sec.
It is like that "half empty" interrupt is not really triggered at FIFO half empty but full empty.
Giovanni
Re: example interfacing a STM32F4 with libusb
Posted: Mon Aug 13, 2012 3:07 pm
by kjellhar
Giovanni wrote:Now it is 4X and the application sends transactions of 1024 bytes, so it should be 1MB/sec but it is still 256kB/sec.
It is like that "half empty" interrupt is not really triggered at FIFO half empty but full empty.
Giovanni
When I tried to debug it, it seemed like the FIFO interrupt didn't trigger at all. The flag was set, but it didn't trigger the ISR. That was masked by the SOF interrupt. When this interrupt was triggered, the ISR checks all the flags and executes the FIFO code. This means that the FIFO will only be filled once at the start of each frame.
Re: example interfacing a STM32F4 with libusb
Posted: Mon Aug 13, 2012 3:23 pm
by Giovanni
Excellent, it is a good hint.
Probably the cause is that the EP interrupts are not enabled in DAINTMSK except for EP0. I will try to fix it later, I am off for a couple of hours.
Giovanni
Re: example interfacing a STM32F4 with libusb
Posted: Mon Aug 13, 2012 4:15 pm
by Mathias
Awesome you found time to look into the USB speed.
During my earlier tests, I found that speed scaled linear up to 4x packet size but not beyond that. Also I didn't manage to get the half_empty interrupt triggered although I think I enabled them correctly...
I'll test your code in a sec.
*edit*
@kjellhar My code only sends transmits one packet per time, I changed the code to reflect that and will push the code shortly. *edit2* pushed
@Giovanni It seems you hit the same bottleneck as I did. It scales pretty well up to 4x and beyond that only minor improvements. I managed to push the same ~5200 packets per second with your code then with
what I had. Does it scale with 8x for you at all? I need 16x to get those packets send.
I hope hope that interrupt wasn't enabled properly so we can fill the FIFO on half-empty.
Re: example interfacing a STM32F4 with libusb
Posted: Mon Aug 13, 2012 6:10 pm
by kjellhar
I'm looking into the transfer size setting, but I'm not that brilliant as a C programmer, so I need some help.
The DIEPTSIZ_XFRSIZ is set in usb_lld_prepare_transmit
This function set the register based on a value set in a variable declared as "USBInEndpointState *isp".
What I don't understand is how the size element in this structure is set. The calling function, usbPrepareTransmit, also defines this variable, but it is not passed on as a paramenter to usb_lld_prepare_transmit.
Could it be that the DIEPTSIZ_XFRSIZ is not correctly set??
Kjell
Re: example interfacing a STM32F4 with libusb
Posted: Mon Aug 13, 2012 7:12 pm
by Giovanni
The transfer size should be OK or the driver would not send the callback correctly which it does or the serial_usb driver would not work at all because it depends entirely from the callbacks behavior.
I think that the problem is entirely with interrupts, tomorrow I will give it a try.
After that the performance should scale linearly with the transaction size for multiplier=2 (or 3 at worst if there is a latency problem).
After fixing this another thing I wish to try is to have a dedicated thread performing the data copy from/to FIFOs in order to move heavy operations out of ISRs.
Giovanni