STM32 SystemClock Modified When Debugging with OpenOCD
/ 4 min read
Updated:Table of Contents
Phenomenon
The issue was reproduced on an STM32F4 target. Register addresses, maximum clock rates, and OpenOCD reset scripts vary across STM32 families, so the exact behavior should not be generalized to every STM32 device.
After enabling the PLL in STM32CubeMX, execution appeared to become stuck in SystemClock_Config() regardless of the configured SYSCLK or HCLK frequency.

More specifically, HAL_RCC_OscConfig() failed while validating the existing RCC and PLL configuration:
//Line 149 in main.cif (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK){ Error_Handler();}
//Line 550 in stm32f4xx_hal_rcc.cif (((RCC_OscInitStruct->PLL.PLLState) == RCC_PLL_OFF) || (READ_BIT(pll_config, RCC_PLLCFGR_PLLSRC) != RCC_OscInitStruct->PLL.PLLSource) || (READ_BIT(pll_config, RCC_PLLCFGR_PLLM) != (RCC_OscInitStruct->PLL.PLLM) << RCC_PLLCFGR_PLLM_Pos) || (READ_BIT(pll_config, RCC_PLLCFGR_PLLN) != (RCC_OscInitStruct->PLL.PLLN) << RCC_PLLCFGR_PLLN_Pos) || (READ_BIT(pll_config, RCC_PLLCFGR_PLLP) != (((RCC_OscInitStruct->PLL.PLLP >> 1U) - 1U)) << RCC_PLLCFGR_PLLP_Pos) || (READ_BIT(pll_config, RCC_PLLCFGR_PLLQ) != (RCC_OscInitStruct->PLL.PLLQ << RCC_PLLCFGR_PLLQ_Pos)))Initial hypotheses
The configured system clock is too high
The maximum clock depends on the exact STM32F4 part number. On this board, reducing the configured clock did not fix the problem:
- Decreasing the clock to 72 MHz did not help, which ruled out a simple overclocking error.
- If the system clock came directly from HSI or HSE, the problem disappeared. - The system ran correctly in this configuration, but the clock was too slow for the application. - Reproducing the PLL problem with HSI as its source ruled out an HSE oscillator or layout problem.
- If the PLL is participated, no matter how low the clock speed is, or whether the clock source comes from HSI or HSE, the problem is always encountered
After that, I tried to use the examples provided by manufacturer, which is also weird:
- The source code of RCC/PLL is pretty much similar to generated before, while none of them could work
- The binary program provided could work perfectly! Which excludes the problems from hardware.
After some tries, the problem is narrowed down to the RCC/PLL configuration
STM32CubeMX or HAL bug
Though I have generated code thousands times directly from CubeMX and it ran perfectly before on STM32F103, it could be possible a vital bug made by ST official. And it could be true. Some reported a bug of mis-configuring a register in HAL few years ago and ST promised to solve the problem by updating a firmware pack. https://community.st.com/t5/stm32-mcus-embedded-software/bugs-encountered-in-f4-rcc-hal-code-are-there-any-workarounds/td-p/209967 The installed firmware package already contained the reported fix, and testing the previous package did not solve the problem.
Debugger behavior
The firmware worked when flashed and started without a debug session. This narrowed the difference to the ST-Link/OpenOCD reset sequence rather than the generated application code.
Reasons
I was inspired by https://www.eevblog.com/forum/microcontrollers/stm32-clock-gets-modified-when-debugger-is-connected/
The OpenOCD target script modifies registers during reset init.
OpenOCD provides several reset commands:
In the OpenOCD version used for this test, reset init ran the following handler from stm32f4x.cfg:
$_TARGETNAME configure -event reset-init { # Configure PLL to boost clock to HSI x 4 (64 MHz) mww 0x40023804 0x08012008 ;# RCC_PLLCFGR 16 Mhz /8 (M) * 128 (N) /4(P) mww 0x40023C00 0x00000102 ;# FLASH_ACR = PRFTBE | 2(Latency) mmw 0x40023800 0x01000000 0 ;# RCC_CR |= PLLON sleep 10 ;# Wait for PLL to lock mmw 0x40023808 0x00001000 0 ;# RCC_CFGR |= RCC_CFGR_PPRE1_DIV2 mmw 0x40023808 0x00000002 0 ;# RCC_CFGR |= RCC_CFGR_SW_PLL
# Boost JTAG frequency adapter speed 8000}The handler configures the PLL for 64 MHz and increases the adapter speed. Those RCC values remain when the application begins its own clock setup, so the HAL observes a PLL configuration different from the one generated by STM32CubeMX.

Solution
- For this configuration, use
reset haltinstead ofreset initso that the target script does not rewrite the PLL registers. Some boards rely on otherreset-initactions, so check the target script before applying this workaround elsewhere. The operation is pretty simple, change the option in CLion from:
to:

Besides
Inspecting peripheral registers through an SVD file in CLion made it much easier to compare RCC state with the reference manual. The TinyGo STM32 SVD repository contains a useful STM32F407 definition; use the file matching the exact target MCU.