Walk me through configuring the clock tree from an external crystal to 168 MHz on an STM32F4.
The clock tree configuration follows a specific sequence where order matters — getting it wrong causes hard faults or peripheral misconfiguration. Start with the system running on the default internal oscillator (HSI at 16 MHz). Step 1: Enable the HSE (High-Speed External oscillator) by setting the HSEON bit in RCC_CR. Wait for the HSERDY flag to set, confirming the external crystal (typically 8 MHz or 25 MHz) has stabilized. This takes a few milliseconds. If the crystal is not populated or damaged, HSERDY never sets — robust firmware includes a timeout here that falls back to HSI.
Step 2: Configure Flash wait states for the target frequency before switching to the faster clock. At 168 MHz and 3.3V supply, the STM32F4 requires 5 wait states (WS5) in the FLASH_ACR register. Also enable the prefetch buffer and instruction/data caches (ART Accelerator) to mitigate the wait-state penalty. Configuring wait states after switching the clock would cause the CPU to attempt fetching instructions faster than Flash can deliver them, resulting in corrupt instruction reads and an immediate hard fault.
Step 3: Configure the PLL. The PLL takes the HSE frequency and transforms it through three dividers: VCO_input = HSE / M, VCO_output = VCO_input * N, SYSCLK = VCO_output / P. For an 8 MHz crystal targeting 168 MHz: M = 8 (VCO input = 1 MHz), N = 336 (VCO output = 336 MHz, must be within the 100-432 MHz valid range), P = 2 (SYSCLK = 168 MHz). Also set Q = 7 for the USB OTG FS clock (VCO/Q = 48 MHz required by USB). Write all these to RCC_PLLCFGR, set the PLL source to HSE, then enable the PLL via PLLON in RCC_CR and wait for PLLRDY.
Step 4: Configure bus prescalers — AHB prescaler = 1 (HCLK = 168 MHz), APB1 prescaler = 4 (APB1 = 42 MHz, must not exceed 42 MHz), APB2 prescaler = 2 (APB2 = 84 MHz, must not exceed 84 MHz). Step 5: Switch SYSCLK to PLL by setting SW bits in RCC_CFGR to PLL, then verify SWS bits confirm the switch. The entire sequence takes microseconds of CPU time plus millisecond-scale oscillator stabilization. If any step is done out of order — especially configuring Flash wait states after the clock switch — the system will fault immediately and unpredictably.
Source: MCU Cores & Clocking Q&A
