diff --git a/stmhal/boards/pllvalues.py b/stmhal/boards/pllvalues.py new file mode 100644 index 000000000..183313f30 --- /dev/null +++ b/stmhal/boards/pllvalues.py @@ -0,0 +1,115 @@ +""" +This is an auxiliary script that is used to compute valid PLL values to set +the CPU frequency to a given value. The algorithm here appears as C code +for the machine.freq() function. +""" + +def close_int(x): + return abs(x - round(x)) < 0.01 + +# original version that requires N/M to be an integer (for simplicity) +def compute_pll(hse, sys): + for P in (2, 4, 6, 8): # allowed values of P + Q = sys * P / 48 + NbyM = sys * P / hse + # N/M and Q must be integers + if not (close_int(NbyM) and close_int(Q)): + continue + # VCO_OUT must be between 192MHz and 432MHz + if not (192 <= hse * NbyM <= 432): + continue + # compute M + M = int(192 // NbyM) + while hse > 2 * M or NbyM * M < 192: + M += 1 + # VCO_IN must be between 1MHz and 2MHz (2MHz recommended) + if not (M <= hse): + continue + # compute N + N = NbyM * M + # N and Q are restricted + if not (192 <= N <= 432 and 2 <= Q <= 15): + continue + # found valid values + assert NbyM == N // M + return (M, N, P, Q) + # no valid values found + return None + +# improved version that doesn't require N/M to be an integer +def compute_pll2(hse, sys): + for P in (2, 4, 6, 8): # allowed values of P + 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): + 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 + +def verify_and_print_pll(hse, sys, 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 + + # verify ints + assert close_int(M) + assert close_int(N) + assert close_int(P) + assert close_int(Q) + + # verify range + assert 2 <= M <= 63 + assert 192 <= N <= 432 + assert P in (2, 4, 6, 8) + assert 2 <= Q <= 15 + 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 main(): + global out_format + import sys + if len(sys.argv) != 2: + print("usage: pllvalues.py ") + 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 + for sysclk in range(1, 217): + pll = compute_pll2(hse_value, sysclk) + if pll is not None: + n_valid += 1 + verify_and_print_pll(hse_value, sysclk, pll) + print("found %u valid configurations" % n_valid) + +if __name__ == "__main__": + main()