2026-01-14 3:26 AM - last edited on 2026-01-15 2:05 AM by FBL
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.
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).
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.
2026-01-28 5:01 AM - edited 2026-01-28 5:44 AM
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.
I'm trying to figure out if I have this version where the DFU mass-erase is not working.
Thanks,
Strongato
2026-01-29 2:04 AM
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
2026-01-30 1:09 AM
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)
However, on STM32F446, here is trace and result when sending only 128B, our STM32H757 (as device) cannot read more than 128B
and when sending further packets (as you mentioned for instance 192B) They are all NAKed and we can see two issues to be investigated.
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.
2026-01-30 2:35 AM
2026-03-02 4:10 AM
2026-05-21 3:16 AM - edited 2026-05-21 4:56 AM
Hi @FBL
We acquired a usb analyzer, and the weird thing that I noticed was that the F446 as host, after being NAK'd, does not retry the same packet, while the G0 and PC do?
F446 Host: 128 byte transfer that works:
F446 Host: 192 byte transfer that fails:
As you can see, the packets that are NAK'd are not retried, they just loop.
While the G0 as host does retry the NAK'd packet:
I'm also sending the .usb files of the f446 transfers.
My assumption is that the FIFO buffer does not get flushed on every NAK, but it just sends what's already inside.
Kind regards,
Strongato
2026-05-21 8:14 AM
Thank you @Strongato for your patience.
I have escalated the ticket to our expert and will provide you an answer ASAP.
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.