stm32/powerctrl: Support using PLLI2C on STM32F413 as USB clock source.
So SYSCLK can run at more varied frequencies, eg 100MHz. Signed-off-by: Damien George <damien@micropython.org>
This commit is contained in:
parent
00963a4e69
commit
f4340b7e62
|
@ -50,6 +50,22 @@
|
|||
#define RCC_SR_RMVF RCC_CSR_RMVF
|
||||
#endif
|
||||
|
||||
// Whether this MCU has an independent PLL which can generate 48MHz for USB.
|
||||
#if defined(STM32F413xx)
|
||||
// STM32F413 uses PLLI2S as secondary PLL.
|
||||
#define HAVE_PLL48 1
|
||||
#define RCC_CR_PLL48_ON RCC_CR_PLLI2SON
|
||||
#define RCC_CR_PLL48_RDY RCC_CR_PLLI2SRDY
|
||||
#elif defined(STM32F7)
|
||||
// STM32F7 uses PLLSAI as secondary PLL.
|
||||
#define HAVE_PLL48 1
|
||||
#define RCC_CR_PLL48_ON RCC_CR_PLLSAION
|
||||
#define RCC_CR_PLL48_RDY RCC_CR_PLLSAIRDY
|
||||
#else
|
||||
// MCU does not have a secondary PLL.
|
||||
#define HAVE_PLL48 0
|
||||
#endif
|
||||
|
||||
// Location in RAM of bootloader state (just after the top of the stack)
|
||||
extern uint32_t _estack[];
|
||||
#define BL_STATE ((uint32_t *)&_estack)
|
||||
|
@ -141,13 +157,24 @@ STATIC int powerctrl_config_vos(uint32_t sysclk_mhz) {
|
|||
}
|
||||
|
||||
// Assumes that PLL is used as the SYSCLK source
|
||||
int powerctrl_rcc_clock_config_pll(RCC_ClkInitTypeDef *rcc_init, uint32_t sysclk_mhz, bool need_pllsai) {
|
||||
int powerctrl_rcc_clock_config_pll(RCC_ClkInitTypeDef *rcc_init, uint32_t sysclk_mhz, bool need_pll48) {
|
||||
uint32_t flash_latency;
|
||||
|
||||
#if defined(STM32F7)
|
||||
if (need_pllsai) {
|
||||
// Configure PLLSAI at 48MHz for those peripherals that need this freq
|
||||
// (calculation assumes it can get an integral value of PLLSAIN)
|
||||
#if HAVE_PLL48
|
||||
if (need_pll48) {
|
||||
// Configure secondary PLL at 48MHz for those peripherals that need this freq
|
||||
// (the calculation assumes it can get an integral value of PLL-N).
|
||||
|
||||
#if defined(STM32F413xx)
|
||||
const uint32_t plli2sm = HSE_VALUE / 1000000;
|
||||
const uint32_t plli2sq = 2;
|
||||
const uint32_t plli2sr = 2;
|
||||
const uint32_t plli2sn = 48 * plli2sq;
|
||||
RCC->PLLI2SCFGR = plli2sr << RCC_PLLI2SCFGR_PLLI2SR_Pos
|
||||
| plli2sq << RCC_PLLI2SCFGR_PLLI2SQ_Pos
|
||||
| plli2sn << RCC_PLLI2SCFGR_PLLI2SN_Pos
|
||||
| plli2sm << RCC_PLLI2SCFGR_PLLI2SM_Pos;
|
||||
#else
|
||||
const uint32_t pllm = (RCC->PLLCFGR >> RCC_PLLCFGR_PLLM_Pos) & 0x3f;
|
||||
const uint32_t pllsaip = 4;
|
||||
const uint32_t pllsaiq = 2;
|
||||
|
@ -155,13 +182,18 @@ int powerctrl_rcc_clock_config_pll(RCC_ClkInitTypeDef *rcc_init, uint32_t sysclk
|
|||
RCC->PLLSAICFGR = pllsaiq << RCC_PLLSAICFGR_PLLSAIQ_Pos
|
||||
| (pllsaip / 2 - 1) << RCC_PLLSAICFGR_PLLSAIP_Pos
|
||||
| pllsain << RCC_PLLSAICFGR_PLLSAIN_Pos;
|
||||
RCC->CR |= RCC_CR_PLLSAION;
|
||||
#endif
|
||||
|
||||
// Turn on the PLL and wait for it to be ready.
|
||||
RCC->CR |= RCC_CR_PLL48_ON;
|
||||
uint32_t ticks = mp_hal_ticks_ms();
|
||||
while (!(RCC->CR & RCC_CR_PLLSAIRDY)) {
|
||||
while (!(RCC->CR & RCC_CR_PLL48_RDY)) {
|
||||
if (mp_hal_ticks_ms() - ticks > 200) {
|
||||
return -MP_ETIMEDOUT;
|
||||
}
|
||||
}
|
||||
|
||||
// Select the alternate 48MHz source.
|
||||
RCC->DCKCFGR2 |= RCC_DCKCFGR2_CK48MSEL;
|
||||
}
|
||||
#endif
|
||||
|
@ -317,7 +349,7 @@ int powerctrl_set_sysclk(uint32_t sysclk, uint32_t ahb, uint32_t apb1, uint32_t
|
|||
// Default PLL parameters that give 48MHz on PLL48CK
|
||||
uint32_t m = MICROPY_HW_CLK_VALUE / 1000000, n = 336, p = 2, q = 7;
|
||||
uint32_t sysclk_source;
|
||||
bool need_pllsai = false;
|
||||
bool need_pll48 = false;
|
||||
|
||||
// Search for a valid PLL configuration that keeps USB at 48MHz
|
||||
uint32_t sysclk_mhz = sysclk / 1000000;
|
||||
|
@ -338,8 +370,8 @@ int powerctrl_set_sysclk(uint32_t sysclk, uint32_t ahb, uint32_t apb1, uint32_t
|
|||
uint32_t vco_out = sys * p;
|
||||
n = vco_out * m / (MICROPY_HW_CLK_VALUE / 1000000);
|
||||
q = vco_out / 48;
|
||||
#if defined(STM32F7)
|
||||
need_pllsai = vco_out % 48 != 0;
|
||||
#if HAVE_PLL48
|
||||
need_pll48 = vco_out % 48 != 0;
|
||||
#endif
|
||||
}
|
||||
goto set_clk;
|
||||
|
@ -393,11 +425,11 @@ set_clk:
|
|||
return -MP_EIO;
|
||||
}
|
||||
|
||||
#if defined(STM32F7)
|
||||
#if HAVE_PLL48
|
||||
// Deselect PLLSAI as 48MHz source if we were using it
|
||||
RCC->DCKCFGR2 &= ~RCC_DCKCFGR2_CK48MSEL;
|
||||
// Turn PLLSAI off because we are changing PLLM (which drives PLLSAI)
|
||||
RCC->CR &= ~RCC_CR_PLLSAION;
|
||||
RCC->CR &= ~RCC_CR_PLL48_ON;
|
||||
#endif
|
||||
|
||||
// Re-configure PLL
|
||||
|
@ -440,7 +472,7 @@ set_clk:
|
|||
// Set PLL as system clock source if wanted
|
||||
if (sysclk_source == RCC_SYSCLKSOURCE_PLLCLK) {
|
||||
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK;
|
||||
int ret = powerctrl_rcc_clock_config_pll(&RCC_ClkInitStruct, sysclk_mhz, need_pllsai);
|
||||
int ret = powerctrl_rcc_clock_config_pll(&RCC_ClkInitStruct, sysclk_mhz, need_pll48);
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
|
@ -607,11 +639,11 @@ void powerctrl_enter_stop_mode(void) {
|
|||
|
||||
powerctrl_disable_hsi_if_unused();
|
||||
|
||||
#if defined(STM32F7)
|
||||
#if HAVE_PLL48
|
||||
if (RCC->DCKCFGR2 & RCC_DCKCFGR2_CK48MSEL) {
|
||||
// Enable PLLSAI if it is selected as 48MHz source
|
||||
RCC->CR |= RCC_CR_PLLSAION;
|
||||
while (!(RCC->CR & RCC_CR_PLLSAIRDY)) {
|
||||
RCC->CR |= RCC_CR_PLL48_ON;
|
||||
while (!(RCC->CR & RCC_CR_PLL48_RDY)) {
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -351,8 +351,8 @@ void SystemClock_Config(void) {
|
|||
|
||||
uint32_t vco_out = RCC_OscInitStruct.PLL.PLLN * (MICROPY_HW_CLK_VALUE / 1000000) / RCC_OscInitStruct.PLL.PLLM;
|
||||
uint32_t sysclk_mhz = vco_out / RCC_OscInitStruct.PLL.PLLP;
|
||||
bool need_pllsai = vco_out % 48 != 0;
|
||||
if (powerctrl_rcc_clock_config_pll(&RCC_ClkInitStruct, sysclk_mhz, need_pllsai) != 0) {
|
||||
bool need_pll48 = vco_out % 48 != 0;
|
||||
if (powerctrl_rcc_clock_config_pll(&RCC_ClkInitStruct, sysclk_mhz, need_pll48) != 0) {
|
||||
__fatal_error("HAL_RCC_ClockConfig");
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue