stm32/powerctrl: Improve support for changing system freq on H7 MCUs.
This commit improves pllvalues.py to generate PLL values for H7 MCUs that are valid (VCO in and out are in range) and extend for the entire range of SYSCLK values up to 400MHz (up to 480MHz is currently unsupported).
This commit is contained in:
parent
03b73ce329
commit
2c8c2b935e
@ -649,7 +649,7 @@ CMSIS_MCU_HDR = $(CMSIS_DIR)/$(CMSIS_MCU_LOWER).h
|
|||||||
modmachine.c: $(GEN_PLLFREQTABLE_HDR)
|
modmachine.c: $(GEN_PLLFREQTABLE_HDR)
|
||||||
$(GEN_PLLFREQTABLE_HDR): $(PLLVALUES) | $(HEADER_BUILD)
|
$(GEN_PLLFREQTABLE_HDR): $(PLLVALUES) | $(HEADER_BUILD)
|
||||||
$(ECHO) "GEN $@"
|
$(ECHO) "GEN $@"
|
||||||
$(Q)$(PYTHON) $(PLLVALUES) -c $(if $(filter $(MCU_SERIES),f7),--relax-pll48,) file:$(BOARD_DIR)/stm32$(MCU_SERIES)xx_hal_conf.h > $@
|
$(Q)$(PYTHON) $(PLLVALUES) -c -m $(MCU_SERIES) file:$(BOARD_DIR)/stm32$(MCU_SERIES)xx_hal_conf.h > $@
|
||||||
|
|
||||||
$(BUILD)/modstm.o: $(GEN_STMCONST_HDR)
|
$(BUILD)/modstm.o: $(GEN_STMCONST_HDR)
|
||||||
# Use a pattern rule here so that make will only call make-stmconst.py once to
|
# Use a pattern rule here so that make will only call make-stmconst.py once to
|
||||||
|
@ -7,6 +7,36 @@ for the machine.freq() function.
|
|||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
class MCU:
|
||||||
|
def __init__(self, range_sysclk, range_m, range_n, range_p, range_q, range_vco_in, range_vco_out):
|
||||||
|
self.range_sysclk = range_sysclk
|
||||||
|
self.range_m = range_m
|
||||||
|
self.range_n = range_n
|
||||||
|
self.range_p = range_p
|
||||||
|
self.range_q = range_q
|
||||||
|
self.range_vco_in = range_vco_in
|
||||||
|
self.range_vco_out = range_vco_out
|
||||||
|
|
||||||
|
mcu_default = MCU(
|
||||||
|
range_sysclk=range(2, 216 + 1, 2),
|
||||||
|
range_m=range(2, 63 + 1),
|
||||||
|
range_n=range(192, 432 + 1),
|
||||||
|
range_p=range(2, 8 + 1, 2),
|
||||||
|
range_q=range(2, 15 + 1),
|
||||||
|
range_vco_in=range(1, 2 + 1),
|
||||||
|
range_vco_out=range(192, 432 + 1),
|
||||||
|
)
|
||||||
|
|
||||||
|
mcu_h7 = MCU(
|
||||||
|
range_sysclk=range(2, 400 + 1, 2), # above 400MHz currently unsupported
|
||||||
|
range_m=range(1, 63 + 1),
|
||||||
|
range_n=range(4, 512 + 1),
|
||||||
|
range_p=range(2, 128 + 1, 2),
|
||||||
|
range_q=range(1, 128 + 1),
|
||||||
|
range_vco_in=range(1, 16 + 1),
|
||||||
|
range_vco_out=range(150, 960 + 1), # 150-420=medium, 192-960=wide
|
||||||
|
)
|
||||||
|
|
||||||
def close_int(x):
|
def close_int(x):
|
||||||
return abs(x - round(x)) < 0.01
|
return abs(x - round(x)) < 0.01
|
||||||
|
|
||||||
@ -42,41 +72,40 @@ def compute_pll(hse, sys):
|
|||||||
# improved version that doesn't require N/M to be an integer
|
# improved version that doesn't require N/M to be an integer
|
||||||
def compute_pll2(hse, sys, relax_pll48):
|
def compute_pll2(hse, sys, relax_pll48):
|
||||||
# Loop over the allowed values of P, looking for a valid PLL configuration
|
# 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
|
# that gives the desired "sys" frequency.
|
||||||
# floating point arithmetic on Python 2.
|
|
||||||
fallback = None
|
fallback = None
|
||||||
for P in (2.0, 4.0, 6.0, 8.0):
|
for P in mcu.range_p:
|
||||||
NbyM = sys * P / hse
|
|
||||||
# VCO_OUT must be between 192MHz and 432MHz
|
# VCO_OUT must be between 192MHz and 432MHz
|
||||||
if not (192 <= hse * NbyM <= 432):
|
if not sys * P in mcu.range_vco_out:
|
||||||
continue
|
continue
|
||||||
|
NbyM = float(sys * P) / hse # float for Python 2
|
||||||
# scan M
|
# scan M
|
||||||
M = int(192 // NbyM) # starting value
|
M_min = mcu.range_n[0] // int(round(NbyM)) # starting value
|
||||||
while 2 * M < hse:
|
while mcu.range_vco_in[-1] * M_min < hse:
|
||||||
M += 1
|
M_min += 1
|
||||||
# VCO_IN must be between 1MHz and 2MHz (2MHz recommended)
|
# VCO_IN must be >=1MHz, but higher is better for stability so start high (low M)
|
||||||
for M in range(M, hse + 1):
|
for M in range(M_min, hse + 1):
|
||||||
if NbyM * M < 191.99 or not close_int(NbyM * M):
|
|
||||||
continue
|
|
||||||
# compute N
|
# compute N
|
||||||
N = NbyM * M
|
N = NbyM * M
|
||||||
# N must be an integer
|
# N must be an integer
|
||||||
if not close_int(N):
|
if not close_int(N):
|
||||||
continue
|
continue
|
||||||
|
N = round(N)
|
||||||
# N is restricted
|
# N is restricted
|
||||||
if not (192 <= N <= 432):
|
if N not in mcu.range_n:
|
||||||
continue
|
continue
|
||||||
Q = (sys * P / 48)
|
Q = float(sys * P) / 48 # float for Python 2
|
||||||
# Q must be an integer in a set range
|
# Q must be an integer in a set range
|
||||||
if not (2 <= Q <= 15):
|
if close_int(Q) and round(Q) in mcu.range_q:
|
||||||
|
# found valid values
|
||||||
|
return (M, N, P, Q)
|
||||||
|
# Re-try Q to get at most 48MHz
|
||||||
|
Q = (sys * P + 47) // 48
|
||||||
|
if Q not in mcu.range_q:
|
||||||
continue
|
continue
|
||||||
if not close_int(Q):
|
if fallback is None:
|
||||||
if int(M) == int(hse) and fallback is None:
|
# the values don't give 48MHz on PLL48 but are otherwise OK
|
||||||
# the values don't give 48MHz on PLL48 but are otherwise OK
|
fallback = M, N, P, Q
|
||||||
fallback = M, N, P, int(Q)
|
|
||||||
continue
|
|
||||||
# found valid values
|
|
||||||
return (M, N, P, Q)
|
|
||||||
if relax_pll48:
|
if relax_pll48:
|
||||||
# might have found values which don't give 48MHz on PLL48
|
# might have found values which don't give 48MHz on PLL48
|
||||||
return fallback
|
return fallback
|
||||||
@ -85,6 +114,7 @@ def compute_pll2(hse, sys, relax_pll48):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
def compute_derived(hse, pll):
|
def compute_derived(hse, pll):
|
||||||
|
hse = float(hse) # float for Python 2
|
||||||
M, N, P, Q = pll
|
M, N, P, Q = pll
|
||||||
vco_in = hse / M
|
vco_in = hse / M
|
||||||
vco_out = hse * N / M
|
vco_out = hse * N / M
|
||||||
@ -103,16 +133,16 @@ def verify_pll(hse, pll):
|
|||||||
assert close_int(Q)
|
assert close_int(Q)
|
||||||
|
|
||||||
# verify range
|
# verify range
|
||||||
assert 2 <= M <= 63
|
assert M in mcu.range_m
|
||||||
assert 192 <= N <= 432
|
assert N in mcu.range_n
|
||||||
assert P in (2, 4, 6, 8)
|
assert P in mcu.range_p
|
||||||
assert 2 <= Q <= 15
|
assert Q in mcu.range_q
|
||||||
assert 1 <= vco_in <= 2
|
assert mcu.range_vco_in[0] <= vco_in <= mcu.range_vco_in[-1]
|
||||||
assert 192 <= vco_out <= 432
|
assert mcu.range_vco_out[0] <= vco_out <= mcu.range_vco_out[-1]
|
||||||
|
|
||||||
def compute_pll_table(source_clk, relax_pll48):
|
def compute_pll_table(source_clk, relax_pll48):
|
||||||
valid_plls = []
|
valid_plls = []
|
||||||
for sysclk in range(2, 217, 2):
|
for sysclk in mcu.range_sysclk:
|
||||||
pll = compute_pll2(source_clk, sysclk, relax_pll48)
|
pll = compute_pll2(source_clk, sysclk, relax_pll48)
|
||||||
if pll is not None:
|
if pll is not None:
|
||||||
verify_pll(source_clk, pll)
|
verify_pll(source_clk, pll)
|
||||||
@ -121,10 +151,34 @@ def compute_pll_table(source_clk, relax_pll48):
|
|||||||
|
|
||||||
def generate_c_table(hse, valid_plls):
|
def generate_c_table(hse, valid_plls):
|
||||||
valid_plls.sort()
|
valid_plls.sort()
|
||||||
|
if mcu.range_sysclk[-1] <= 0xff and mcu.range_m[-1] <= 0x3f and mcu.range_p[-1] // 2 - 1 <= 0x3:
|
||||||
|
typedef = 'uint16_t'
|
||||||
|
sys_mask = 0xff
|
||||||
|
m_shift = 10
|
||||||
|
m_mask = 0x3f
|
||||||
|
p_shift = 8
|
||||||
|
p_mask = 0x3
|
||||||
|
else:
|
||||||
|
typedef = 'uint32_t'
|
||||||
|
sys_mask = 0xffff
|
||||||
|
m_shift = 24
|
||||||
|
m_mask = 0xff
|
||||||
|
p_shift = 16
|
||||||
|
p_mask = 0xff
|
||||||
|
print("#define PLL_FREQ_TABLE_SYS(pll) ((pll) & %d)" % (sys_mask,))
|
||||||
|
print("#define PLL_FREQ_TABLE_M(pll) (((pll) >> %d) & %d)" % (m_shift, m_mask))
|
||||||
|
print("#define PLL_FREQ_TABLE_P(pll) (((((pll) >> %d) & %d) + 1) * 2)" % (p_shift, p_mask))
|
||||||
|
print("typedef %s pll_freq_table_t;" % (typedef,))
|
||||||
print("// (M, P/2-1, SYS) values for %u MHz source" % hse)
|
print("// (M, P/2-1, SYS) values for %u MHz source" % hse)
|
||||||
print("static const uint16_t pll_freq_table[%u] = {" % len(valid_plls))
|
print("static const pll_freq_table_t pll_freq_table[%u] = {" % (len(valid_plls),))
|
||||||
for sys, (M, N, P, Q) in valid_plls:
|
for sys, (M, N, P, Q) in valid_plls:
|
||||||
print(" (%u << 10) | (%u << 8) | %u," % (M, P // 2 - 1, sys))
|
print(" (%u << %u) | (%u << %u) | %u," % (M, m_shift, P // 2 - 1, p_shift, sys), end='')
|
||||||
|
if M >= 2:
|
||||||
|
vco_in, vco_out, pllck, pll48ck = compute_derived(hse, (M, N, P, Q))
|
||||||
|
print(" // M=%u N=%u P=%u Q=%u vco_in=%.2f vco_out=%.2f pll48=%.2f"
|
||||||
|
% (M, N, P, Q, vco_in, vco_out, pll48ck), end=''
|
||||||
|
)
|
||||||
|
print()
|
||||||
print("};")
|
print("};")
|
||||||
|
|
||||||
def print_table(hse, valid_plls):
|
def print_table(hse, valid_plls):
|
||||||
@ -157,6 +211,7 @@ def search_header_for_hsx_values(filename, vals):
|
|||||||
return vals
|
return vals
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
global mcu
|
||||||
global out_format
|
global out_format
|
||||||
|
|
||||||
# parse input args
|
# parse input args
|
||||||
@ -164,7 +219,7 @@ def main():
|
|||||||
argv = sys.argv[1:]
|
argv = sys.argv[1:]
|
||||||
|
|
||||||
c_table = False
|
c_table = False
|
||||||
relax_pll48 = False
|
mcu_series = 'f4'
|
||||||
hse = None
|
hse = None
|
||||||
hsi = None
|
hsi = None
|
||||||
|
|
||||||
@ -172,14 +227,14 @@ def main():
|
|||||||
if argv[0] == '-c':
|
if argv[0] == '-c':
|
||||||
c_table = True
|
c_table = True
|
||||||
argv.pop(0)
|
argv.pop(0)
|
||||||
elif argv[0] == '--relax-pll48':
|
elif argv[0] == '-m':
|
||||||
relax_pll48 = True
|
|
||||||
argv.pop(0)
|
argv.pop(0)
|
||||||
|
mcu_series = argv.pop(0).lower()
|
||||||
else:
|
else:
|
||||||
break
|
break
|
||||||
|
|
||||||
if len(argv) != 1:
|
if len(argv) != 1:
|
||||||
print("usage: pllvalues.py [-c] <hse in MHz>")
|
print("usage: pllvalues.py [-c] [-m <mcu_series>] <hse in MHz>")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
if argv[0].startswith("file:"):
|
if argv[0].startswith("file:"):
|
||||||
@ -194,6 +249,15 @@ def main():
|
|||||||
# HSE given directly as an integer
|
# HSE given directly as an integer
|
||||||
hse = int(argv[0])
|
hse = int(argv[0])
|
||||||
|
|
||||||
|
# Select MCU parameters
|
||||||
|
if mcu_series == 'h7':
|
||||||
|
mcu = mcu_h7
|
||||||
|
else:
|
||||||
|
mcu = mcu_default
|
||||||
|
|
||||||
|
# Relax constraight on PLLQ being 48MHz on F7 and H7 MCUs, which have separate PLLs for 48MHz
|
||||||
|
relax_pll48 = mcu_series in ('f7', 'h7')
|
||||||
|
|
||||||
hse_valid_plls = compute_pll_table(hse, relax_pll48)
|
hse_valid_plls = compute_pll_table(hse, relax_pll48)
|
||||||
if hsi is not None:
|
if hsi is not None:
|
||||||
hsi_valid_plls = compute_pll_table(hsi, relax_pll48)
|
hsi_valid_plls = compute_pll_table(hsi, relax_pll48)
|
||||||
|
@ -310,6 +310,11 @@ STATIC mp_obj_t machine_freq(size_t n_args, const mp_obj_t *args) {
|
|||||||
#else
|
#else
|
||||||
mp_int_t sysclk = mp_obj_get_int(args[0]);
|
mp_int_t sysclk = mp_obj_get_int(args[0]);
|
||||||
mp_int_t ahb = sysclk;
|
mp_int_t ahb = sysclk;
|
||||||
|
#if defined (STM32H7)
|
||||||
|
if (ahb > 200000000) {
|
||||||
|
ahb /= 2;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
mp_int_t apb1 = ahb / 4;
|
mp_int_t apb1 = ahb / 4;
|
||||||
mp_int_t apb2 = ahb / 2;
|
mp_int_t apb2 = ahb / 2;
|
||||||
if (n_args > 1) {
|
if (n_args > 1) {
|
||||||
|
@ -93,12 +93,48 @@ void powerctrl_check_enter_bootloader(void) {
|
|||||||
|
|
||||||
#if !defined(STM32F0) && !defined(STM32L0) && !defined(STM32WB)
|
#if !defined(STM32F0) && !defined(STM32L0) && !defined(STM32WB)
|
||||||
|
|
||||||
|
typedef struct _sysclk_scaling_table_entry_t {
|
||||||
|
uint16_t mhz;
|
||||||
|
uint16_t value;
|
||||||
|
} sysclk_scaling_table_entry_t;
|
||||||
|
|
||||||
|
#if defined(STM32F7)
|
||||||
|
STATIC const sysclk_scaling_table_entry_t volt_scale_table[] = {
|
||||||
|
{ 151, PWR_REGULATOR_VOLTAGE_SCALE3 },
|
||||||
|
{ 180, PWR_REGULATOR_VOLTAGE_SCALE2 },
|
||||||
|
// Above 180MHz uses default PWR_REGULATOR_VOLTAGE_SCALE1
|
||||||
|
};
|
||||||
|
#elif defined(STM32H7)
|
||||||
|
STATIC const sysclk_scaling_table_entry_t volt_scale_table[] = {
|
||||||
|
// See table 55 "Kernel clock distribution overview" of RM0433.
|
||||||
|
{200, PWR_REGULATOR_VOLTAGE_SCALE3},
|
||||||
|
{300, PWR_REGULATOR_VOLTAGE_SCALE2},
|
||||||
|
// Above 300MHz uses default PWR_REGULATOR_VOLTAGE_SCALE1
|
||||||
|
// (above 400MHz needs special handling for overdrive, currently unsupported)
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
STATIC int powerctrl_config_vos(uint32_t sysclk_mhz) {
|
||||||
|
#if defined(STM32F7) || defined(STM32H7)
|
||||||
|
uint32_t volt_scale = PWR_REGULATOR_VOLTAGE_SCALE1;
|
||||||
|
for (int i = 0; i < MP_ARRAY_SIZE(volt_scale_table); ++i) {
|
||||||
|
if (sysclk_mhz <= volt_scale_table[i].mhz) {
|
||||||
|
volt_scale = volt_scale_table[i].value;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (HAL_PWREx_ControlVoltageScaling(volt_scale) != HAL_OK) {
|
||||||
|
return -MP_EIO;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
// Assumes that PLL is used as the SYSCLK source
|
// 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_pllsai) {
|
||||||
uint32_t flash_latency;
|
uint32_t flash_latency;
|
||||||
|
|
||||||
#if defined(STM32F7)
|
#if defined(STM32F7)
|
||||||
|
|
||||||
if (need_pllsai) {
|
if (need_pllsai) {
|
||||||
// Configure PLLSAI at 48MHz for those peripherals that need this freq
|
// Configure PLLSAI at 48MHz for those peripherals that need this freq
|
||||||
// (calculation assumes it can get an integral value of PLLSAIN)
|
// (calculation assumes it can get an integral value of PLLSAIN)
|
||||||
@ -118,20 +154,16 @@ int powerctrl_rcc_clock_config_pll(RCC_ClkInitTypeDef *rcc_init, uint32_t sysclk
|
|||||||
}
|
}
|
||||||
RCC->DCKCFGR2 |= RCC_DCKCFGR2_CK48MSEL;
|
RCC->DCKCFGR2 |= RCC_DCKCFGR2_CK48MSEL;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// If possible, scale down the internal voltage regulator to save power
|
// If possible, scale down the internal voltage regulator to save power
|
||||||
uint32_t volt_scale;
|
int ret = powerctrl_config_vos(sysclk_mhz);
|
||||||
if (sysclk_mhz <= 151) {
|
if (ret) {
|
||||||
volt_scale = PWR_REGULATOR_VOLTAGE_SCALE3;
|
return ret;
|
||||||
} else if (sysclk_mhz <= 180) {
|
|
||||||
volt_scale = PWR_REGULATOR_VOLTAGE_SCALE2;
|
|
||||||
} else {
|
|
||||||
volt_scale = PWR_REGULATOR_VOLTAGE_SCALE1;
|
|
||||||
}
|
|
||||||
if (HAL_PWREx_ControlVoltageScaling(volt_scale) != HAL_OK) {
|
|
||||||
return -MP_EIO;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(STM32F7)
|
||||||
|
|
||||||
// These flash_latency values assume a supply voltage between 2.7V and 3.6V
|
// These flash_latency values assume a supply voltage between 2.7V and 3.6V
|
||||||
if (sysclk_mhz <= 30) {
|
if (sysclk_mhz <= 30) {
|
||||||
flash_latency = FLASH_LATENCY_0;
|
flash_latency = FLASH_LATENCY_0;
|
||||||
@ -172,6 +204,17 @@ int powerctrl_rcc_clock_config_pll(RCC_ClkInitTypeDef *rcc_init, uint32_t sysclk
|
|||||||
#if !defined(STM32F0) && !defined(STM32L0) && !defined(STM32L4) && !defined(STM32WB)
|
#if !defined(STM32F0) && !defined(STM32L0) && !defined(STM32L4) && !defined(STM32WB)
|
||||||
|
|
||||||
STATIC uint32_t calc_ahb_div(uint32_t wanted_div) {
|
STATIC uint32_t calc_ahb_div(uint32_t wanted_div) {
|
||||||
|
#if defined(STM32H7)
|
||||||
|
if (wanted_div <= 1) { return RCC_HCLK_DIV1; }
|
||||||
|
else if (wanted_div <= 2) { return RCC_HCLK_DIV2; }
|
||||||
|
else if (wanted_div <= 4) { return RCC_HCLK_DIV4; }
|
||||||
|
else if (wanted_div <= 8) { return RCC_HCLK_DIV8; }
|
||||||
|
else if (wanted_div <= 16) { return RCC_HCLK_DIV16; }
|
||||||
|
else if (wanted_div <= 64) { return RCC_HCLK_DIV64; }
|
||||||
|
else if (wanted_div <= 128) { return RCC_HCLK_DIV128; }
|
||||||
|
else if (wanted_div <= 256) { return RCC_HCLK_DIV256; }
|
||||||
|
else { return RCC_HCLK_DIV512; }
|
||||||
|
#else
|
||||||
if (wanted_div <= 1) { return RCC_SYSCLK_DIV1; }
|
if (wanted_div <= 1) { return RCC_SYSCLK_DIV1; }
|
||||||
else if (wanted_div <= 2) { return RCC_SYSCLK_DIV2; }
|
else if (wanted_div <= 2) { return RCC_SYSCLK_DIV2; }
|
||||||
else if (wanted_div <= 4) { return RCC_SYSCLK_DIV4; }
|
else if (wanted_div <= 4) { return RCC_SYSCLK_DIV4; }
|
||||||
@ -181,14 +224,35 @@ STATIC uint32_t calc_ahb_div(uint32_t wanted_div) {
|
|||||||
else if (wanted_div <= 128) { return RCC_SYSCLK_DIV128; }
|
else if (wanted_div <= 128) { return RCC_SYSCLK_DIV128; }
|
||||||
else if (wanted_div <= 256) { return RCC_SYSCLK_DIV256; }
|
else if (wanted_div <= 256) { return RCC_SYSCLK_DIV256; }
|
||||||
else { return RCC_SYSCLK_DIV512; }
|
else { return RCC_SYSCLK_DIV512; }
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
STATIC uint32_t calc_apb_div(uint32_t wanted_div) {
|
STATIC uint32_t calc_apb1_div(uint32_t wanted_div) {
|
||||||
|
#if defined(STM32H7)
|
||||||
|
if (wanted_div <= 1) { return RCC_APB1_DIV1; }
|
||||||
|
else if (wanted_div <= 2) { return RCC_APB1_DIV2; }
|
||||||
|
else if (wanted_div <= 4) { return RCC_APB1_DIV4; }
|
||||||
|
else if (wanted_div <= 8) { return RCC_APB1_DIV8; }
|
||||||
|
else { return RCC_APB1_DIV16; }
|
||||||
|
#else
|
||||||
if (wanted_div <= 1) { return RCC_HCLK_DIV1; }
|
if (wanted_div <= 1) { return RCC_HCLK_DIV1; }
|
||||||
else if (wanted_div <= 2) { return RCC_HCLK_DIV2; }
|
else if (wanted_div <= 2) { return RCC_HCLK_DIV2; }
|
||||||
else if (wanted_div <= 4) { return RCC_HCLK_DIV4; }
|
else if (wanted_div <= 4) { return RCC_HCLK_DIV4; }
|
||||||
else if (wanted_div <= 8) { return RCC_HCLK_DIV8; }
|
else if (wanted_div <= 8) { return RCC_HCLK_DIV8; }
|
||||||
else { return RCC_SYSCLK_DIV16; }
|
else { return RCC_HCLK_DIV16; }
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
STATIC uint32_t calc_apb2_div(uint32_t wanted_div) {
|
||||||
|
#if defined(STM32H7)
|
||||||
|
if (wanted_div <= 1) { return RCC_APB2_DIV1; }
|
||||||
|
else if (wanted_div <= 2) { return RCC_APB2_DIV2; }
|
||||||
|
else if (wanted_div <= 4) { return RCC_APB2_DIV4; }
|
||||||
|
else if (wanted_div <= 8) { return RCC_APB2_DIV8; }
|
||||||
|
else { return RCC_APB2_DIV16; }
|
||||||
|
#else
|
||||||
|
return calc_apb1_div(wanted_div);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
int powerctrl_set_sysclk(uint32_t sysclk, uint32_t ahb, uint32_t apb1, uint32_t apb2) {
|
int powerctrl_set_sysclk(uint32_t sysclk, uint32_t ahb, uint32_t apb1, uint32_t apb2) {
|
||||||
@ -207,11 +271,11 @@ int powerctrl_set_sysclk(uint32_t sysclk, uint32_t ahb, uint32_t apb1, uint32_t
|
|||||||
|
|
||||||
// Search for a valid PLL configuration that keeps USB at 48MHz
|
// Search for a valid PLL configuration that keeps USB at 48MHz
|
||||||
uint32_t sysclk_mhz = sysclk / 1000000;
|
uint32_t sysclk_mhz = sysclk / 1000000;
|
||||||
for (const uint16_t *pll = &pll_freq_table[MP_ARRAY_SIZE(pll_freq_table) - 1]; pll >= &pll_freq_table[0]; --pll) {
|
for (const pll_freq_table_t *pll = &pll_freq_table[MP_ARRAY_SIZE(pll_freq_table) - 1]; pll >= &pll_freq_table[0]; --pll) {
|
||||||
uint32_t sys = *pll & 0xff;
|
uint32_t sys = PLL_FREQ_TABLE_SYS(*pll);
|
||||||
if (sys <= sysclk_mhz) {
|
if (sys <= sysclk_mhz) {
|
||||||
m = (*pll >> 10) & 0x3f;
|
m = PLL_FREQ_TABLE_M(*pll);
|
||||||
p = ((*pll >> 7) & 0x6) + 2;
|
p = PLL_FREQ_TABLE_P(*pll);
|
||||||
if (m == 0) {
|
if (m == 0) {
|
||||||
// special entry for using HSI directly
|
// special entry for using HSI directly
|
||||||
sysclk_source = RCC_SYSCLKSOURCE_HSI;
|
sysclk_source = RCC_SYSCLKSOURCE_HSI;
|
||||||
@ -259,8 +323,13 @@ set_clk:
|
|||||||
#if !defined(STM32H7)
|
#if !defined(STM32H7)
|
||||||
ahb = sysclk >> AHBPrescTable[RCC_ClkInitStruct.AHBCLKDivider >> RCC_CFGR_HPRE_Pos];
|
ahb = sysclk >> AHBPrescTable[RCC_ClkInitStruct.AHBCLKDivider >> RCC_CFGR_HPRE_Pos];
|
||||||
#endif
|
#endif
|
||||||
RCC_ClkInitStruct.APB1CLKDivider = calc_apb_div(ahb / apb1);
|
RCC_ClkInitStruct.APB1CLKDivider = calc_apb1_div(ahb / apb1);
|
||||||
RCC_ClkInitStruct.APB2CLKDivider = calc_apb_div(ahb / apb2);
|
RCC_ClkInitStruct.APB2CLKDivider = calc_apb2_div(ahb / apb2);
|
||||||
|
#if defined(STM32H7)
|
||||||
|
RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1;
|
||||||
|
RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV2;
|
||||||
|
RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV2;
|
||||||
|
#endif
|
||||||
|
|
||||||
#if MICROPY_HW_CLK_LAST_FREQ
|
#if MICROPY_HW_CLK_LAST_FREQ
|
||||||
// Save the bus dividers for use later
|
// Save the bus dividers for use later
|
||||||
@ -294,6 +363,26 @@ set_clk:
|
|||||||
RCC_OscInitStruct.PLL.PLLN = n;
|
RCC_OscInitStruct.PLL.PLLN = n;
|
||||||
RCC_OscInitStruct.PLL.PLLP = p;
|
RCC_OscInitStruct.PLL.PLLP = p;
|
||||||
RCC_OscInitStruct.PLL.PLLQ = q;
|
RCC_OscInitStruct.PLL.PLLQ = q;
|
||||||
|
|
||||||
|
#if defined(STM32H7)
|
||||||
|
RCC_OscInitStruct.PLL.PLLR = 0;
|
||||||
|
if (MICROPY_HW_CLK_VALUE / 1000000 <= 2 * m) {
|
||||||
|
RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_0; // 1-2MHz
|
||||||
|
} else if (MICROPY_HW_CLK_VALUE / 1000000 <= 4 * m) {
|
||||||
|
RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_1; // 2-4MHz
|
||||||
|
} else if (MICROPY_HW_CLK_VALUE / 1000000 <= 8 * m) {
|
||||||
|
RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_2; // 4-8MHz
|
||||||
|
} else {
|
||||||
|
RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_3; // 8-16MHz
|
||||||
|
}
|
||||||
|
if (MICROPY_HW_CLK_VALUE / 1000000 * n <= 420 * m) {
|
||||||
|
RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOMEDIUM; // 150-420MHz
|
||||||
|
} else {
|
||||||
|
RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE; // 192-960MHz
|
||||||
|
}
|
||||||
|
RCC_OscInitStruct.PLL.PLLFRACN = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
|
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
|
||||||
return -MP_EIO;
|
return -MP_EIO;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user