[Tracking] Refactor STM32 clock configuration and initialization #14975
Description
Description
This issue is a tracking for the refactoring of the clock configuration and initialization on STM32 cpus.
Current situation
In the current situation, the whole clock configuration is done at board level although a lot parameters are CPU level specific.
-
Here is the list of clock parameters that doesn't depend on the board configuration:
- sysclk source clock: it can be either HSE, HSI, MSI (only on L0,L1,L4,WB families) or PLL but in RIOT only the PLL is used.
- the PLL parameters (M,N,P,Q factors or PREDIV,MUL factors, depending on the families
- the AHB/APBx dividers
-
There are other problems with the current clock configuration mechanism: it's not easy to change the parameters.
For example, one would have to write his own config header and use pre-processor conditionals to skip the default values. This custom header would have to define all parameters, even if only a few needs to be tweaked. -
For AHB/APBx dividers, there's no connection between the define of the divider value (it must contain the corresponding bitfields to put in the configuration register) and actual output clock of the bus. Example:
RIOT/boards/common/stm32/include/f0/cfg_clock_default.h
Lines 48 to 52 in 27e4c19
Here,CLOCK_APB1
isCLOCK_CORECLOCK
divided by 1, but CLOCK_APB1_DIV is not 1, it's the corresponding bitfield. It would be simpler to directly computeCLOCK_APB1
fromCLOCK_CORECLOCK
andCLOCK_APB1_DIV
:
#define CLOCK_APB1 CLOCK_CORECLOCK / CLOCK_APB1_DIV
And since APB1 corresponds to HCLK / CLOCK_APB1_DIV
, it should even be CLOCK_AHB / CLOCK_APB1_DIV
-
Another issue with the current design is that
CLOCK_CORECLOCK
is hardcoded although it could easily be computed automatically, at build time, as a combination of the input clock frequency (either HSI or HSE) and the PLL factors. -
The stm32fx.c file is mixing two different families of clocks initialization: those with M/N/P PLL (f2/f4/f7) and those with PREDIV/MUL PLL (F0/F1/F3)
-
About the selection of the 48MHz clock (used by USB): some 100MHz and 180MHz capable CPUs are forced to run at 96MHz and 168MHz to get a 48MHz clock PLLQ even if it's unused (no USB required for instance).
-
It is not possible to define the AHB divider to something different than 1, otherwise
xtimer
test applications are not working properly.
Expected situation
In general, the expected situation should provide a way to easily configure the clocks of a CPU: by easily, we mean no need to know the bitfields in advance and the parameters can be overridden via CFLAGS (command line or Makefile), a custom config header and Kconfig.
- The only parameters that should depend on the board configuration are:
- whether the board provides an HSE to clock the CPU
- if there's one, the frequency of the HSE
- whether the board provides an LSE (and eventually it's frequency)
- All other parameters should be only exposed at the CPU level: SYSCLK source, PLL parameters, AHB/APBx dividers, MCO sources, enabling and config of 48MHz clocks
Doing this will allow a simpler and centralized clock configuration: less code duplication and more flexibility.
The CLOCK_CORECLOCK and all sub-clock values should be computed at build time with good defaults.
For the 48MHz source clocks, they should only be enabled if required by the application. For the moment, this is only the case when the USB peripheral feature is required.
On F4 and F7 families, several 48MHz clock source are possible (from PLLQ, PLLI2S or PLLSAI). The idea is to fall back to PLLI2S/PLLSAI when PLLQ cannot output 48MHz and to fail at build time if no 48MHz clock is available.
For 100MHz and 180MHz capable CPUs (typically on F4), we should by default configure them to reach their maximum clock frequency by default and adapt it when 48MHz is needed (and then their core clock would decrease to 96/168MHz).
After that rework, the cpu/dist/clk_conf
tool will become obsolete and will not longer be needed.
Work to be done
Achieving what's described above is a lot of work and cannot be done in a single PR. To prepare the work needed for Kconfig, all configuration constants will be prefixed by CONFIG_
.
Here are the steps needed (not necessary in order, for some there are already opened PRs and some PRs were already merged):
- Prerequisites changes:
- For each STM32 families, provide the clock configuration of all boards in common headers: see boards/stm32f0: introduce default shared clock configuration header #14891, boards/stm32f1: stm32f3: use shared default clock configuration header #14892, boards/stm32l1: introduce shared clock configuration header #14870 for details on F0/F1/F3/L1.
- L0 and L1 specific required changes:
- Rework the initialization and configuration of L0 and L1 families. These families are already sharing the same initialization code, but only PLL can be used. boards/stm32l0l1: rework clock initialization and configuration #14945
- Implement MCO configuration for L0/L1 cpu/stm32l0l1: add MCO configuration and initialization #15073
- Implement 48MHz clock configuration/initialization for L0/L1 boards/stm32l0l1: rework clock initialization and configuration #14945
- L4/WB specific required changes:
- Rework the initialization and configuration of L4 and WB families. boards: cpu: stm32l4/wb: rework clock configuration and initialization #14866
- Implement MCO configuration for L4/WB, cpu/stm32l4: configure and initialize MCO #15064
- Implement 48MHz clock configuration/initialization for L4/WB: cpu/stm32l4: improve clock initialization #15036
- Implement PLLSAI1/2 clock initialization and configuration (could be inspired by the work done in boards/stm32f2/f4/f7: rework clock initialization and configuration #14946)
- F0/F1/F3 specific required changes:
- Rework the initialization and configuration of F0 family: boards/stm32f0: rework clock initialization and configuration #14921.
Here, since f0 is sharing with F1/F2/F4/F7 the same implementation of the clock initialization (instmclk_fx.c
), we have to split the f0 part fromstmclk_fx.c
and work on it. - Rework the initialization and configuration of F1 and F3 families: boards/stm32f1/f3: rework clock initialization and configuration #14923.
Since F0/F1/F3 have a very similar clock configuration (HSE/HSI/PLL possible SYSCLK sources and PREDIV/MUL PLL parameters, only one MCO output), this PR merge their clock initialization code. - Better handle the HSI PLL input that is divided by 2 and cannot be configured by the user (it's hard-wired) on some f0 and f3 cpu lines boards/stm32f1f3: model clock configuration in Kconfig #15001
- Implement MCO configuration for F0/F1/F3 cpu/stm32f0f1f3: add MCO configuration and initialization #15078
- Implement 48MHz clock configuration/initialization for F0/F1/F3 (HSI48 on F0 only available on STM32F04x, STM32F07x and STM32F09x lines)
- Merge the F0/F1/F3 clock configuration headers cpu/stm32: merge f0/f1/f3 clock configuration headers #15650
- Rework the initialization and configuration of F0 family: boards/stm32f0: rework clock initialization and configuration #14921.
- F2/F4/F7 specific required changes:
- Rework the initialization and configuration of F2, F4 and F7 families: boards/stm32f2/f4/f7: rework clock initialization and configuration #14946.
This is a big one because these families can provide several PLL (Main PLL, PLLI2S, PLLSAI), 48MHz possible clock from 2 sources, 2 MCO (MCO1 and MCO2) and CPUs can work at different max clock speeds. - Remove
cpu/dist/clk_conf
tool that will be obsolete after boards/stm32f2/f4/f7: rework clock initialization and configuration #14946 gets merged. Also update the github actions check (will be required by the CI anyway) - Remove 96MHz and 168MHz default clock configuration headers and merge them with the 100MHz and 180MHz headers. 96MHz and 180MHz clock should only be set by default when a 48MHz clock source is required, otherwise the CPU is configured to 100MHz and 180MHz by default. boards/stm32f4: remove default clock configuration for 96MHz and 168MHz CPUs #15043
- Manage overdrive mode for high clock speeds (>168MHz on F4 and > 180MHz on F7) cpu/stm32: enable overdrive mode on f4 and f7 for high clock speeds #15223
- Rework the initialization and configuration of F2, F4 and F7 families: boards/stm32f2/f4/f7: rework clock initialization and configuration #14946.
- G0/G4 specific required changes:
- Improve 48MHz clock configuration (there are multiple available sources
- Implement MCO initialization and configuration cpu/stm32gx: add MCO configuration and initialization #15084
- Possible improvements once clock configurations are consistent across STM32 CPU families:
- Move all clock configuration headers from boards/ to cpu/ and only keep in boards the default values for HSE and LSE boards/stm32: cpu/stm32: move clock configuration from boards to cpu #15273
-
CLOCK_CORECLOCK
,CLOCK_AHB
,CLOCK_APBx
should only be defined instmclk.h
- Common ifdefs in the clock configurations could be factorized cpu/stm32: merge clock source selection headers #15657
- Find a way to handle in a generic way good PLL defaults for any value of HSE clock: not possible but custom configuration can be provided at board level (both in periph_conf.h and in Kconfig)
- Do some cleanup in stmclk_common.c (in
disable_clock_hsi
for instance, there's a check on CLOCK_HSE that should be removed) cpu/stm32: simplify stmclk_disable_hsi function #15259 - Replace the
CLOCK_LSE
withCONFIG_BOARD_HAS_LSE
in the periph_rtc implementation and in the configuration headers cpu/stm32: remove CLOCK_LSE define, use CONFIG_BOARD_HAS_LSE instead #15260 - Implement static inline functions to return the core clock, clock_apb, etc
- Add pre-processor checks for the PLL parameters and for the intermediate PLL clock values that should be kept within certain bounds (that depends on families and/or cpu lines)
- Fix the timer issue when
CLOCK_AHB_DIV
is different from 1 - Add configuration for AHB prescaler (fixed to 1 for the moment). This requires the previous point to be fixed first.
- Implement calibration for internal oscillators (for HSI, LSI, HSI48 for example)
- Document the clock configuration cpu/stm32: rewrite clock configuration documentation #15265
- Kconfig: add Kconfig files for configuring the clocks at CPU level
- Expose CPU lines config in Kconfig: cpu/stm32: model CPU lines in Kconfig + small refactoring #14998
- Move Kconfig file of stm32gx to
cpu/stm32
boards/stm32gx: move kconfig clock configuration to cpu level #15286 - F0: boards/stm32f0: add Kconfig for clock configuration #14967
- F1/F3: boards/stm32f1f3: model clock configuration in Kconfig #15001
- F2/F4/F7 cpu/stm32f2f4f7: expose clock configuration in kconfig #15632
- L0/L1: boards/stm32l0l1: model clock configuration in kconfig #15000
- L4/WB: boards/stm32l4/wb: add Kconfig for clock configuration #14968
- MP1
- Expose MCO configuration in Kconfig cpu/stm32: model MCO clock configuration in kconfig #15706
This is is not exhaustive and is subject to change over time.