summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--stmhal/Makefile7
-rw-r--r--stmhal/boards/pllvalues.py77
-rw-r--r--stmhal/modmachine.c71
3 files changed, 89 insertions, 66 deletions
diff --git a/stmhal/Makefile b/stmhal/Makefile
index 8735d84c3..8bdb07b1e 100644
--- a/stmhal/Makefile
+++ b/stmhal/Makefile
@@ -397,6 +397,7 @@ $(BUILD)/firmware.elf: $(OBJ)
$(Q)$(LD) $(LDFLAGS) -o $@ $^ $(LIBS)
$(Q)$(SIZE) $@
+PLLVALUES = boards/pllvalues.py
MAKE_PINS = boards/make-pins.py
BOARD_PINS = boards/$(BOARD)/pins.csv
PREFIX_FILE = boards/stm32f4xx_prefix.c
@@ -443,12 +444,18 @@ $(BUILD)/%_$(BOARD).c $(HEADER_BUILD)/%.h $(HEADER_BUILD)/%_af_const.h $(BUILD)/
$(BUILD)/pins_$(BOARD).o: $(BUILD)/pins_$(BOARD).c
$(call compile_c)
+GEN_PLLFREQTABLE_HDR = $(HEADER_BUILD)/pllfreqtable.h
GEN_STMCONST_HDR = $(HEADER_BUILD)/modstm_const.h
GEN_STMCONST_QSTR = $(BUILD)/modstm_qstr.h
GEN_STMCONST_MPZ = $(HEADER_BUILD)/modstm_mpz.h
CMSIS_MCU_LOWER = $(shell echo $(CMSIS_MCU) | tr '[:upper:]' '[:lower:]')
CMSIS_MCU_HDR = cmsis/$(CMSIS_MCU_LOWER).h
+modmachine.c: $(GEN_PLLFREQTABLE_HDR)
+$(GEN_PLLFREQTABLE_HDR): $(PLLVALUES) | $(HEADER_BUILD)
+ $(ECHO) "Create $@"
+ $(Q)$(PYTHON) $(PLLVALUES) -c file:boards/$(BOARD)/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
# make both modstm_const.h and modstm_qstr.h
diff --git a/stmhal/boards/pllvalues.py b/stmhal/boards/pllvalues.py
index 183313f30..e930ae87d 100644
--- a/stmhal/boards/pllvalues.py
+++ b/stmhal/boards/pllvalues.py
@@ -67,14 +67,17 @@ def compute_pll2(hse, sys):
# no valid values found
return None
-def verify_and_print_pll(hse, sys, pll):
+def compute_derived(hse, pll):
M, N, P, Q = pll
-
- # compute derived quantities
vco_in = hse / M
vco_out = hse * N / M
pllck = hse / M * N / P
pll48ck = hse / M * N / Q
+ return (vco_in, vco_out, pllck, pll48ck)
+
+def verify_pll(hse, pll):
+ M, N, P, Q = pll
+ vco_in, vco_out, pllck, pll48ck = compute_derived(hse, pll)
# verify ints
assert close_int(M)
@@ -90,26 +93,68 @@ def verify_and_print_pll(hse, sys, pll):
assert 1 <= vco_in <= 2
assert 192 <= vco_out <= 432
- # print out values
- print(out_format % (sys, M, N, P, Q, vco_in, vco_out, pllck, pll48ck))
+def generate_c_table(hse, valid_plls):
+ valid_plls = valid_plls + [(16, (0, 0, 2, 0))]
+ if hse < 16:
+ valid_plls.append((hse, (1, 0, 2, 0)))
+ valid_plls.sort()
+ print("// (M, P/2-1, SYS) values for %u MHz HSE" % hse)
+ print("static const uint16_t pll_freq_table[%u] = {" % len(valid_plls))
+ for sys, (M, N, P, Q) in valid_plls:
+ print(" (%u << 10) | (%u << 8) | %u," % (M, P // 2 - 1, sys))
+ print("};")
+
+def print_table(hse, valid_plls):
+ print("HSE =", hse, "MHz")
+ print("sys : M N P Q : VCO_IN VCO_OUT PLLCK PLL48CK")
+ out_format = "%3u : %2u %.1f %.2f %.2f : %5.2f %6.2f %6.2f %6.2f"
+ for sys, pll in valid_plls:
+ print(out_format % ((sys,) + pll + compute_derived(hse, pll)))
+ print("found %u valid configurations" % len(valid_plls))
def main():
global out_format
+
+ # parse input args
import sys
- if len(sys.argv) != 2:
- print("usage: pllvalues.py <hse in MHz>")
+ argv = sys.argv[1:]
+
+ c_table = False
+ if argv[0] == '-c':
+ c_table = True
+ argv.pop(0)
+
+ if len(argv) != 1:
+ print("usage: pllvalues.py [-c] <hse in MHz>")
sys.exit(1)
- hse_value = int(sys.argv[1])
- print("HSE =", hse_value, "MHz")
- print("sys : M N P Q : VCO_IN VCO_OUT PLLCK PLL48CK")
- out_format = "%3u : %2u %.1f %.2f %.2f : %5.2f %6.2f %6.2f %6.2f"
- n_valid = 0
+
+ if argv[0].startswith("file:"):
+ # extract HSE_VALUE from header file
+ with open(argv[0][5:]) as f:
+ for line in f:
+ line = line.strip()
+ if line.startswith("#define") and line.find("HSE_VALUE") != -1:
+ idx_start = line.find("((uint32_t)") + 11
+ idx_end = line.find(")", idx_start)
+ hse = int(line[idx_start:idx_end]) // 1000000
+ break
+ else:
+ raise ValueError("%s does not contain a definition of HSE_VALUE" % argv[0])
+ else:
+ # HSE given directly as an integer
+ hse = int(argv[0])
+
+ valid_plls = []
for sysclk in range(1, 217):
- pll = compute_pll2(hse_value, sysclk)
+ pll = compute_pll2(hse, sysclk)
if pll is not None:
- n_valid += 1
- verify_and_print_pll(hse_value, sysclk, pll)
- print("found %u valid configurations" % n_valid)
+ verify_pll(hse, pll)
+ valid_plls.append((sysclk, pll))
+
+ if c_table:
+ generate_c_table(hse, valid_plls)
+ else:
+ print_table(hse, valid_plls)
if __name__ == "__main__":
main()
diff --git a/stmhal/modmachine.c b/stmhal/modmachine.c
index bcbf43fde..df75d393c 100644
--- a/stmhal/modmachine.c
+++ b/stmhal/modmachine.c
@@ -52,6 +52,7 @@
#include "spi.h"
#include "uart.h"
#include "wdt.h"
+#include "genhdr/pllfreqtable.h"
#if defined(MCU_SERIES_F4)
// the HAL does not define these constants
@@ -276,61 +277,31 @@ STATIC mp_obj_t machine_freq(mp_uint_t n_args, const mp_obj_t *args) {
uint32_t m = HSE_VALUE / 1000000, n = 336, p = 2, q = 7;
uint32_t sysclk_source;
- // the following logic assumes HSE < HSI
- if (HSE_VALUE / 1000000 <= wanted_sysclk && wanted_sysclk < HSI_VALUE / 1000000) {
- // use HSE as SYSCLK
- sysclk_source = RCC_SYSCLKSOURCE_HSE;
- } else if (HSI_VALUE / 1000000 <= wanted_sysclk && wanted_sysclk < 24) {
- // use HSI as SYSCLK
- sysclk_source = RCC_SYSCLKSOURCE_HSI;
- } else {
- // search for a valid PLL configuration that keeps USB at 48MHz
- for (; wanted_sysclk > 0; wanted_sysclk--) {
- for (p = 2; p <= 8; p += 2) {
- // compute VCO_OUT
- mp_uint_t vco_out = wanted_sysclk * p;
- // make sure VCO_OUT is between 192MHz and 432MHz
- if (vco_out < 192 || vco_out > 432) {
- continue;
- }
- // make sure Q is an integer
- if (vco_out % 48 != 0) {
- continue;
- }
- // solve for Q to get PLL48CK at 48MHz
- q = vco_out / 48;
- // make sure Q is in range
- if (q < 2 || q > 15) {
- continue;
- }
- // make sure N/M is an integer
- if (vco_out % (HSE_VALUE / 1000000) != 0) {
- continue;
- }
- // solve for N/M
- mp_uint_t n_by_m = vco_out / (HSE_VALUE / 1000000);
- // solve for M, making sure VCO_IN (=HSE/M) is between 1MHz and 2MHz
- m = 192 / n_by_m;
- while (m < (HSE_VALUE / 2000000) || n_by_m * m < 192) {
- m += 1;
- }
- if (m > (HSE_VALUE / 1000000)) {
- continue;
- }
- // solve for N
- n = n_by_m * m;
- // make sure N is in range
- if (n < 192 || n > 432) {
- continue;
- }
-
- // found values!
+ // 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) {
+ uint32_t sys = *pll & 0xff;
+ if (sys <= wanted_sysclk) {
+ m = (*pll >> 10) & 0x3f;
+ p = ((*pll >> 7) & 0x6) + 2;
+ if (m == 0) {
+ // special entry for using HSI directly
+ sysclk_source = RCC_SYSCLKSOURCE_HSI;
+ goto set_clk;
+ } else if (m == 1) {
+ // special entry for using HSE directly
+ sysclk_source = RCC_SYSCLKSOURCE_HSE;
+ goto set_clk;
+ } else {
+ // use PLL
sysclk_source = RCC_SYSCLKSOURCE_PLLCLK;
+ uint32_t vco_out = sys * p;
+ n = vco_out * m / (HSE_VALUE / 1000000);
+ q = vco_out / 48;
goto set_clk;
}
}
- mp_raise_ValueError("can't make valid freq");
}
+ mp_raise_ValueError("can't make valid freq");
set_clk:
//printf("%lu %lu %lu %lu %lu\n", sysclk_source, m, n, p, q);