[U-Boot-Users] [PATCH] ColdFire: Fix UART baudrate at 115200
Jerry Van Baren
gerald.vanbaren at ge.com
Wed May 28 23:29:21 CEST 2008
Liew Tsi Chung wrote:
> Jerry,
>
> The calculation you provided does not work, I tried it before.
> The best approach is reverse calculation after finding the closer
> counter (or divider), then find the smaller gap to the bus frequency.
>
> Using the calculation without the fix: counter = ((bus_freq / baudrate)
> + 31 )/ 32
Where are you getting the +31 from? Is this in the User's Manual?
> Bus freq 140Mhz and baudrate 115200
>
> counter = ((140000000 / 115200) + 31) / 32
> counter = 38
>
> However, the 38 divider shows partial garbage message when output to the
> terminal.
>
> Now, perform reverse calculation to obtain bus frequency.
> bus_freq = ((counter * 32) - 31) * 115200
Computations are for mathematicians. Real engineers measure the actual
frequency. ;-)
If you change the " - 31" to " - 42", your computations will result in a
different divisor. Why are you subtracting what appears to be an
arbitrary number (31)?
> bus_freq = ((38 * 32) - 31) * 115200
> bus_freq = 136512000
> diff = 140000000 - 136512000 = 3488000
>
> counter bus_freq diff
> ======= ========= =======
> 36 129139200 way too off!
> 37 132825600 7174400
> 38 136512000 3488000
> 39 140198400 198400 <=== Work at this counter! Small
> diff.
> 40 143884800 3884800
>
> Regards,
> TsiChung
Are you sure your input frequency is 140MHz and not 144MHZ??? Have you
read the itty-bitty numbers on the crystal? Have you put a scope on it
and actually measured it? Never trust those hardware people. ;-)
Looking at the MFC5407 (arbitrarily, not knowing what processor you
have), the dividers are as expected and *do not* match your "- 31"
calculations. They have a simple example and simple math that matches
(no "- 31").
Hmmm, the MFC5407 has a max CLKIN (and thus bus clock) of 54MHz. You
must have a different flavor. MFC548x maxes at 50MHz. What processor
are you using? Ahh, MFC5249 has a 140MHz bus. Still is a straight
forward divide-by n*32, no "- 31".
gvb
> -----Original Message-----
> From: Jerry Van Baren [mailto:gerald.vanbaren at ge.com]
> Sent: Wednesday, May 28, 2008 1:45 PM
> To: Liew Tsi Chung
> Cc: U-Boot-Users; Wolfgang Denx; Rigby John
> Subject: Re: [U-Boot-Users] [PATCH] ColdFire: Fix UART baudrate at
> 115200
>
> Tsi-Chung.Liew wrote:
>> From: TsiChung Liew <Tsi-Chung.Liew at freescale.com>
>>
>> If bus frequency is larger than 133MHz, the UART cannot output
>> baudrate at 115200 correctly.
>>
>> Signed-off-by: TsiChung Liew <Tsi-Chung.Liew at freescale.com>
>> ---
>> drivers/serial/mcfuart.c | 5 ++++-
>> 1 files changed, 4 insertions(+), 1 deletions(-)
>>
>> diff --git a/drivers/serial/mcfuart.c b/drivers/serial/mcfuart.c index
>
>> 88f3eb1..fca76bd 100644
>> --- a/drivers/serial/mcfuart.c
>> +++ b/drivers/serial/mcfuart.c
>> @@ -64,7 +64,10 @@ int serial_init(void)
>>
>> /* Setting up BaudRate */
>> counter = (u32) (gd->bus_clk / (gd->baudrate));
>> - counter >>= 5;
>> + counter = (counter + 31) >> 5;
>> +
>> + if ((gd->bus_clk > 133333333) && (gd->baudrate >= 115200))
>> + counter++;
>>
>> /* write to CTUR: divide counter upper byte */
>> uart->ubg1 = (u8) ((counter & 0xff00) >> 8);
>
> This doesn't look right at all. It looks like you are patching up
> integer math problems by using different bad math and then special
> casing the result. (In the metal working world, this is known as
> "measure with a micrometer, mark with chalk, cut with a torch, and grind
> to fit.")
>
> Part A:
> -------
> > counter = (u32) (gd->bus_clk / (gd->baudrate));
>
> If you want this to be more accurate, you should round it:
>
> > counter = (u32) ((gd->bus_clk + (gd->baudrate / 2)) /
> (gd->baudrate));
>
> Part B:
> -------
> > + counter = (counter + 31) >> 5;
>
> This is not rounding properly, it is doing a "ceiling".
>
> > + counter = (counter + 16) >> 5;
>
> Part C:
> -------
>
> > + if ((gd->bus_clk > 133333333) && (gd->baudrate >= 115200))
> > + counter++;
>
> This looks totally bogus. I very strongly suspect you need this because
> the above parts A: and B: are not rounding the division math properly,
> resulting in a wrong divisor *for your configuration*. While the above
> conditional may result in the correct divisor *for your configuration,*
> it probably will be wrong for some finite set of *other* configurations.
>
> If I got my algebra correct and my parenthesis balanced, I believe the
> above is trying to calculate the following formula:
> counter = (u32) (
> ((gd->bus_clk + (gd->baudrate / 2) +
> (gd->baudrate * 16))
> / (gd->baudrate * 32);
>
> Note, however, that (gd->baudrate / 2) is going to be relatively small
> compared to gd->bus_clk and (gd->baudrate * 16), so I suspect that the
> above formula could be changed to the following formula with no
> significant impact in accuracy:
> counter = (u32) (
> ((gd->bus_clk + (gd->baudrate * 16))
> / (gd->baudrate * 32);
>
> Hmmmm, checking the math with 133e6 for the bus rate with full precision
> math (i.e. a calculator), I get a divisor value of 36.08 (truncated to
> an integer => 36). Your hack-math results in a divisor of 38. The last
> formula I proposed above result in a divisor of 36.58 (truncated to an
> integer => 36). That checks.
>
> Real math => 36.08
> Hack-math => 38 (109375 baud => 5.1% off)
> Last formula => 36 (115451 baud => 0.2% off)
>
> For 160e6 bus frequency:
> Real math => 43.40
> Hack-math => 44 (113636 baud => 1.4% off)
> Last formula => 43 (116279 baud => 0.1% off)
>
> I don't see how your formula works (well, actually it works but only
> because async serial can handle ~10% error). In fact, it looks to me
> that your "correction" actually results in *more* error than the
> original calculation *without* rounding. What is your actual bus speed?
>
> What are to using on the other end of the serial line - I'm wondering
> if your receiver end is substantially off, causing a stack-up error that
> is causing your problem??? Is your board hardware marginal at 115200
> baud - what does it look like on a scope???
>
> Best regards,
> gvb
>
More information about the U-Boot
mailing list