2026-02-09 2:48 AM - last edited on 2026-02-09 5:09 AM by mƎALLEm
Hello everyone,
I am facing a confusing behavior with USB SOF events on two identical STM32 boards and I would appreciate any insight.
2 × NUCLEO-H743ZI2
Same MCU revision (checked device ID, revision ID – identical)
Same USB connection to the same PC (USB OTG FS, device mode)
Exactly the same firmware binary programmed on both boards
STM32 HAL + CubeMX generated project
USB CDC device (USB OTG FS)
No conditional compilation, no board-specific code
I wanted to check:
Whether USB SOF events are really occurring every 1 ms
Whether SOF can be considered a reliable timing source
So I implemented a very simple counter in the SOF callback:
#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U)
static void PCD_SOFCallback(PCD_HandleTypeDef *hpcd)
#else
void HAL_PCD_SOFCallback(PCD_HandleTypeDef *hpcd)
#endif
{
sof_eventc++;
USBD_LL_SOF((USBD_HandleTypeDef*)hpcd->pData);
}
Additionally:
TIM2 is configured as a 1 Hz timer
In the TIM2 overflow interrupt, I read and print sof_eventc
Output is monitored via a serial terminal
Counter is reset every second
Since USB Full Speed SOF is 1 ms:
I expect ≈ 1000 SOF events per second
This is where it becomes strange:
Board #1:
~996 SOF events per second
(occasionally 995 or 997 – looks perfectly reasonable)
Board #2:
~1994 SOF events per second
(almost exactly 2×)
Both boards are running:
the same binary
same clock configuration
same USB host
same cable and port
On Board #2 only:
When I send data from the host (PC → device), i.e. any USB receive activity:
The SOF count drops to ~1930
The value becomes unstable / inconsistent
On Board #1, USB traffic does not affect the SOF count significantly.
How is it possible that two identical NUCLEO-H743ZI2 boards, running the exact same firmware, produce:
~1000 SOF callbacks on one board
~2000 SOF callbacks on the other?
Is HAL_PCD_SOFCallback() guaranteed to be called exactly once per USB frame, or can it be:
triggered multiple times per frame?
skipped or coalesced under USB traffic?
Can USB traffic (RX activity) legitimately reduce the number of SOF callbacks delivered to the application?
Is counting SOF callbacks a valid way to measure the USB 1 ms frame timing, or should another mechanism (e.g. DSTS.FNSOF) be used instead?
At this point I am unsure whether:
I am misunderstanding the SOF callback semantics, or
there is some subtle USB OTG / HAL / interrupt behavior that differs per board even with the same binary
Any ideas, explanations, or references would be greatly appreciated.
Thank you.
Solved! Go to Solution.
2026-02-09 4:29 AM
> How is it possible that two identical NUCLEO-H743ZI2 boards, running the exact same firmware, produce:...
Funny but there are two different MB used for NUCLEO-H743ZI: MB1137 with ST-Link v2.1 (described in UM1974) and MB1364 with ST-Link V3E (UM2407) and they differ in default HSE confuguration.
UM1974 for MB1137 says in "7.8.1 OSC clock supply":
MCO from ST-LINK (Default): MCO output of ST-LINK is used as input clock. This
frequency cannot be changed, it is fixed at 8 MHz and connected to the
PF0/PH0-OSC_IN of STM32 microcontroller.
While UM2407 for MB1364 differs a bit ("7.5.1 HSE clock (high speed external clock)"):
MCO from ST-LINK (Default): the MCO output of ST-LINK is used as an input clock. By
default, it is fixed at 8 MHz and connected to PF0/PH0-OSC_IN of the STM32H7 series
microcontroller. The frequency may be changed during ST-Link firmware upgrade (for
more details, refer to RN0093, available from www.st.com).
Since you have the newer version NUCLEO-743ZI2 with MB1364 HSE clock might be dependent on the ST-Link's update history?
4.14 Summary of changes in ST-LinkUpgrade.exe 2.5.4 and STLinkUpgrade.jar 3.3.4
...
On STLINK-V3E boards:
– Possibility added to choose the MCO clock output from ST-LINK to target among 3 values.
The default value (HSI / 2 = 8 MHz) can be changed through STLinkUpgrade applications to
HSE / 3 = 8.33 MHz (for better clock accuracy) or cut off. The operation is reversible. In case of a
switch to 8.33 MHz, the target application must be updated accordingly: a factor × (24 / 25) must be
applied in the PLL configuration in order to keep the clock tree unchanged behind (for instance, if
PLLN = 400, set PLLN = 384). Moreover the HSE_VALUE constant commonly defined into stm32xxx
_hal_conf.h must be changed to value 8333333.
...
4.6 Summary of changes in ST-LinkUpgrade.exe 3.14.5 and STLinkUpgrade.jar
3.14.5
...
On STLINK-V3 boards:
– Rework of MCO clock selection, with new possible choices (HSE/4 and HSE/5)
...
2026-02-09 3:05 AM
Did you check if they have the same crystal applied?
2026-02-09 4:29 AM
> How is it possible that two identical NUCLEO-H743ZI2 boards, running the exact same firmware, produce:...
Funny but there are two different MB used for NUCLEO-H743ZI: MB1137 with ST-Link v2.1 (described in UM1974) and MB1364 with ST-Link V3E (UM2407) and they differ in default HSE confuguration.
UM1974 for MB1137 says in "7.8.1 OSC clock supply":
MCO from ST-LINK (Default): MCO output of ST-LINK is used as input clock. This
frequency cannot be changed, it is fixed at 8 MHz and connected to the
PF0/PH0-OSC_IN of STM32 microcontroller.
While UM2407 for MB1364 differs a bit ("7.5.1 HSE clock (high speed external clock)"):
MCO from ST-LINK (Default): the MCO output of ST-LINK is used as an input clock. By
default, it is fixed at 8 MHz and connected to PF0/PH0-OSC_IN of the STM32H7 series
microcontroller. The frequency may be changed during ST-Link firmware upgrade (for
more details, refer to RN0093, available from www.st.com).
Since you have the newer version NUCLEO-743ZI2 with MB1364 HSE clock might be dependent on the ST-Link's update history?
4.14 Summary of changes in ST-LinkUpgrade.exe 2.5.4 and STLinkUpgrade.jar 3.3.4
...
On STLINK-V3E boards:
– Possibility added to choose the MCO clock output from ST-LINK to target among 3 values.
The default value (HSI / 2 = 8 MHz) can be changed through STLinkUpgrade applications to
HSE / 3 = 8.33 MHz (for better clock accuracy) or cut off. The operation is reversible. In case of a
switch to 8.33 MHz, the target application must be updated accordingly: a factor × (24 / 25) must be
applied in the PLL configuration in order to keep the clock tree unchanged behind (for instance, if
PLLN = 400, set PLLN = 384). Moreover the HSE_VALUE constant commonly defined into stm32xxx
_hal_conf.h must be changed to value 8333333.
...
4.6 Summary of changes in ST-LinkUpgrade.exe 3.14.5 and STLinkUpgrade.jar
3.14.5
...
On STLINK-V3 boards:
– Rework of MCO clock selection, with new possible choices (HSE/4 and HSE/5)
...
2026-02-09 6:12 AM
Thank you very much for this explanation — this was a detail I was completely unaware of, so I really appreciate you pointing it out.
I checked the ST-Link configuration on both boards and confirmed that they are both ST-Link V3 and configured to use HSI/2 = 8 MHz as the MCO output. Unfortunately, this did not change the observed behavior.
To further investigate, I also tested with a third NUCLEO-H743ZI2 board, and the situation became even more confusing. While the second board was at least relatively consistent (around ~1990 SOF events per second), the third board shows highly unstable behavior, with SOF counts fluctuating continuously between ~1000 and ~1900.
I will revisit the points you mentioned in more detail and try to analyze the clocking and USB timing behavior more carefully. If I manage to identify the root cause, I will update this thread with my findings.
Thanks again for taking the time to respond and for the very useful information.
2026-02-09 6:19 AM
In doubt it might be better to solder a crystal on the board and the set the solder bridges to use it instead of ST-Link supplied MCO?
2026-02-09 7:00 AM
Thanks for the clarification. To be honest, I was not fully confident about my clock configuration. I could not find a straightforward way to derive a clean and exact 48 MHz USB clock from the PLL with my current setup, so I chose to use RC48 instead. From a functional point of view, USB communication has been working without any visible issues.
However, after looking more carefully into the points you highlighted, I now believe that the main source of the observed behavior is very likely related to using RC48 as the USB clock source (jitter, clock domain separation, and interrupt latency effects), rather than a firmware or board defect.
Thanks again for pointing this out — it helped me better understand what I’m seeing.
2026-02-10 12:12 AM
Thanks for the clarification. To be honest, I was not fully confident about my clock configuration. I could not find a straightforward way to derive a clean and exact 48 MHz USB clock from the PLL with my current setup, so I chose to use RC48 instead. From a functional point of view, USB communication has been working without any visible issues.
However, after looking more carefully into the points you highlighted, I now believe that the main source of the observed behavior is very likely related to using RC48 as the USB clock source (jitter, clock domain separation, and interrupt latency effects), rather than a firmware or board defect.