Skip to content

KAKUTEH7WING: PLL2 VCO out of spec with 16 MHz HSE — SDMMC kernel clock at 400 MHz #11594

@daijoubu

Description

@daijoubu

Bug Description

On the KAKUTEH7WING target (and any other H7 target with HSE_MHZ 16), the PLL2 VCO exceeds the STM32H7 PLL specification.

Root Cause

PLL2 dividers are hardcoded in src/main/target/system_stm32h7xx.c (lines 500-512):

RCC_PeriphClkInit.PLL2.PLL2M = 5;
RCC_PeriphClkInit.PLL2.PLL2N = 500;
RCC_PeriphClkInit.PLL2.PLL2R = 4; // 200MHz (for SDMMC)

This assumes HSE = 8 MHz, giving VCO = 8/5 × 500 = 800 MHz within the PLL2 wide VCO range (192-836 MHz per DS12110 Rev 11 §6.3.10 (PLL characteristics). PLL2R = 4 gives 200 MHz SDMMC kernel clock.

On KAKUTEH7WING (HSE = 16 MHz), the math is:

VCO = 16 / 5 × 500 = 1600 MHz
Output Divider Frequency VCO (836 MHz max) Status
PLL2P 2 800 MHz 1600 MHz ~1.9× over VCO max
PLL2Q 3 533 MHz 1600 MHz ~1.9× over VCO max
PLL2R (SDMMC) 4 400 MHz 1600 MHz ~1.9× over VCO max

PLL VCO Out of Spec

Per DS12110 Rev 11 §6.3.10 (PLL characteristics), the PLL2 wide VCO range is 192-836 MHz (same range as PLL1). At 1600 MHz, the PLL output is unreliable regardless of divider ratio.

SDMMC Kernel Clock Note

The issue previously described 200 MHz as the SDMMC kernel clock "max spec." This was inaccurate. After review:

  • 200 MHz is a design convention: the HAL's fixed clock dividers (SDMMC_NSPEED_CLK_DIV=4, SDMMC_HSPEED_CLK_DIV=2) produce standard SD card frequencies (25/50 MHz SDMMC_CK) from that kernel clock rate
  • The HAL reads the actual kernel clock at runtime (HAL_RCCEx_GetPeriphCLKFreq()) and adapts dynamically — it does not require 200 MHz
  • AN5200 states max SDMMC_CK at 208 MHz (SDR104 mode)
  • At 400 MHz kernel clock (the buggy value), the fixed dividers intended for 200 MHz would produce double the intended SD card clock (50 MHz in normal speed), potentially exceeding the card's normal-speed limit

The primary fix is making PLL2M dynamic so VCO never exceeds 836 MHz.

Fix (Merged in PR #11596)

Make PLL2M dynamic using the same formula as PLL1M, and reduce PLL2N to keep VCO at 800 MHz:

RCC_PeriphClkInit.PLL2.PLL2M = HSE_VALUE / 1000000 / 2;
RCC_PeriphClkInit.PLL2.PLL2N = 400;

This pins VCO = 800 MHz for any HSE frequency:

  • HSE=8: M=4, N=400 → VCO=800 MHz, PLL2R=4 → 200 MHz
  • HSE=16: M=8, N=400 → VCO=800 MHz, PLL2R=4 → 200 MHz

Environment

Target: KAKUTEH7WING (HSE_MHZ 16)
MCU: STM32H743
File: src/main/target/system_stm32h7xx.c lines 500-512

PRs

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions