This evening I will tell you a
tale about how you can effectively calculate the parameters of the prescaler, which is usually used to set the USART clock frequency of the ports, in particular the 8250-compatible, used in the Intel SoC.
Currently there are at least two Intel SoC lines that use a fractional prescaler USART.
- Medfield, CloverTrail, Tangier
- BayTrail, Braswell
What is the difference between them, I'll tell you later.
Below are the formulas by which
Fusart is calculated — the USART clock frequency, and
baud — the transmission rate.
')
Rest
Fref is the frequency before the prescaler,
m is the numerator,
n is the denominator of the rational fraction of the prescaler,
prescaler is the integer divided by
Fusart ,
DLAB is the 16-bit divider presented in 8250-compatible chips.
Of the entire set, we know only two quantities, namely:
Fref and
baud . The size of the
prescaler is usually equal to 16 and in some chips there is no possibility to change it (this is precisely what distinguishes
the Intel SoC lines from each other)
Calculation of prescaler
Since we are working with a fractional prescaler, and not with a full PLL, then from
(1) it follows
And therefore we can already calculate the value of the
prescalerprescaler = 16 fusart = baud * prescaler if fref < fusart: if fref >= baud: prescaler = fref / baud else: prescaler = 1 fusart = baud * prescaler
Fusart calculation
The previous part only works if it does not
(3) . Otherwise, the
Fusart can be very low relative to
Fref at the requested rather low transmission rate, for example 110 baud.
And since the numerator and denominator of the divider are usually of equal width (in bits), it would be nice to limit their divergence. To do this,
let's bring
Fusart to
Fref as much as possible.
fusart <<= int(math.log(fref / fusart, 2))
Why was this approach chosen? The thing is, if we have an overflow of
DLAB , and it is only 16-bit, then in the case of the use of the power of two, we can track it with the simplest bit operations.
The queue for the denominator
Obviously, now from
(1,2) , there follows a simple proportion
Thus, we can easily calculate the numerator and denominator of the rational fraction prescaler.
divisor = gcd(fref, fusart) n = fref / divisor while n > (2 ** width - 1): divisor <<= 1 n >>= 1 m = fusart / divisor
Here,
width is the width in bits of the numerator and denominator.
That's all. For those who wish, the source code in Python can be found
on GitHub Gist (it has already been updated several times and may be updated in the future).
Example calculation for Fref = 50MHz, width = 24 bitsThe output is in the format 1) m , 2) n , 3) prescaler , 4) Fusart , 5) a mysterious number, 6) a list of transmission rates, in brackets the value DLAB .
24 25 12 48000000 64000000 4000000 (1)
49 50 14 49000000 56000000 3.5 million (1)
4 5 16 40 000 000 40 000 000 2500 000 (1)
16 25 16 320000 32000000 500000 (4), 1,000,000 (2), 2,000,000 (1)
24 25 16 48000000 48000000 1500000 (2), 3000000 (1)
2304 3125 16 36864000 36864000 576000 (4), 1152000 (2)
8192 15625 16 26214400 26214400 50 (32768), 200 (8192)
9216 15625 16 29491200 29491200 1800 (1024), 57600 (32), 115200 (16), 230400 (8), 460800 (4), 921600 (2), 1843200 (1)
12288 15625 16 39321600 39321600 75 (32768), 150 (16384), 300 (8192), 600 (4096), 1200 (2048), 2400 (1024), 4800 (512), 9600 (256), 19200 (128), 38400 (64)
45056 78125 16 28835840 28835840 110 (16384)
274432 390625 16 35127296 35127296 134 (16384)
Please note that the above algorithm is simple and fast, although not so accurate, but it satisfies our goal.