cancel
Showing results for 
Search instead for 
Did you mean: 

USB FS Losing word in RxFIFO (STM42F40x)

hpipon957
Associate III
Posted on March 03, 2012 at 06:09

Hi All

I thought that I had managed to tame the USB FS device, but I was wrong. There is one simple thing that is not working and it is so simple that it seems impossible to solve...

I have a CDC class operating. Enumeration is OK and IN and OUT data exchanges work on the bulk endpoints. This links a UART to a virtual COM port (classic use of CDC) but I noticed that the UART baud date was not getting set correctly - this is set when the terminal emulator connects to the virtual COM port or when its settings are changed.

This is a simple SETUP (set line coding [0x20]) on endpoint 0 followed by a DATA packet with 7 bytes of data containing the settings.

After a few minutes of debugging it became obvious that the received data packet was incorrect. It was also quite clear that only 3 of the 7 expected bytes were in the input buffer. Seemed like something small but after several hours of low level debugging it has turned out to be something so small that it is invisible...

Any help on the following finding?

1) The first thing that happens is that the standard SETUP packet is received (popping the RxFIFO status gives the expected [OTG_FS_GRXSTSP = 0x014c0080] type status (SETUP with 8 bytes)).

2) The 8 bytes are extracted from the FIFO as normal and it is seen that it is a Set Line Coding with extra data so nothing more is done at the moment - the interrupt is quit.

3) Then something unexpected happens. The following interrupt signals the next another RxFIFO event but its FIFO status is invalid - [OTG_FS_GRXSTSP = 0x02000680] (this would be 0x68 bytes received and an invalid bit set and also an invalid reason). This is ignored (if the FIFO status is not popped the interrupt is not cleared though). [I did try to see whether there was some data to be read from the RxFIFO when it arrived but there wasn't - it just returned some pattern similar to reading when no data is waiting].

4) After this, the expected receive FIFO interrupt arrives showing an OUT reception with 7 bytes - [OTG_FS_GRXSTSP = 0x01450070]. So the RxFIFO is read out but the first word read returns the last 3 bytes of the expected 7 (the first 4 are not there) and the second word read returns something that has nothing to do with received data.

In fact a SETUP frame followed by a DATA frame is quite rare. USB-MSD, USB-HID projects don't encounter it on endpoint 0. It is only the USB-CDC Set Line Coding and (presumably) Set Control Line State (for controlling RTS/DTR) that are affected.

Endpoint 0 has been setup with large FIFO size (64 words) and also configured for reception of 3 back-to-back SETUPS. The SETUP reception causes just extraction of the SETUP data and no other register accesses that could go wrong. The behavior is consistent and I haven't been able to change it by whatever tricks I have been able to think up just yet.

Is there maybe some (bad) configuration setting that could cause this behaviour or could it be a problem with the USB controller? Is there an example of working USB-CDC supporting the line settings??

Regards

Mark

#usb-cdc #utasker #stm32f4-usb-rxfifo-[solved] #usb-otg-fifo-extra-bytes-trdt
10 REPLIES 10
aseemann9
Associate
Posted on March 07, 2012 at 08:32

Hi,

there is a notice in libopenstm32:

/* Save packet size for stm32f107_ep_read_packet() */ rxbcnt = (rxstsp & OTG_FS_GRXSTSP_BCNT_MASK) >> 4; /* FIXME: Why is a delay needed here? * This appears to fix a problem where the first 4 bytes * of the DATA OUT stage of a control transaction are lost. */ for(i = 0; i < 1000; i++) asm(''nop'');

It is for f107 but i think  f4xx otg_fs is the same. Maybe that is the solution!

regards

armin

hpipon957
Associate III
Posted on March 07, 2012 at 13:29

Hi Armin

Many thanks for this information!

Unfortunately the USB controller in the STM32F4 is very different to the one in the STM32F1xx. I tried adding a delay at this location and it didn't change anything - probably I would have seen that a delay was necessary when stepping the code in this particular case but that was also not the case.

However it is inspiration in that the F1 USB controller seems to do something strange in this same situation and perhaps the F4 one inherited some peculiarity from it. I wonder whether the people for the libopencm3 project may know something if they are also working with the F4 (?)

Regards

Mark

hpipon957
Associate III
Posted on March 07, 2012 at 13:51

Hi

Oooops. I made a mistake in that I was comparing the USB device on the STM32F107 and not the USB FS OTG module, which does look to be essentially the same.

If they got it working it must at least be possible..;-) Will take a closer look or contact someone from the team.

Regards

Mark

aseemann9
Associate
Posted on March 09, 2012 at 07:22

hi Mark,

can you share information about your implementation of usb device on f4xx? I have to do it

in the near future also. That's why i have read the sources of libopenstm32. Or send me a

pm?

regards

armin

hpipon957
Associate III
Posted on March 09, 2012 at 13:20

Hi

The STM32Fxxx project is at

http://www.utasker.com/forum/index.php?topic=1697.0

The newest version is at the bottom (V1.4.1 at date of writing) containg CDC, MSD and HID classes, but still with the difficulty with setting the UART speed via virtual COM connection due to the problem discussed...

Regards

Mark

lkolaszewski9111
Associate
Posted on October 05, 2012 at 01:33

Hi Mark. Was wondering if you ever solved this one? In fact, we are using libopencm, and their code is also broken. A large delay fixes theirs, but ruins throughput and is not acceptable. Any help would be greatly appreciated.

Thanks so much Mark.

hpipon957
Associate III
Posted on October 06, 2012 at 08:36

Hi Jason

I have no solution yet but have verified that the ST-Micro OTG-FS-CDC demo: www.st.com/internet/com/SOFTWARE_RESOURCES/SW_COMPONENT/FIRMWARE/stm32_f105-07_f2_f4_usb-host-device_lib.zip does work correctly. This confirms that it is 'possible' to get it to work.

There are no delays in that code so I think that the workaround in the libopencm3 driver may have worked in a particular instance but is may not always be a reliable workaround (it didn't help in my code).

The configuration of the USB-OTG-FS device is varied - I checked the way that the ST code is handling the SETUP with following OUT in comparison to the code that I have and it is allowing 2 SETUP packets to be queued whereas I am allowing 3. It sets 64 byte limits whereas I have 3 x 8. Also the OTG_FS_DOEPTSIZ0 and OTG_FS_DOEPCTL0 are written in the ST example every time when the SETUP token has been received whereas I set up it once and leave it (although I think that I tried re-writing the registers when I was throwing some possibilities at it during the original work, but maybe after each OUT reception rather than between the SETUP and the OUT (?)).

Since the ST Micro driver code is indeed working correctly (it doesn't lose a long word from the rx FIFO in the case of Control Endpoint SETUPs with data as does some other code - sometimes with what may be a ''lucky'' but questionably reliable workaround in one case) I have concluded that there is a configuration or sequence of register accesses that must exactly match a particular requirement of the chip's implementation. This may be a bug in the chip or a quirk, depending on how it is looked out - maybe with some logical sense to the designer but maybe also not. The solution proably lies in finding the exact sequence necessary - either by trial and error of a number of possible configurations and register access sequences, but probably more efficiently by coping the exact configuration used by the ST example and also copy the register accesses during the SETUP/OUT interrupt sequence (note that this USB device is very interrupt intense in comparison to most others, requiring handling about 5 interrupts just to receive a SETUP token) - getting this identical must allow the data to be extracted without the reproducable long word loss that has been experienced by a number of driver writers; whether it makes sense or not, I think that this is where the answer lies and then make sure that it is never changed again....

Regards

Mark

petter23
Associate II
Posted on February 07, 2013 at 18:16

I have had a similar problem and I write this so you may try and see if

it maybe solves your issue as well.

In my case data sent to host contains 4 bytes extra data. The former

sent packet first 4 bytes is inserted into the beginning of the

packet. This only happened when we ran at 30 MHz. The problem was not

seen at or above 36 MHz. It was also impossible to even get enumerated

when running below 30 MHz.

The problem has just now found a solution. Have a look at the GUSBCFG

TRDT, ''USB turnaround time'' setting. The driver has hardcoded values

that does not consider the AHB speed as it should, look for

gusbcfg.b.usbtrdtim in usb_dcd_int.c Also the formula in the reference

manual is a bit cryptic to say the least. The ''AHB clock'' and ''PHY clock''

should not be frequency but time. Hence a more accurate formula would be

        TRDT = 4 × [ PHY / AHB + 0.5] + 1

The calculated value is a ''minimum required'' value. You can/should pick

a larger value depending on your application (if it changes speed).

ST will probably replace the formula altogether from the reference manual

and replace it with a table instead.

hpipon957
Associate III
Posted on June 09, 2013 at 15:15

Hi Petter

Many thanks for your message, which I only just saw.

My value was taken from an example setup which was obviously not using the correct value for the turnaround time (the field was set to 0x05 whereby the processor is running at 168 MHz.

I now use

    #define OTG_FS_GUSBCFG_TRDT_VALUE  (1 + (4 * (HCLK + (48000000/2)/48000000)))

    #if OTG_FS_GUSBCFG_TRDT_VALUE > OTG_FS_GUSBCFG_TRDT_MAX

        #define OTG_FS_GUSBCFG_TRDT_SETTING  OTG_FS_GUSBCFG_TRDT_MASK    // set the maximum value

    #else

        #define OTG_FS_GUSBCFG_TRDT_SETTING (OTG_FS_GUSBCFG_TRDT_VALUE << OTG_FS_GUSBCFG_TRDT_SHIFT)

    #endif

    OTG_FS_GUSBCFG = (OTG_FS_GUSBCFG_TRDT_SETTING | OTG_FS_GUSBCFG_PHYSEL | OTG_FS_GUSBCFG_FDMOD); // force device mode - this takes 25ms to become effective and pulls the D+ line high with pull-up

which sets it to its maximum value of 0xf.

Unfortunately there is however no change in behaviour and the first long word read from the FIFO in this (single) case is still getting lost.

Regards

Mark