summaryrefslogtreecommitdiffstatshomepage
path: root/stmhal/boards/pllvalues.py
blob: 183313f304f43b770f3977d4d6080eb911764b0c (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
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 <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
    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()