cancel
Showing results for 
Search instead for 
Did you mean: 

We have random data loss on USB transmit. Any hints?

davidpilcher9
Associate III
Posted on March 14, 2018 at 14:30

Hi

We have an STM32L4x5 project. We are using

STM32CubeMX

to generate our HAL based framework and have a bunch of hardware all working great. We were noticing application level CRC errors on receipt of data being receiving via a CDC USB connection and this has caused me to create a simple test case which shows it. We are probably doing something wrong here, but would love some insight into this.

char output[90] = ''0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567\r\n'';

int index = 0;

uint8_t * out = (uint8_t*)&output;

while (1)

{

USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*)hUsbDeviceFS.pClassData;

while (hcdc->TxState != 0){

// wait for usb tx done

}

if (CDC_Transmit_FS(out+index, 10)== USBD_OK)

{

index += 10;

}

if (index >= sizeof(output))

{

index = 0;

DelayMilliseconds(50);

}

WatchdogReset();

}

This is a complete 10 second hack of a test case which we put in main.c, but generates the same issue, which is on the PC we receive data like this:

0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567

0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567

0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567

0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567

0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567

0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567

0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567

0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567

0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567

0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567

01234567890123456789012301234567890123456789012345678901234567890123456789012345678901234567

0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567

0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567

0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567

0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567

01234567890123456789012345678901234567890123456789012301234567890123456789012345678901234567

0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567

0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567

0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567

0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567

Here, we see an occasional duplicate DWORD. If we output a single byte at a time rather than 10, the issue occurs mode frequently.

0690X0000060A5RQAU.png

If I add some debug output in the USB library where the data is being put onto the USB FIFO from our buffer pointers I see it being written correctly into the EP FIFO registers in order ok, but different data is being received.

Any hints as to what we're doing wrong here?

Oh yes, our functions for sending are:

static int8_t CDC_Init_FS(void)

{

/* USER CODE BEGIN 3 */

/* Set Application Buffers */

USBD_CDC_SetTxBuffer(&hUsbDeviceFS, UserTxBufferFS, 0);

USBD_CDC_SetRxBuffer(&hUsbDeviceFS, UserRxBufferFS);

FIFO_Init(&usbRxFifo, usbRxBuffer, USB_RX_BUFF_SIZE);

FIFO_Init(&usbTxFifo, usbTxBuffer, USB_TX_BUFF_SIZE);

usbLastTxLen = 0;

UplinkDecoderInit(&usbRxState);

state = 0;

return (USBD_OK);

/* USER CODE END 3 */

}

uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len)

{

uint8_t result = USBD_OK;

/* USER CODE BEGIN 7 */

USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*)hUsbDeviceFS.pClassData;

if (hcdc->TxState != 0){

return USBD_BUSY;

}

USBD_CDC_SetTxBuffer(&hUsbDeviceFS, Buf, Len);

result = USBD_CDC_TransmitPacket(&hUsbDeviceFS);

/* USER CODE END 7 */

return result;

}

Thanks, Dave

Note: this post was migrated and contained many threaded conversations, some content may be missing.
11 REPLIES 11
Ben K
Senior III
Posted on March 14, 2018 at 17:02

This looks very much like a Tx FIFO issue, but I can imagine multiple points of failure. The filling of the FIFO might be incorrectly optimized by the compiler, which may produce bad behavior when preempted during execution. To root out this possibility, try the followings:

1. It seems that there is an OS running in this test. Check how it behaves on its own without the OS (no preemption or scheduling).

2. What compiler are you using? Try to build and run the test with no compiler optimizations.

Additionally you may try flushing the TxFIFO between transmissions.

The other possibility is clearly theoretical: the device starts transferring the USB packet when the FIFO isn't filled yet, and so the old FIFO content is loaded for the first bytes. This may only happen when the USB interrupt isn't serviced with a low latency. Testing it is more complicated than the others, the filling of the FIFO should be moved to the HAL_PCD_EP_Transmit() - just like in the case of isochronous transfers - from the HAL_PCD_IRQHandler().

Posted on March 14, 2018 at 17:25

Hi Ben,

Thanks for the reply. There is no OS here - this basic test was running in main.c immediately after all the hardware Init calls (and a 10s delay for USB to come up).  As raw as it gets (well I guess we could remove other STM32 Cube blocks and just init the USB.)

It's using GCC in OpenSTM32.org.  This is -Og, so no performance optimization.

We're not using dma... so this is interrupt driven and I see the write values output.

We captured the raw USB packets PC side and they are wrong there so it's definitely STM side.

Will look into seeing if we can flush the hardware fifos.

Thanks,

Dave

Posted on March 15, 2018 at 00:16

In that case I suggest you change the USB_EPStartXfer() function the following way:

HAL_StatusTypeDef USB_EPStartXfer(USB_OTG_GlobalTypeDef *USBx , USB_OTG_EPTypeDef *ep, uint8_t dma)

{

...

    // if (ep->type == EP_TYPE_ISOC) // <- Comment out this line to fill FIFO at the time of call

    {

      USB_WritePacket(USBx, ep->xfer_buff, ep->num, ep->xfer_len, dma);   

    }   

...

}

If this doesn't produce any difference then I'm officially out of ideas.

Posted on March 15, 2018 at 00:17

What is the system (AHB) frequency, and what is the value of OTG_GUSBCFG.TRDT?

JW

Posted on March 15, 2018 at 00:22

AHB is 32Mhz, above the 4 or similar in the datasheet.

Posted on March 15, 2018 at 00:28

And answer to the second part of my question?

JW

Posted on March 15, 2018 at 00:44

Forcing USB_WritePacket immediately appears to cause the state machine to get into a state where it never clears hcdc->TxState.  It is stuck as 1 after a couple of characters.

Posted on March 15, 2018 at 00:48

0x3C00

Posted on March 15, 2018 at 00:54

0x3C00

OTG_GUSBCFG.TRDT is a 4-bit field.

Is this value of whole OTG_GUSBCFG, ie. TRDT=0xF?

If so, then it's hummm as it would mean the configured frequency is between 14.2MHz and 15MHz; but it should work nevertheless.

JW