cancel
Showing results for 
Search instead for 
Did you mean: 

USB_WritePacket stuck in infinite loop

Strongato
Associate II

 

Hello ST Team,

I developed a custom USB DFU HOST class on an STM32F446ZE. I soldered a USB-C cable directly to the D+/D-, 5V and GND pins.

The Problem: The stack works correctly for transfers up to 128 bytes. However, when I set phost->Control.setup.b.wLength.w > 128 (e.g., 192 bytes) and call USBH_CtlReq, the code enters an infinite loop inside USB_WritePacket.

I have traced the execution line-by-line, monitoring the HCTSIZ register values: size (Transfer Size) and cnt (Packet Count).

Below is the detailed trace comparing a working 128-byte transfer vs. a failing 192-byte transfer.

1. Successful Scenario: Transferring 128 Bytes

Initial State: size = 128, cnt = 2.

Loop Iteration 1:

  • i=15: USBx_DFIFO written. Register updates: size = 64, cnt = 2.

  • i=31: USBx_DFIFO written. Register updates: size = 64, cnt = 1.

Loop Iteration 2:

  • Initial State: size = 128, cnt = 2.

  • i=15: USBx_DFIFO written. Register updates: size = 64, cnt = 1.

  • i=31: USBx_DFIFO written. Register updates: size = 64, cnt = 0.

  • Result: Transfer Complete (Success).


2. Failing Scenario: Transferring 192 Bytes

Initial State: size = 192, cnt = 3.

Loop Iteration 1:

  • i=15: USBx_DFIFO written. Register updates: size = 128, cnt = 3.

  • i=31: USBx_DFIFO written. Register updates: size = 64, cnt = 2.

  • i=47: USBx_DFIFO written. Register updates: size = 64, cnt = 1.

Loop Iteration 2 (Anomaly Begins):

  • Initial State: size = 128, cnt = 2

  • i=15: USBx_DFIFO written. Register updates: size = 128, cnt = 2.

  • i=31: USBx_DFIFO written. Register updates: size = 64, cnt = 1.

  • i=47: USBx_DFIFO written. Register updates: size = 64, cnt = 1.

    •  cnt value didn't change in last transfer?

Loop Iteration 3 (Corruption & Infinite Loop):

  • Transfer initialized with: size = 128, cnt = 3

    •  cnt value set to 3 again?

  • i=15: USBx_DFIFO written. Register updates: size = 128, cnt = 3.

  • i=31: USBx_DFIFO written. Register updates: size = 64, cnt = 3.

    • cnt value is now stuck at 3.

  • i=47: USBx_DFIFO written. Register updates: size = 64, cnt = 3.


Comparison with STM32G0: I ported this exact USB DFU Host class to an STM32G0C1CEU6, and the transfers work perfectly there with no issues. My application code remained identical. The only major difference is the hardware architecture (F4 uses FIFO vs G0 uses PMA) and the low-level drivers.

This is my first post so if I missed something or any additional data is needed, I'm happy to provide it.

 

13 REPLIES 13
FBL
ST Employee

Hi @Strongato 

Do you reproduce using our reference boards ?

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.




Best regards,
FBL

Hi @FBL 

Yes, I can consistently reproduce the issue on the NUCLEO-F446ZE reference board.

For comparison, this exact same application logic works perfectly on an STM32G0 (custom board).

 

Kind regards,

Strongato

FBL
ST Employee

Thank you for your feedback @Strongato  Would you share minimum firmware to reproduce on my end?

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.




Best regards,
FBL

Hi @FBL 

 

Yes I can, could you share your personal e-mail or a way I could send it to you since this is proprietary software?

 

Best regards,

Strongato

Hi @Strongato 

Thank you for your feedback.

Can you share it directly to this ID privately over GitHub. Since requesting file transfers via email can take some time and not recommended, using GitHub would help speed up the process. 

Otherwise, you can share just the project via private message in the ST Community inbox.

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.




Best regards,
FBL
FBL
ST Employee

Hi @Strongato 

Would you provide working project over STM32G0? Can you provide more details about your device. 

Unfortunately, we don't have an example DFU host. 

I couldn't reproduce the issue you mention, it doesn't get stuck in USB_WritePacket as you mention. On my end, I used an H7 as device, and here is the trace using 128B for DFU_UPLOAD.

FBL_0-1769098580973.png

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.




Best regards,
FBL

Hi FBL,

Thank you so much for your reply!

I've put the G0 project onto the github page as well, but as you will see, the USB DFU HOST class is identical.
I just created a new project, configured USB HOST and added my class.

I'm unsure why you sent a DFU_UPLOAD request, I don't even have that implemented in my USB DFU HOST code?

The infinite loop happens when we are sending a DFU_DNLOAD with wLength > 128,
but from your screenshot I see you sent 1 byte. Could you try sending 192 or higher if you're using my code?
Could you provide more information how you are testing this, so I could get a better understanding how I could help?
Are you using the Teledyne LeCroy to send DFU packets or you wrote your own USB DFU HOST example code?

I do not have access to a USB protocol analyzer, so I cannot provide a screenshot.
We only own a SALEAE logic analyzer, but I'm not sure how helpful the output of that would be.

DNLOAD request with wLength:
[0, 128] - works
<128, 384] - infinite loop between CTRL_DATA_OUT and CTRL_DATA_OUT_WAIT
<384, inf> - stuck at CTRL_DATA_OUT

It gets stuck after 384, because the value of tx fifo size is 384
(I did not change this, so it's probably default).
USB_OTG_GlobalTypeDef *USBx = USB_OTG_FS;
const uint32_t tx_words = (USBx->DIEPTXF0_HNPTXFSIZ >> 16) & 0xFFFF; // 96 words

This limitation is not present on stm32G0 since it does not use the FIFO buffer.

The devices that I have tested on the stm32F446 are:
stm32F405RGT6 - 128 bytes works
stm32H743VIH6 - 128 bytes works

The devices that I have tested on the stm32G0 are:
stm32F405RGT6 - 2048 bytes works (max transfer size), and DFU_IO_BUFF_SIZE = 2048 in my class code
stm32H743VIH6 - 1024 bytes works (max transfer size), and DFU_IO_BUFF_SIZE = 1024 in my class code

The way I have tested these is I hold down the boot button, and the devices go into bootloader mode,
like that I plug them into my F446/G0 which has the USB DFU HOST class.

From the screenshot provided you can see that the memory of the stm32F405 is filled at
0x08000000 and then again on 0x08000800, which is 2048 bytes per block.

For stm32h7 device the memory is filled at 0x08000000 and then again on 0x08000400,
which is 1024 per block.

Kind regards,
Strongato

FBL
ST Employee

Hi @Strongato 

I found you are using HSI to clock your system. Note that HSE is mandatory for USB Host applications.

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.




Best regards,
FBL

 

Hi @FBL ,

Yes, thank you for pointing it out!

I'm currently in the process of talking with the hardware team to add an external crystal to our custom board,
since I have been getting inconsistent results when using the dfu host on stm32g0
(sometimes the flash works, sometimes it gets stuck in an infinite loop).
When adding freeRTOS the code also becomes more unstable.

But like I said, I get inconsistent results on the stm32g0, but on the stm32f446 it is always stuck in infinite loop above 128 bytes.
Later I could try to add an external crystal to the stm32f446 as well to see if that could be the issue.

It fails more often on the stm32h743 as device than the stm32f405 as device, which I found to be interesting,
It could be because of different sector sizes or bootloader version.
I can't be sure since when I use CubeProgrammer the bootloader version and revision show up as --, and I don't have access to the code.

When selecting the external crystal for our stm32g0c1, I was first thinking of buying the NUCLEO stm32g0b1,
the b1 version (since the c1 does not exist), and trying it with your reference boards first.
Since the development and ordering of new hardware could take a while.

I can use any external crystal with a frequency between 8mhz and 25mhz, but the lower the better?

Thank you so much,
Strongato