pllvalues.py 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. """
  2. This is an auxiliary script that is used to compute valid PLL values to set
  3. the CPU frequency to a given value. The algorithm here appears as C code
  4. for the machine.freq() function.
  5. """
  6. from __future__ import print_function
  7. def close_int(x):
  8. return abs(x - round(x)) < 0.01
  9. # original version that requires N/M to be an integer (for simplicity)
  10. def compute_pll(hse, sys):
  11. for P in (2, 4, 6, 8): # allowed values of P
  12. Q = sys * P / 48
  13. NbyM = sys * P / hse
  14. # N/M and Q must be integers
  15. if not (close_int(NbyM) and close_int(Q)):
  16. continue
  17. # VCO_OUT must be between 192MHz and 432MHz
  18. if not (192 <= hse * NbyM <= 432):
  19. continue
  20. # compute M
  21. M = int(192 // NbyM)
  22. while hse > 2 * M or NbyM * M < 192:
  23. M += 1
  24. # VCO_IN must be between 1MHz and 2MHz (2MHz recommended)
  25. if not (M <= hse):
  26. continue
  27. # compute N
  28. N = NbyM * M
  29. # N and Q are restricted
  30. if not (192 <= N <= 432 and 2 <= Q <= 15):
  31. continue
  32. # found valid values
  33. assert NbyM == N // M
  34. return (M, N, P, Q)
  35. # no valid values found
  36. return None
  37. # improved version that doesn't require N/M to be an integer
  38. def compute_pll2(hse, sys):
  39. # Loop over the allowed values of P, looking for a valid PLL configuration
  40. # that gives the desired "sys" frequency. We use floats for P to force
  41. # floating point arithmetic on Python 2.
  42. for P in (2.0, 4.0, 6.0, 8.0):
  43. Q = sys * P / 48
  44. # Q must be an integer in a set range
  45. if not (close_int(Q) and 2 <= Q <= 15):
  46. continue
  47. NbyM = sys * P / hse
  48. # VCO_OUT must be between 192MHz and 432MHz
  49. if not (192 <= hse * NbyM <= 432):
  50. continue
  51. # compute M
  52. M = 192 // NbyM # starting value
  53. while hse > 2 * M or NbyM * M < 192 or not close_int(NbyM * M):
  54. M += 1
  55. # VCO_IN must be between 1MHz and 2MHz (2MHz recommended)
  56. if not (M <= hse):
  57. continue
  58. # compute N
  59. N = NbyM * M
  60. # N must be an integer
  61. if not close_int(N):
  62. continue
  63. # N is restricted
  64. if not (192 <= N <= 432):
  65. continue
  66. # found valid values
  67. return (M, N, P, Q)
  68. # no valid values found
  69. return None
  70. def compute_derived(hse, pll):
  71. M, N, P, Q = pll
  72. vco_in = hse / M
  73. vco_out = hse * N / M
  74. pllck = hse / M * N / P
  75. pll48ck = hse / M * N / Q
  76. return (vco_in, vco_out, pllck, pll48ck)
  77. def verify_pll(hse, pll):
  78. M, N, P, Q = pll
  79. vco_in, vco_out, pllck, pll48ck = compute_derived(hse, pll)
  80. # verify ints
  81. assert close_int(M)
  82. assert close_int(N)
  83. assert close_int(P)
  84. assert close_int(Q)
  85. # verify range
  86. assert 2 <= M <= 63
  87. assert 192 <= N <= 432
  88. assert P in (2, 4, 6, 8)
  89. assert 2 <= Q <= 15
  90. assert 1 <= vco_in <= 2
  91. assert 192 <= vco_out <= 432
  92. def generate_c_table(hse, valid_plls):
  93. valid_plls = valid_plls + [(16, (0, 0, 2, 0))]
  94. if hse < 16:
  95. valid_plls.append((hse, (1, 0, 2, 0)))
  96. valid_plls.sort()
  97. print("// (M, P/2-1, SYS) values for %u MHz HSE" % hse)
  98. print("static const uint16_t pll_freq_table[%u] = {" % len(valid_plls))
  99. for sys, (M, N, P, Q) in valid_plls:
  100. print(" (%u << 10) | (%u << 8) | %u," % (M, P // 2 - 1, sys))
  101. print("};")
  102. def print_table(hse, valid_plls):
  103. print("HSE =", hse, "MHz")
  104. print("sys : M N P Q : VCO_IN VCO_OUT PLLCK PLL48CK")
  105. out_format = "%3u : %2u %.1f %.2f %.2f : %5.2f %6.2f %6.2f %6.2f"
  106. for sys, pll in valid_plls:
  107. print(out_format % ((sys,) + pll + compute_derived(hse, pll)))
  108. print("found %u valid configurations" % len(valid_plls))
  109. def main():
  110. global out_format
  111. # parse input args
  112. import sys
  113. argv = sys.argv[1:]
  114. c_table = False
  115. if argv[0] == '-c':
  116. c_table = True
  117. argv.pop(0)
  118. if len(argv) != 1:
  119. print("usage: pllvalues.py [-c] <hse in MHz>")
  120. sys.exit(1)
  121. if argv[0].startswith("file:"):
  122. # extract HSE_VALUE from header file
  123. with open(argv[0][5:]) as f:
  124. for line in f:
  125. line = line.strip()
  126. if line.startswith("#define") and line.find("HSE_VALUE") != -1:
  127. idx_start = line.find("((uint32_t)") + 11
  128. idx_end = line.find(")", idx_start)
  129. hse = int(line[idx_start:idx_end]) // 1000000
  130. break
  131. else:
  132. raise ValueError("%s does not contain a definition of HSE_VALUE" % argv[0])
  133. else:
  134. # HSE given directly as an integer
  135. hse = int(argv[0])
  136. valid_plls = []
  137. for sysclk in range(1, 217):
  138. pll = compute_pll2(hse, sysclk)
  139. if pll is not None:
  140. verify_pll(hse, pll)
  141. valid_plls.append((sysclk, pll))
  142. if c_table:
  143. generate_c_table(hse, valid_plls)
  144. else:
  145. print_table(hse, valid_plls)
  146. if __name__ == "__main__":
  147. main()