Skip to content

Instantly share code, notes, and snippets.

@andy-shev
Last active August 29, 2015 14:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save andy-shev/8b2a73aeca2874f4cc89 to your computer and use it in GitHub Desktop.
Save andy-shev/8b2a73aeca2874f4cc89 to your computer and use it in GitHub Desktop.
Fractional divider calculator
#!/usr/bin/python -tt
# -*- coding: UTF-8 -*-
# vim: ts=4 sw=4 et ai si
import sys
import os
import operator
import math
import fractions
# See also: https://gist.github.com/endolith/114336
__author__ = "Andy Shevchenko"
__license__ = "GPL v2"
PROG = os.path.basename(sys.argv[0])
BAUDRATES = [
# Group 0
110,
134,
# Group 1
50,
75,
150,
200,
300,
600,
1200,
1800,
2400,
4800,
9600,
19200,
38400,
57600,
115200,
230400,
460800,
921600,
1843200,
# Group 2
576000,
1152000,
# Group 3
500000,
1000000,
1500000,
2000000,
2500000,
3000000,
3500000,
4000000,
]
XTAL = 38400000
PS = 16
RW = 14
ALGO = 1
#
# Fref = XTAL * m / n
# uartclk = Fuart * 16 / ps
# baud = uartclk / (ps * DLAB)
#
def go(xtal, baud, rw, ps, algo):
#
# Iterative
#
# while True:
# fuart = baud * ps
# if fuart < xtal:
# break
# ps -= 1
# if (ps == 1):
# break;
# i = 1
# while True:
# if (xtal - fuart * i) < fuart:
# break
# i += 1
# fuart *= i
#
# Fast
#
fuart = baud * ps
if xtal < fuart:
if xtal >= baud:
ps = xtal / baud
else:
ps = 1
fuart = baud * ps
elif algo & 1 == 0:
# in C we use fls()
scale = int(math.ceil(math.log(xtal / fuart, 2)))
if scale > rw:
fuart <<= scale - rw
else:
fuart <<= int(math.log(xtal / fuart, 2))
#
# Fast: consider to replace while-loop by fls(n >> rw)
#
# div = fractions.gcd(xtal, fuart)
# n = xtal / div
# while n > (2 ** rw - 1):
# div <<= 1
# n >>= 1
# m = fuart / div
# return m, n, ps, fuart * 16 / ps
#
# Precise: rational best approximation
#
f = fractions.Fraction(fuart, xtal).limit_denominator(2 ** rw - 1)
return f.numerator, f.denominator, ps, fuart * 16 / ps
def usage():
sys.stdout.write("Usage %s [XTAL [PS [RW [ALGO]]]]\n" % PROG)
def toint(value):
try:
return int(value)
except ValueError:
usage()
raise SystemExit("Invalid argument")
def main(argv):
if len(argv) > 1:
xtal = toint(argv[1])
else:
xtal = XTAL
if len(argv) > 2:
presc = toint(argv[2])
else:
presc = PS
if len(argv) > 3:
rw = toint(argv[3])
else:
rw = RW
if len(argv) > 4:
algo = toint(argv[4])
else:
algo = ALGO
bauds = dict()
for b in sorted(BAUDRATES):
m, n, ps, uartclk = go(xtal, b, rw, presc, algo)
if (m, n, ps, uartclk) not in bauds:
bauds[(m, n, ps, uartclk)] = list()
bauds[(m, n, ps, uartclk)].append(b)
for m, n, ps, uartclk in sorted(bauds, key=operator.itemgetter(2, 1, 0)):
fref = xtal * m / n
fuart = uartclk * ps / 16
dev = (abs(1.0 - fref * 1.0 / fuart) * 100)
brs = ["%d(%d)" % (b, uartclk / 16 / b) for b in bauds[(m, n, ps, uartclk)]]
dm = (fref - fuart) and '*' or ' '
#print "%-8d %-8d %-2d %-10d %-10d %s%.2f %s" % (m, n, ps, fref, uartclk, dm, dev, ','.join(brs))
print "%-8d %-8d %-2d %-10d %-10d %s" % (m, n, ps, fref, uartclk, ','.join(brs))
if __name__ == "__main__":
sys.exit(main(sys.argv))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment