Page 4 of 12

Re: example interfacing a STM32F4 with libusb

Posted: Wed Jul 11, 2012 5:17 pm
by Mathias
I tried to dig into the STM firmware library to see if they do something differently. Although I didn't always know exactly what the code does, most of them seemed similar.
Only thing I'm not sure about, are you using DMA to transfer the buffer to the USB system? Now I read some 32f4 specs and they write about "advanced FIFO control" and stuff like that... this looks too complicated for me for sure.

Re: example interfacing a STM32F4 with libusb

Posted: Wed Jul 11, 2012 5:56 pm
by Giovanni
There are two distinct USB peripherals in the various STM32, one with two variants:
- USB (USBv1 in HAL, this is the one in F103 and L1 devices)
- OTG-FS (OTGv1 in HAL)
- OTG-HS (this one has a dedicated DMA but it is not yet supported).

I don't think a DMA would make a difference anyway, the problem is not filling the buffers fast enough IMO.

Giovanni

Re: example interfacing a STM32F4 with libusb

Posted: Wed Jul 11, 2012 10:05 pm
by kjellhar
I have also started to look into the STM32F4 documentation, and this is how I understand it so far.

DMA transfer is only available in HS mode with external PHY.

I'm not sure about this double buffering your are talking about. Can't find any references to it.

The USB PHY is getting its data from a FIFO buffer for each EP. In FS mode, it will transfer up to 64bytes in each packet. Once this packet is finished, it will check the buffer, and if there is data available, it will transmit it immediately. This operation will go on for any multiple of 64bytes plus a smaller packet at the end. So if the EP encounters a situation where the buffer contains less than 64 bytes when it is finished with the last packet, it will assume it is the last packet in the transaction. My guess is that it will then wait until the next SOF before it can start over again. This again means it is important to keep filling the FIFO as soon as there is room for more data.

I haven't had the time to dive into the Chibios driver code yet, so forgive me for asking these questions.

I tried to set up a large buffer (1000 bytes) which is the one I feed into usbPrepareTransmit. This buffer is, as far as I understand, not the same as the FIFO used by the USB hardware. I assume that the driver somehow transfer from my buffer to the FIFO, but how is this handled. Does the driver wait until the packet is successfully transferred before it starts to fill a new packet? If this is the case, then I would guess we have a suspect.

Any comments on this?

thanks,
Kjell

Re: example interfacing a STM32F4 with libusb

Posted: Wed Jul 11, 2012 10:23 pm
by kjellhar
Giovanni wrote:There are two distinct USB peripherals in the various STM32, one with two variants:
- USB (USBv1 in HAL, this is the one in F103 and L1 devices)
- OTG-FS (OTGv1 in HAL)
- OTG-HS (this one has a dedicated DMA but it is not yet supported).

I don't think a DMA would make a difference anyway, the problem is not filling the buffers fast enough IMO.

Giovanni


Opps, I looked at the wrong lld files. The OTGv1 files makes more sense than USBv1.

Re: example interfacing a STM32F4 with libusb

Posted: Wed Jul 11, 2012 11:00 pm
by kjellhar
Ok, some more digging into the OTGv1 code.

The otg_txfifo_handler, which again copies data from the user buffer to the FIFO, is triggered by tge TXFE interrupt. This interrupt can be configured to be asserted when the FIFO is empty or half empty depending on the GAHBCFG_TXFELVL bit. In the OTGv1 code, GAHBCFG_TXFELVL is set, which means the TXFE interrupt will trigger when the FIFO is empty. I think this is too late since the USB hardware requires that the entire packet to be transmitted should be present in the buffer at that point. Also, if I read the code correct, the EP init only reserves space for one packet in the FIFO. I think the solution would be to reserve space for two packets, and to trig the TXFE interrupt when the FIFO is half full.

Hope this makes sense. If all this seems like nonsense, it may be that it is a bit too late for me.

Re: example interfacing a STM32F4 with libusb

Posted: Wed Jul 11, 2012 11:07 pm
by Mathias
Thanks Giovanni for the explanation about the different USB devices. That was unclear to me and now it makes a lot more sense. Youre right, I got the DMA confused with the HS device.
Still the FS device has 1.25kbytes of dedicated memory that have to be written and I think thats the problem (which kjellhar also guessed):
in usb_lld.c in the otg_txfifo_handler function, if I exchange

Code: Select all

  if (n > usbp->epc[ep]->in_maxsize)
    n = usbp->epc[ep]->in_maxsize;

with

Code: Select all

  if (n > usbp->epc[ep]->in_maxsize)
   n = 128;

I push nearly twice as many packets (in my libusb example). Although increasing it further hangs the system. This is not yet a valid solution, but I think the problem lies somewhere there. I will see if I can do something about it tomorrow.

Re: example interfacing a STM32F4 with libusb

Posted: Thu Jul 12, 2012 7:36 am
by Giovanni
The double buffering is related to the USBv1 peripheral only.

The OTG peripheral does not have packet buffers but FIFOs. The performance limit is related to the FIFO dept in case of the OTG.

Like kjellhar suggested, in order to optimize performance of the OTGv1 driver the TX FIFOs need to be dimensioned to be able to hold at least two full packets (or more) and must be aggressively filled. That was the plan since beginning but initially the driver proved to be troublesome and I aimed to achieve a stable functionality first.

In order to improve USB performance changes to the high level driver are not required, the USBv1 needs double buffering, the OTGv1 needs the mentioned improved TX FIFOs handling.

The problem with the OTGv1 driver is that FIFO filling is done in ISR context, so pushing too many packets at once would impact the system response time globally, this would not be a problem if done using DMA in the OTG-HS.

Giovanni

Re: example interfacing a STM32F4 with libusb

Posted: Thu Jul 12, 2012 7:38 am
by Giovanni
Mathias wrote:Thanks Giovanni for the explanation about the different USB devices. That was unclear to me and now it makes a lot more sense. Youre right, I got the DMA confused with the HS device.
Still the FS device has 1.25kbytes of dedicated memory that have to be written and I think thats the problem (which kjellhar also guessed):
in usb_lld.c in the otg_txfifo_handler function, if I exchange

Code: Select all

  if (n > usbp->epc[ep]->in_maxsize)
    n = usbp->epc[ep]->in_maxsize;

with

Code: Select all

  if (n > usbp->epc[ep]->in_maxsize)
   n = 128;

I push nearly twice as many packets (in my libusb example). Although increasing it further hangs the system. This is not yet a valid solution, but I think the problem lies somewhere there. I will see if I can do something about it tomorrow.


The general direction is correct, you need also to allocate enough RAM to the TXFIFO, currently it is dimensioned to hold one packet.

Giovanni

Re: example interfacing a STM32F4 with libusb

Posted: Thu Jul 12, 2012 12:52 pm
by Mathias
Hmm, there is already:

Code: Select all

#define STM32_USB_OTG1_RX_FIFO_SIZE         512
and

Code: Select all

 /* @brief   FIFO memory size in words. */
#define STM32_OTG_FIFO_MEM_SIZE         384

512+384*2=1280=1.25k

I also have to retract my statement from yesterday, I receive twice as many packets, but the sizes of the packets are 60bytes and 4 bytes alternating, so the bandwidth didn't increase... it was already pretty late. I'm looking into it now.

Re: example interfacing a STM32F4 with libusb

Posted: Thu Jul 12, 2012 12:56 pm
by Giovanni
STM32_OTG_FIFO_MEM_SIZE is the total RAM size in words (in ARM words are 4 bytes not 2).

The RX FIFO is shared and should already allow multiple packets, the problem is with TX FIFOs (one per endpoint), I think the bottleneck is with transmission only.

Giovanni