STM32Cube with FreeRTOS: Trace the HAL Time Base When Delays Stop Progressing
When a STM32Cube application starts its RTOS but a HAL delay or timeout stops progressing, inspect the HAL time-base path separately from the scheduler tick. A running task scheduler is not proof that the counter used by HAL services is advancing. Selecting another timer also does not complete the integration unless its initialization and interrupt path reach the intended tick update.
The implementation example here is STM32G4 HAL 1.2.7 at commit a6001282dfacfff57e9710250f15e4333b578865. The review is source-based; no firmware build or board test was executed. Other HAL families, overrides and Cube generations must be checked against their own code.

Identify which counter the stalled operation reads
The pinned STM32G4 HAL implementation implements its default delay as a loop around HAL_GetTick. The default getter returns uwTick, while HAL_IncTick advances it. These functions are weak so an application can supply another implementation.
Inspect what the final application actually links. A breakpoint in a source file that was not selected by the build is weak evidence. Locate the effective getter, tick initializer and update routine, including generated replacements. Then observe whether that counter changes before and after the scheduler starts, using a bounded diagnostic that does not depend on the stalled delay itself.
In a hypothetical failure, task scheduling continues but uwTick remains unchanged. That narrows the immediate investigation to the HAL counter and its producer. It does not establish that FreeRTOS is broken or that every hardware timer has stopped.
Separate timer ownership from interrupt delivery
ST's FreeRTOS middleware 2.2.0 integration guide describes reserving SysTick for the kernel and using another suitable timer for the HAL time base. Its configuration instructions target STM32CubeMX2; do not copy those menu locations into a different CubeMX generation.
For the actual project, trace the complete selected path: timer clock and configuration, update event, interrupt enable, vector entry, handler and HAL counter update. A generated timer initializer present on disk does not prove that it runs, and a working interrupt does not prove that its callback increments the intended counter.
Check that the selected resource has not also been assigned an incompatible application function. If the product uses that timer for another purpose, resolve the ownership decision rather than allowing two initialization paths to overwrite each other. Keep the HAL time units consistent with the services consuming the counter.
Inspect the context that is waiting
The same pinned HAL source warns that calling HAL_Delay from an interrupt can block when the tick interrupt cannot preempt it. For the documented case, the tick needs higher urgency, represented by a numerically lower NVIC priority value, than the waiting peripheral interrupt.
Do not respond by raising every interrupt priority. First remove avoidable blocking waits from interrupt context and defer work where the application design permits. Then check the remaining interrupt relationships and any RTOS API restrictions separately. Making a tick able to preempt a caller does not grant that caller permission to use arbitrary kernel services.
Also inspect explicit tick suspension and the selected overrides. The default suspend/resume implementations operate on SysTick; an alternate time-base implementation needs corresponding behavior. A product that intentionally pauses a time source must define which timeout-dependent operations remain permitted during that interval.
Validate both consumers under the intended operating modes
After repairing the path, observe the HAL counter and supported HAL timeout behavior before and after scheduler startup. Test an RTOS delay only from a valid task context after the scheduler is running. Check each consumer's expected time units separately. Then exercise the clock or power transitions the application actually uses, without assuming startup success covers them.
The acceptance result should name which resource drives each time base and show that both consumers progress in the supported contexts. This turns an apparently random delay hang into a traceable integration failure, while keeping untested low-power modes and board-specific timing claims out of the conclusion.