aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ports/stm32/Makefile2
-rw-r--r--ports/stm32/boards/pllvalues.py73
-rw-r--r--ports/stm32/modmachine.c33
-rw-r--r--ports/stm32/system_stm32.c36
4 files changed, 109 insertions, 35 deletions
diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile
index c543f0159..92f3648e1 100644
--- a/ports/stm32/Makefile
+++ b/ports/stm32/Makefile
@@ -582,7 +582,7 @@ CMSIS_MCU_HDR = $(CMSIS_DIR)/$(CMSIS_MCU_LOWER).h
modmachine.c: $(GEN_PLLFREQTABLE_HDR)
$(GEN_PLLFREQTABLE_HDR): $(PLLVALUES) | $(HEADER_BUILD)
$(ECHO) "GEN $@"
- $(Q)$(PYTHON) $(PLLVALUES) -c file:$(BOARD_DIR)/stm32$(MCU_SERIES)xx_hal_conf.h > $@
+ $(Q)$(PYTHON) $(PLLVALUES) -c $(if $(filter $(MCU_SERIES),f7),--relax-pll48,) file:$(BOARD_DIR)/stm32$(MCU_SERIES)xx_hal_conf.h > $@
$(BUILD)/modstm.o: $(GEN_STMCONST_HDR)
# Use a pattern rule here so that make will only call make-stmconst.py once to
diff --git a/ports/stm32/boards/pllvalues.py b/ports/stm32/boards/pllvalues.py
index befd6cfa0..4b090c455 100644
--- a/ports/stm32/boards/pllvalues.py
+++ b/ports/stm32/boards/pllvalues.py
@@ -39,38 +39,49 @@ def compute_pll(hse, sys):
return None
# improved version that doesn't require N/M to be an integer
-def compute_pll2(hse, sys):
+def compute_pll2(hse, sys, relax_pll48):
# Loop over the allowed values of P, looking for a valid PLL configuration
# that gives the desired "sys" frequency. We use floats for P to force
# floating point arithmetic on Python 2.
+ fallback = None
for P in (2.0, 4.0, 6.0, 8.0):
- Q = sys * P / 48
- # Q must be an integer in a set range
- if not (close_int(Q) and 2 <= Q <= 15):
- continue
NbyM = sys * P / hse
# VCO_OUT must be between 192MHz and 432MHz
if not (192 <= hse * NbyM <= 432):
continue
- # compute M
- M = 192 // NbyM # starting value
- while hse > 2 * M or NbyM * M < 192 or not close_int(NbyM * M):
+ # scan M
+ M = int(192 // NbyM) # starting value
+ while 2 * M < hse:
M += 1
# VCO_IN must be between 1MHz and 2MHz (2MHz recommended)
- if not (M <= hse):
- continue
- # compute N
- N = NbyM * M
- # N must be an integer
- if not close_int(N):
- continue
- # N is restricted
- if not (192 <= N <= 432):
- continue
- # found valid values
- return (M, N, P, Q)
- # no valid values found
- return None
+ for M in range(M, hse + 1):
+ if NbyM * M < 191.99 or not close_int(NbyM * M):
+ continue
+ # compute N
+ N = NbyM * M
+ # N must be an integer
+ if not close_int(N):
+ continue
+ # N is restricted
+ if not (192 <= N <= 432):
+ continue
+ Q = (sys * P / 48)
+ # Q must be an integer in a set range
+ if not (2 <= Q <= 15):
+ continue
+ if not close_int(Q):
+ if int(M) == int(hse) and fallback is None:
+ # the values don't give 48MHz on PLL48 but are otherwise OK
+ fallback = M, N, P, int(Q)
+ continue
+ # found valid values
+ return (M, N, P, Q)
+ if relax_pll48:
+ # might have found values which don't give 48MHz on PLL48
+ return fallback
+ else:
+ # no valid values found which give 48MHz on PLL48
+ return None
def compute_derived(hse, pll):
M, N, P, Q = pll
@@ -125,9 +136,17 @@ def main():
argv = sys.argv[1:]
c_table = False
- if argv[0] == '-c':
- c_table = True
- argv.pop(0)
+ relax_pll48 = False
+
+ while True:
+ if argv[0] == '-c':
+ c_table = True
+ argv.pop(0)
+ elif argv[0] == '--relax-pll48':
+ relax_pll48 = True
+ argv.pop(0)
+ else:
+ break
if len(argv) != 1:
print("usage: pllvalues.py [-c] <hse in MHz>")
@@ -150,8 +169,8 @@ def main():
hse = int(argv[0])
valid_plls = []
- for sysclk in range(1, 217):
- pll = compute_pll2(hse, sysclk)
+ for sysclk in range(2, 217, 2):
+ pll = compute_pll2(hse, sysclk, relax_pll48)
if pll is not None:
verify_pll(hse, pll)
valid_plls.append((sysclk, pll))
diff --git a/ports/stm32/modmachine.c b/ports/stm32/modmachine.c
index 3da85c187..6e0c08605 100644
--- a/ports/stm32/modmachine.c
+++ b/ports/stm32/modmachine.c
@@ -324,6 +324,9 @@ STATIC mp_obj_t machine_freq(size_t n_args, const mp_obj_t *args) {
// default PLL parameters that give 48MHz on PLL48CK
uint32_t m = HSE_VALUE / 1000000, n = 336, p = 2, q = 7;
uint32_t sysclk_source;
+ #if defined(STM32F7)
+ bool need_pllsai = false;
+ #endif
// search for a valid PLL configuration that keeps USB at 48MHz
for (const uint16_t *pll = &pll_freq_table[MP_ARRAY_SIZE(pll_freq_table) - 1]; pll >= &pll_freq_table[0]; --pll) {
@@ -345,6 +348,9 @@ STATIC mp_obj_t machine_freq(size_t n_args, const mp_obj_t *args) {
uint32_t vco_out = sys * p;
n = vco_out * m / (HSE_VALUE / 1000000);
q = vco_out / 48;
+ #if defined(STM32F7)
+ need_pllsai = vco_out % 48 != 0;
+ #endif
goto set_clk;
}
}
@@ -394,6 +400,11 @@ STATIC mp_obj_t machine_freq(size_t n_args, const mp_obj_t *args) {
goto fail;
}
+ #if defined(STM32F7)
+ // Turn PLLSAI off because we are changing PLLM (which drives PLLSAI)
+ RCC->CR &= ~RCC_CR_PLLSAION;
+ #endif
+
// re-configure PLL
// even if we don't use the PLL for the system clock, we still need it for USB, RNG and SDIO
RCC_OscInitTypeDef RCC_OscInitStruct;
@@ -409,6 +420,28 @@ STATIC mp_obj_t machine_freq(size_t n_args, const mp_obj_t *args) {
goto fail;
}
+ #if defined(STM32F7)
+ if (need_pllsai) {
+ // Configure PLLSAI at 48MHz for those peripherals that need this freq
+ const uint32_t pllsain = 192;
+ const uint32_t pllsaip = 4;
+ const uint32_t pllsaiq = 2;
+ RCC->PLLSAICFGR = pllsaiq << RCC_PLLSAICFGR_PLLSAIQ_Pos
+ | (pllsaip / 2 - 1) << RCC_PLLSAICFGR_PLLSAIP_Pos
+ | pllsain << RCC_PLLSAICFGR_PLLSAIN_Pos;
+ RCC->CR |= RCC_CR_PLLSAION;
+ uint32_t ticks = mp_hal_ticks_ms();
+ while (!(RCC->CR & RCC_CR_PLLSAIRDY)) {
+ if (mp_hal_ticks_ms() - ticks > 200) {
+ goto fail;
+ }
+ }
+ RCC->DCKCFGR2 |= RCC_DCKCFGR2_CK48MSEL;
+ } else {
+ RCC->DCKCFGR2 &= ~RCC_DCKCFGR2_CK48MSEL;
+ }
+ #endif
+
// set PLL as system clock source if wanted
if (sysclk_source == RCC_SYSCLKSOURCE_PLLCLK) {
uint32_t flash_latency;
diff --git a/ports/stm32/system_stm32.c b/ports/stm32/system_stm32.c
index 0cf0753bd..5d9a1b662 100644
--- a/ports/stm32/system_stm32.c
+++ b/ports/stm32/system_stm32.c
@@ -371,6 +371,13 @@ void SystemInit(void)
*/
void SystemClock_Config(void)
{
+ #if defined(STM32F7)
+ // The DFU bootloader changes the clocksource register from its default power
+ // on reset value, so we set it back here, so the clocksources are the same
+ // whether we were started from DFU or from a power on reset.
+ RCC->DCKCFGR2 = 0;
+ #endif
+
RCC_ClkInitTypeDef RCC_ClkInitStruct;
RCC_OscInitTypeDef RCC_OscInitStruct;
#if defined(STM32H7)
@@ -506,6 +513,28 @@ void SystemClock_Config(void)
__fatal_error("HAL_RCC_OscConfig");
}
+ #if defined(STM32F7)
+ uint32_t vco_out = RCC_OscInitStruct.PLL.PLLN * (HSE_VALUE / 1000000) / RCC_OscInitStruct.PLL.PLLM;
+ bool need_pllsai = vco_out % 48 != 0;
+ if (need_pllsai) {
+ // Configure PLLSAI at 48MHz for those peripherals that need this freq
+ const uint32_t pllsain = 192;
+ const uint32_t pllsaip = 4;
+ const uint32_t pllsaiq = 2;
+ RCC->PLLSAICFGR = pllsaiq << RCC_PLLSAICFGR_PLLSAIQ_Pos
+ | (pllsaip / 2 - 1) << RCC_PLLSAICFGR_PLLSAIP_Pos
+ | pllsain << RCC_PLLSAICFGR_PLLSAIN_Pos;
+ RCC->CR |= RCC_CR_PLLSAION;
+ uint32_t ticks = mp_hal_ticks_ms();
+ while (!(RCC->CR & RCC_CR_PLLSAIRDY)) {
+ if (mp_hal_ticks_ms() - ticks > 200) {
+ __fatal_error("PLLSAIRDY timeout");
+ }
+ }
+ RCC->DCKCFGR2 |= RCC_DCKCFGR2_CK48MSEL;
+ }
+ #endif
+
#if defined(STM32H7)
/* PLL3 for USB Clock */
PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_USB;
@@ -554,13 +583,6 @@ void SystemClock_Config(void)
HAL_PWREx_EnableUSBVoltageDetector();
#endif
-#if defined(STM32F7)
- // The DFU bootloader changes the clocksource register from its default power
- // on reset value, so we set it back here, so the clocksources are the same
- // whether we were started from DFU or from a power on reset.
-
- RCC->DCKCFGR2 = 0;
-#endif
#if defined(STM32L4)
// Enable MSI-Hardware auto calibration mode with LSE
HAL_RCCEx_EnableMSIPLLMode();