What happens if you access a peripheral whose clock is disabled?
On STM32 (and most ARM Cortex-M MCUs), each peripheral is connected to the clock tree through individual clock gate bits in the RCC (Reset and Clock Control) registers. After a system reset, most peripheral clocks are disabled by default — the peripheral receives no clock signal, its registers do not function, and it consumes no dynamic power. If firmware attempts to read or write a peripheral's registers while its clock gate is disabled, the behavior is architecturally undefined on the AHB/APB bus and varies by implementation.
In practice on STM32, writes are silently ignored — the bus transaction completes without error, but the data is discarded because the peripheral's register logic is not clocked and cannot latch the value. Reads typically return zero (the bus returns a default value) or, on some families, may return stale data from the last time the peripheral was clocked. On some MCUs (particularly with stricter bus implementations), accessing an unclocked peripheral generates a bus fault (HardFault on Cortex-M0, or BusFault if enabled on M3+). The inconsistency across families makes this a particularly insidious bug — code that "works" on one MCU may fault on another.
This is one of the most common bugs in embedded development, especially for beginners. The typical symptom is: "I configured the peripheral registers but it does not work, and reading the registers back shows all zeros." The fix is always the same — enable the peripheral clock via the appropriate RCC enable register (RCC->AHB1ENR, RCC->APB1ENR, etc.) before any register access. A second subtle issue: the clock enable write and the first peripheral register access may execute back-to-back. On high-performance Cortex-M7 with write buffering, the clock enable may still be in the write buffer when the peripheral read executes, causing a read of the still-unclocked peripheral. The STM32 HAL inserts a read-back of the enable register after writing it (__IO uint32_t tmpreg = RCC->AHB1ENR; (void)tmpreg;) to force the write buffer to drain and ensure the clock is active before proceeding.
Source: MCU Cores & Clocking Q&A
