TITLE: Setting up STM32F4 Clocks
AUTHOR: Chuck McManis
LAST UPDATE: 19-May-2019


Computers use clocks. Some have both time of day clocks which hold the time and date, but for this article we’re going to focus on the system clocks which are generally fixed frequency square waves that synchronize the operation of various circuits within the computer.

If you have used a microprocessor such as the Arduino, you may have read something like “The system clock is 16 Mhz”. For many programmers, what the actual value is doesn’t matter, as long as it is stated somewhere. But for embedded programmers, knowing what the clock speed is, and how to change it, lets you operate various peripherals.

The system clock, and all of the peripheral clocks it feeds on the STM32F4 series processors, can be rather intimidating at first. But once you get to know it, you may find as I did that it is pretty straight forward.

Clock Sources

Back in the early days of microprocessors, setting up the clock was the job of a separate chip known as the clock controller. This chip would generate a two phase clock and ensure that the timing between power on and the reset line being released to let the CPU run was met. Then in 1976 when the Z80 was introduced it had a built-in clock chip and from that point forward microprocessors generally had a couple of pins dedicated to either a crystal, or a clock input.

The STM32F4 series generally has three possible clock sources.

The place where this gets tricky is that the chip also includes an internal phase locked loop (PLL) which can be used to increase the effective clock rate significantly.

Further, one clock feeds many of the peripherals and that can put constraints on the clock speed selected if those peripherals are to work correctly. The most common constraint is that the high speed USB peripheral and Ethernet peripheral require a 48 MHz clock to work correctly.

The Phase Locked Loop

The phase locked loop component inside the chip combines a clock multiplier and one or more clock dividers that feed the clock inputs of the chip. There is a brief description of how phase locked loops work here.

Components of the STM32 PLL block

The PLL component is shown above in block form. Different versions of the chip may have one, two, or as many as four of these on some models. They all have the same configuration restrictions but they are used for different parts of the chip, and they all share the same ‘M’ divider. In the diagram, like in the datasheet, the notation /<letter> means "divide by value in field <letter>, and the xN notation is “multiply by N.”

So lets take a quick tour of this gizmo starting with step 1. At the top an input clock signal is fed into the PLL. This clock is either the HSI clock at 16 MHz or an external clock (set by crystal or oscillator) for most of the F4 series. Some of the L4 variants have a medium speed internal clock called MSI and some can use the lowspeed clocks (either LSE or LSI) to feed the system PLL. That input clock is divided by the value ‘M’ which is stored in the PLLM field of the PLL configuration register (RCC_PLLCFGR).

There are a couple of constraints on what values M can take, first it must be greater than 1, the values 0 and 1 are illegal in this field. Second, the result of dividing the input clock by M should take on the value between 1.0 MHz and 2.0 Mhz. This output feeds the VCO (voltage controlled oscillator) and its accuracy is a function of this clock. The reference manuals further recommend that you try to be as close to 2.0 MHz as possible in order to minimize clock jitter (occasional shifts in the clock edges).

At this point you have the input clock divided by the constant M which can take the values between 2 and 63. And you have chosen this value to result in a clock output between 1.0 and 2.0 MHz. The next step, shown with a “2” in the figure, multiplies the product of the input divded by M with the value in the N field.

As with the M field, the N field can take values that are not valid clock configurations. Specifically, the N field typically can take any value between 0 and 511, however the final value of the multiplication must be a value between 100 MHz and 433 MHz. So any value of N that would result in a final value outside this range, is considered invalid, or at least not supported.

This intermediate clock then feeds three dividers, P, Q, and R. These dividers are labeled as steps “3”, “4”, and “5” in the figure.

The system clock (SYSCLK) is defined as the division of intermediate clock and the P field. The P field is only 2 bits wide and so ST Micro has compromised on making it a number that is used directly, instead the values of 0, 1, 2, and 3 are associated with divisor values of 2, 4, 6, and 8. As the minimum value for this field is 2, and the maximum intermediate clock value is 433, the current architecture is constrained to a maximum system clock of 216.5 MHz. The current generation however tops out at 180 MHz and that can be less than useful if you want to use peripherals that need the 48 MHz clock as we will see in a minute.

For each specific part number that ST Micro makes, they put in the reference manual the maximum value of the system clock. The most common side effect of exceeding that value are the system “hanging” or “freezing” because the FLASH subsystem can’t keep up. So when setting up the system clock you should consult the reference manual for the chip you are using, and keep the value of the intermediate clock divided by the effective P value, at or below the maximum value for the chip. Also, this maximum clock rate is often affected by voltage, with 3.3V having the fastest possible clock rate and 1.8V having the slowest.

The next output of the PLL block is the Q clock. This output takes on the value of the intermediate clock divided by the value in Q. Unlike P, the Q field is 4 bits wide and can take numeric values between 0 and 15, however like the M field, the values of 0 and 1 are illegal and the clock will not work when these values are used.

In early versions of the Reference manual, and still on some variants of the F4, this output was labeled the PLL48CK which indicated it was a 48 MHz clock. The USB and SDIO peripherals typically require this clock to be at least 25 MHz and no greater than 48 MHz.

A key consideration is that the USB on-the-go full speed interface (USB OTG FS) requires it to be 48 MHz. If you are going to use this peripheral, then you must arrange it so that the intermediate clock you set up above can be achieved by dividing the intermediate clock by integer between 2 and 15. Looking at that a different way, if you’re using this peripheral there are only 8 valid values for the intermediate clock. With the lowest intermediate clock value of 96 MHz which is divisible by the smallest allowed divior of 2. And the highest intermediate clock value of 432 MHz which is divisible by 9 to get you 48 MHz.

It was constraints like this one that has caused ST Micro to add additional PLL units to the chip, sometimes calls PLLI2S or PLLSAI. If you find you can’t get what you need in terms of clocks, check to see if there is another chip that has a different clock tree that will help you achieve it.

The last output on the PLL is the R output. That is shown as step “5” in the diagram. When this output is connected to something inside the chip, its control field is 3 bits wide. Like the M and Q fields the values of 0 and 1 are not allowed. This gives you the values 2 through 7 to work with.

On the parts with DSI (like the STM32F469 and STM32F479) this output is the DSI clock off the main PLL configuration. These parts also add a third PLL block so that you can generate the PLL48CK 48 MHz clock with that PLL. This allows you to run the DSI at full speed and still have the USB OTG FS peripheral working correctly at the same time.

The R output is most commonly used as an I2S clock and typically is in its own PLL block so you can set the intermediate clock to something that can be divided cleanly into a “standard” I2S clock rate. Remember that all of the PLL clocks share the same source clock and the same M divider.

The PLL’s fields for N, P, Q, and R are all in the same bit positions for each PLL block but are not always used. Additonally the M field, bits 0 to 5, are used on the main PLL and reserved on all others. Because 0 it not a valid value for the N, Q, M, and R fields we can use that value in an API to indicate that the value should not be populated. That is discussed in the next section.