Skip to main content
Associate II
January 14, 2026
Question

USB_WritePacket stuck in infinite loop

  • January 14, 2026
  • 6 replies
  • 633 views

 

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.

 

6 replies

Technical Moderator
January 15, 2026

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
StrongatoAuthor
Associate II
January 15, 2026

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

Technical Moderator
January 15, 2026

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
StrongatoAuthor
Associate II
January 15, 2026

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

Technical Moderator
January 16, 2026

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
Technical Moderator
January 22, 2026

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
StrongatoAuthor
Associate II
January 26, 2026

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

Technical Moderator
January 28, 2026

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
StrongatoAuthor
Associate II
January 28, 2026

 

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

StrongatoAuthor
Associate II
January 28, 2026

Hi @FBL ,

Is there a way to check the bootloader version on the stm32h743 without direct access to the code and if the CubeProgrammer says -- instead of bootloader version and revision number?

EDIT: on my chip it says stm32h743vih6 78 a4a v0 v phl 78 135

 

The code gets into an infinite loop after sending mass-erase, but sometimes it passes.

Strongato_1-1769604509433.png

I'm trying to figure out if I have this version where the DFU mass-erase is not working.

Thanks,
Strongato

StrongatoAuthor
Associate II
January 29, 2026

Hi @FBL ,

I posted the example of me using the HSE bypass clock (f446_example.zip), but the infinite loop remains.

This should be good enough for a stable USB connection, I don't need an external crystal, if I use the bypass clock?

 

I also realised that when I use the f446 as host instead of g0, the h7 device does mass erase fine, so it's probably a stability issue on my g0, not the ST bootloader.

Thanks,
Strongato

Technical Moderator
January 30, 2026

Hi @Strongato 

I have reproduced the issue on my end and I forwarded it to development team for further investigation.
It could be linked to your custom DFU host stack (class framework / state machine) or our HAL/LL driver. When using our G0 as host, it is working as expected (even though we know it's a different controller and different mechanisms)

FBL_0-1769763436360.png

FBL_2-1769763739666.png

 

However, on STM32F446, here is trace and result when sending only 128B, our STM32H757 (as device) cannot read more than  128BFBL_1-1769763698303.png

and when sending further packets (as you mentioned for instance 192B) They are all NAKed and we can see two issues to be investigated.

FBL_3-1769763788700.png

An internal ticket is submitted to dedicated team to help on this issue. (226226 Once I get updates from our development team , I will get back to you ASAP)

Thank you for your feedback

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
StrongatoAuthor
Associate II
January 30, 2026

Hi @FBL ,

thank you so much for your reply!

I look forward to hearing back.

 

Kind regards,

Strongato