STM32 gotchas
194. PLL does not output expected frequency or does not work at all, as physical ratio is not identical to the value written to registers

In every STM32, there is at least one PLL in the RCC module, which generates the high frequency clock (>16 MHz) for overall mcu operation from relatively low frequency (0.1MHz..16MHz) primary clock source (HSI, MSI, HSE).

In the older and lower-end STM32 ('F1, 'L1, 'F0, 'F3, 'L0), the PLL is controlled by a single parameter, which determines the PLL's multiplier. However, the value written to respective register field (usually RCC_CFGR.PLLMUL) is not equal to the ratio by which the PLL's input frequency is multiplied. In most STM32 with simple PLL, the physical ratio = (value + 1), i.e. value of 0b0000 results in x2 frequency, value of 0b0001 results in x3, etc; with the exception that both 0b1110 and 0b1111 result in x16 frequency.

The 'L0 and 'L1 families have a different form of simple PLL: its output frequeny ratios can be described only by a table (x3, x4, x6, x8, x12, x16, x24, x32, x48).

In the higher-end and newer STM321, the PLL has a pre-scaler2, the multiplier itself, and usually 3 output dividers, potentially serving 3 clock branches with different frequencies. The prescaler's ratio is denoted M, the multiplier's N, and the output dividers' P, Q and R.

Here again, the physical divider/multiplier ratios are not necessarily equal to the values written to respective registers fields (in the dedicated PLL register, RCC_PLLCFGR). The details differ across STM32 families, so it's necessary to carefully read the description of these registers fields when migrating between families.

The N multiplier ratio usually does match the written value.

In 'F4 and 'F7, the P post-divider's ratio = 2 * (value + 1) (i.e. /2, /4, /6, /8); this divider's output can be used as system clock. Strangely, the Q (and R in the SAI PLL where present) ratios equal to the written values, but values of 0 and 1 are forbidden; the same applies to the M prescaler.

In 'G0, the M prescaler's, and all 3 post-scaler's ratio = value + 1.

In 'L476 (historically the first member of 'L4 family), the M pre-scaler's ratio = value + 1; R (which here supplies system clock) and Q divider's ratio = 2 * (value + 1), and the P divider is selectable only between 2 quite strange values, /7 and /17.

In all other 'L4 and also in 'G4 and 'L5, the same scheme is used, except that there's an extra field for the P-postscaler, following the "ratio equals value, but minimum value is 2" scheme. However, for (quite uncomprehensible) backward compatibility reasons, the original bit for P switching between the weird /7 and /17 ratios is maintained, and is valid when the new field is set to 0b0000.


1. except 'H7 and 'U5, which have a much more complex fractional-N PLL

2. in high-end families with multiple PLLs, there may be only one common pre-scaler; this fact in itself may be a source of mistake