cancel
Showing results for 
Search instead for 
Did you mean: 

USB transfer multiple of packet size

shippo
Associate II
Posted on June 14, 2014 at 15:30

I don't know whether this is related to the STM32CubeF4 package or the STM32F407 so I'll post here.

I'm using the STM32F4 discovery board and the onboard USB FS port.

I wrote a VCP interface that lets me send a buffer of any length (basically just expanded the CDC example), but when I try to send a buffer with a length which is a multiple of the FS max packet size (64 bytes) the data is not transferred immediately but only on the next call to USBD_LL_Transmit (which in turn calls HAL_PCD_EP_Transmit).

I tested this with 64 and 128 byte buffers.

Am I doing something wrong here, is this a known bug or a new bug?

And is it more likely related to the STM32CubeF4 or the chip itself?

What I already did is look through the HAL firmware code but as far as I can see there's no rounding errors or similar that would cause such an issue...
17 REPLIES 17
lfrodrigues
Associate
Posted on July 28, 2014 at 20:31

Hi Peter,

I've also been struggling trying to make the vcp work. Would you be able to share your code?

Best,

Luis

shippo
Associate II
Posted on July 28, 2014 at 23:24

As I said I pretty much use the template and piece together a command line from received characters, but that's rather application specific.

What kind of problems do you have?

Posted on October 15, 2014 at 11:58

Hi Peter,

How do you handle USB transfer, are you using USBD_CDC_SetTxBuffer() and USBD_CDC_TransmitPacket()? I've tested your use case with two different buffers 64 and 128 bytes and it is working for me, as it follows:

USBD_CDC_SetTxBuffer(&USBD_Device, (uint8_t*)StatUserTxBuffer, sizeof(StatUserTxBuffer));
if(USBD_CDC_TransmitPacket(&USBD_Device) == USBD_OK)
{
}

Regards, Heisenberg.
shippo
Associate II
Posted on May 30, 2015 at 18:34

Heisenberg, sorry for not getting back to you.

I don't know if this is still an issue with the newest HAL version, I have not updated yet (the project is on pause, that's why I've not been here).

Anyway, I'll answer this now:

Yes I'm using

SetTxBuffer()

and

TransmitPacket()

, however I didn't test it with FS USB, only HS USB where the maximum packet size is 512 bytes.

Also, I can't remember exactly, but from what I recall this was only a problem on Windows (I could be wrong though, it's been some time).

taraben
Senior
Posted on June 01, 2015 at 23:49

Hello Peter,

yes this is still a problem. I run into the same issue.

I dont have the problems on Linux host. I thought it is related to the VCP driver on windows.

Adib.

rc
Associate II
Posted on June 19, 2015 at 18:46

The crux of the problem - if you trace it down to hardware - is that DMA is used to send the data. The high level routine ''USBD_CDC_TransmitPacket'' just ultimately sets up the DMA but after it does, it returns ok. If you go ahead and reuse your buffer after that hight level ok, then potentially the DMA will send what you put next into your buffer. So when you do a one of, it all works. But in a real system those buffers are moving around and getting used for other things. So using a buffer which is not really free is where the problem lies.

For instance if I make a call to USBD_CDC_TransmitPacket and I don't use that buffer for anything else until I see the data pop out the other end of the USB connection, then all is well. However if I zero that buffer right after the call, even tho I received a ''HAL is ok'' reply, then when the DMA gets to sending the buffer, it won't be what I wanted.

The function USBD_CDC_DataIn seems to be called after the data has been sent, so using it as a call back makes sense. Unfortunately it has no user code space in it. It is not called directly either so finding the call chain is difficult. One could either drop a user piece of code into that call or perhaps replace it in the class callbacks data structure. Both options are not nice. With some of the other drivers, there is a weak callback function which can be replaced or there are user code areas that are respected by the code generator. This seems to be lacking.

The callback to USBD_CDC_DataIn seems to just set the TxState to 0. So one could in theory poll that state by calling USBD_CDC_TransmitPacket with a zero length packet until it said ok but unfortunately that will set the state to non zero.  Or perhaps one could keep the old buffer until the new one is accepted. Many ways of ugly.

I should point out that there is a weak callback but that is used by the CDC code. There is no link back to user code to let the use know when to reuse the buffer. The chain starts from: HAL_PCD_IRQHandler

which calls: HAL_PCD_DataInStageCallback (this is the weak call back but gets defined in CDC code) 

which calls:  USBD_LL_DataInStage

which finally calls: USBD_CDC_DataIn and this is where it all ends.

The user code is unaware of that chain of events.

rc
Associate II
Posted on June 19, 2015 at 21:35

Well as it turns out life is even stranger than we can imagine. I thought I had my problem solved by tying into USBD_CDC_DataIn but that didn't help. It turns out that my buffer pool was the problem. I have a pool of buffers allocated at compile time and then divvied up at run time according to a calculated length. This results in buffers not starting on 4 byte address boundary. Even tho the buffers contain bytes, something - probably DMA - doesn't like to start on a non-aligned boundary. I found this out by printing the buffer addresses as they were being used and noticed that for the ok frames sent, it was on aligned buffer boundaries.  So be warned, if you pass a non-aligned address to USBD_CDC_SetTxBuffer, you might not send what is in the buffer. There rightfully should be a note in the code about this or it should just accept it and work with it.