Improvement to am335x_lcd_calc_divisor()

Leonardo Fogel leonardofogel at yahoo.com.br
Tue Jun 30 13:25:26 UTC 2015


Hello.

Given a reference frequency (R) and a target frequency (F), am335x_lcd_calc_divisor(R,F) calculates the divisor (d) such that abs(R/d - F) is the minimum; ideally R/d == F.

https://svnweb.freebsd.org/base/head/sys/arm/ti/am335x/am335x_lcd.c?revision=284534&view=markup#l234

The function does a brute-force search; it tests d=2,...,255. I would like to propose a simpler (and faster) implementation.

Let r be the real number R/F, such that R/r == F. The integer d that produces the minimum abs(R/d - F) also produces the minimum abs(r - d). The trivial solution is d = lround(r) (rounds to the nearest integer).

We do not need floating point arithmetic. Let f be the fractional part of r, namely, the real number (R%F)/F. If f >= 0.5, then lround(r) rounds up. Otherwise, it rounds down. We can test whether 10*f >= 5. Here is the proposal:

	if (freq == 0) /* there is a bug somewhere. */
		return (255);

	/* The fractional part of the real number reference/freq, times 10. */
	fraction_x10 = 10*(reference%freq)/freq;
	if (fraction_x10 >= 5)
		div = reference/freq + 1; /* rounds up   */
	else
		div = reference/freq ;    /* rounds down */

	/* Raster mode case: divisors are in range from 2 to 255 */
	if (div < 2)
		div = 2;
	else if (div > 255)
		dir = 255;

	return (div);

If you think it is worth, I'll be glad to submit a path. I just can not test it, though.
Thank you.
Leonardo


More information about the freebsd-arm mailing list