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:
|
#define CLOCK_AHB_DIV RCC_CFGR_HPRE_DIV1 |
|
#define CLOCK_AHB (CLOCK_CORECLOCK / 1) |
|
#define CLOCK_APB1_DIV RCC_CFGR_PPRE_DIV1 /* max 48MHz */ |
|
#define CLOCK_APB1 (CLOCK_CORECLOCK / 1) |
|
#define CLOCK_APB2 (CLOCK_APB1) |
Here, CLOCK_APB1 is CLOCK_CORECLOCK divided by 1, but CLOCK_APB1_DIV is not 1, it's the corresponding bitfield. It would be simpler to directly compute CLOCK_APB1 from CLOCK_CORECLOCK and CLOCK_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:
- L0 and L1 specific required changes:
- L4/WB specific required changes:
- F0/F1/F3 specific required changes:
- F2/F4/F7 specific required changes:
- G0/G4 specific required changes:
- Possible improvements once clock configurations are consistent across STM32 CPU families:
- Kconfig: add Kconfig files for configuring the clocks at CPU level
This is is not exhaustive and is subject to change over time.
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:
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_APB1isCLOCK_CORECLOCKdivided by 1, but CLOCK_APB1_DIV is not 1, it's the corresponding bitfield. It would be simpler to directly computeCLOCK_APB1fromCLOCK_CORECLOCKandCLOCK_APB1_DIV:And since APB1 corresponds to
HCLK / CLOCK_APB1_DIV, it should even beCLOCK_AHB / CLOCK_APB1_DIVAnother issue with the current design is that
CLOCK_CORECLOCKis 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
xtimertest 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.
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_conftool 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):
Here, since f0 is sharing with F1/F2/F4/F7 the same implementation of the clock initialization (in
stmclk_fx.c), we have to split the f0 part fromstmclk_fx.cand work on it.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.
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.
cpu/dist/clk_conftool 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)CLOCK_CORECLOCK,CLOCK_AHB,CLOCK_APBxshould only be defined instmclk.hdisable_clock_hsifor instance, there's a check on CLOCK_HSE that should be removed) cpu/stm32: simplify stmclk_disable_hsi function #15259CLOCK_LSEwithCONFIG_BOARD_HAS_LSEin the periph_rtc implementation and in the configuration headers cpu/stm32: remove CLOCK_LSE define, use CONFIG_BOARD_HAS_LSE instead #15260CLOCK_AHB_DIVis different from 1cpu/stm32boards/stm32gx: move kconfig clock configuration to cpu level #15286This is is not exhaustive and is subject to change over time.