Maker Pro
Maker Pro

UARTS and oscilator tolerances made easy for PICs

J

Jan Panteltje

I have seen several statements here about how accurate an oscillator
needs to be for serial communication in a PIC.

Lets make it simple:
Normally we have:
1 start, 8 data, 2 stop bits (or one stop bit).

Assuming for a moment the pic samples the bit somewhere in the middle,
although datasheet mentions 2 samples, hopefully these are just 2 clocks
apart in the middle of the bit position.
Now say we have 10 bits.
So to get the wrong bit in the last bit (the most critical one), you need to
be 5% off!
For 11 bits 4.9 %.
If you add a little for the '2 x test' maybe 4%.
Depends a bit how the UART works, if it samples until start bit found, add an
other clock period.
3.5 % should do it.
This assumes the 'other end' is exact on freq.
If the other end is 1% off, that leaves 2.5%.
PC is mostly 100% on baudrate (+ xtal tolerance).

Any comments?
 
I

Ian Stirling

Jan Panteltje said:
I have seen several statements here about how accurate an oscillator
needs to be for serial communication in a PIC.

Lets make it simple:
Normally we have:
1 start, 8 data, 2 stop bits (or one stop bit).

Assuming for a moment the pic samples the bit somewhere in the middle,
although datasheet mentions 2 samples, hopefully these are just 2 clocks
apart in the middle of the bit position.

They arn't, they are divided equally around the bit time.
Now say we have 10 bits.
So to get the wrong bit in the last bit (the most critical one), you need to
be 5% off!
For 11 bits 4.9 %.
If you add a little for the '2 x test' maybe 4%.
Depends a bit how the UART works, if it samples until start bit found, add an
other clock period.
3.5 % should do it.
This assumes the 'other end' is exact on freq.
If the other end is 1% off, that leaves 2.5%.
PC is mostly 100% on baudrate (+ xtal tolerance).

Only for a few bitrates.
For some there is a built in error, as the divisor isn't an integer,
and there is no way to setup the 8250/.... to do fractional division.
Any comments?

Why should you assume the other end is any more accurate than you are?
It may have a software UART, and be counting on its fingers to get the
right baud rate, and it worked when tested on the engineers PC.

I would say that unless you have complete control on what it's connected
to, then aiming to get better than +-1% is probablly good practice.
 
W

Wouter van Ooijen

PC is mostly 100% on baudrate (+ xtal tolerance).

How many PCs did you check?

And anyway, a reasoning that allocates all margin to one side of a
communications channel sounds suspicious to me.
Any comments?

Are you sure the electronics and the cable do not add some
uncertainty?

The recieving starts with detecting the edge of the start bit. The
receiver will check at fixed moments (not continuously), this will add
some uncertainty. I don't know for sure how much (in most cases this
info is not in the datasheet), I think worst case 1/3 of a bit cell.

The PIC UART baud rate generator does not generate the exact frequency
for all baudrates (depends on clock frequency and BRGH).

My rule of thumb: reliable asynch communication requires a clock that
is accurate to 1% (on both sides). I have not yet seen an internal
oscillator in any microcontroller that is this accurate. (One cheat:
some USB uC's trim their internal OSC to the received USB signal.)


Wouter van Ooijen

-- ------------------------------------
http://www.voti.nl
PICmicro chips, programmers, consulting
 
J

Jan Panteltje

They arn't, they are divided equally around the bit time.
That would be bad, you can sample twice to test for gliches,
but as you go off center in the bit, you ask for problems.
I made some UARTS in FPGA (and a lot in software),
but test in the middle.
It would explain PIC problems that people have.



Only for a few bitrates.
For some there is a built in error, as the divisor isn't an integer,
and there is no way to setup the 8250/.... to do fractional division.
Yes that is true, I have written those routines to address the UART
directly, but the normal baudrates are right on.
9600, 19200, 57600 (not so normal), 115200 are right on.


int uart_set_baudrate(char *device, int baudrate)
{
int combase;
int a;
int dividerhigh, dividerlow;
long fquarts;
int divide;
int divisor;


if(! get_combase(device, &combase) )
{
return 0;
}

fquarts = 1843200;
divisor = fquarts / 16; /* 115200 = fquarts / 16 */

if(debug_flag)
{
fprintf(stdout, "divisor=%d\n", divisor);
}

/* first enable write to baudrate dividers */
a = inb(combase + 3); /* get value at port*/
a = a | 128; /* set bit 7 */
outb(a, combase + 3); /* write back to port */

/* calculate value of dividers for 1.8432 MHz quartz */
(int) divide = divisor / baudrate;
dividerlow = divide % 256;
dividerhigh = divide / 256;

//if(debug_flag)
{
fprintf(stdout,\
"rs232_setbaudrate(): Baud=%d, div=%d divlow=%d divhigh=%d\n",\
baudrate, divide, dividerlow, dividerhigh);

fprintf(stdout, "\nreal baudrate now: %5.2f\n",\
(float)divisor / (dividerlow + (256.0 * dividerhigh)) );
}

/* write value to divisor addresses */
outb(dividerlow, combase + 0);
outb(dividerhigh, combase + 1);

/* set 8250 / 16450 registers to normal (data use) */
a = a & 127; /* reset bit 7 */
outb(a, combase + 3);

return(1);
} /* end function rs232_setbaudrate */

Why should you assume the other end is any more accurate than you are?
It may have a software UART, and be counting on its fingers to get the
right baud rate, and it worked when tested on the engineers PC.

I would say that unless you have complete control on what it's connected
to, then aiming to get better than +-1% is probablly good practice.
Yes, true, but the 1% is a bit tight.
Many cases it will be a PC (for the PIC) and you can select baudrate in
the PIC, and the tolerance can be bigger.
Indeed if it is going to some unknown environment, 1% is good.
I always use xtal (in the PIC), but even then you cannot always get 1%,
the baudrate may be determined by something else.
For example with 6 MHz and 19200 you get more then 2 % error,
because of the division counters.

It is interesting, because it is used so often (rs232).
But USB is taking over...
Found one PIC with USB but it was OTP....
Maybe there are more.
 
I

Ian Stirling

Jan Panteltje said:
That would be bad, you can sample twice to test for gliches,
but as you go off center in the bit, you ask for problems.
I made some UARTS in FPGA (and a lot in software),
but test in the middle.
It would explain PIC problems that people have.

But how do you find the middle?
You have to sample at some speed higher than twice the baud
rate (probably 8 or 16 times) and work out where
the bits are.
This means that your idea of where the center of the bit is
must be out by at least +-0.5 sampling times.

This has to be added to the other timings.
 
M

Martin Riddle

Use the 11.0592 mhz crystal if you can. All baud rates will have register values that have no error. The only error will be in the
crystal freq itself.

Cheers
 
A

Adrian Jansen

I have used a controller which has 10's of thousands of other copies running
serial comms, almost all connected to 'standard PCs'. It happens to have a
1.7 % error in baud rate at 4800, and no-one has ever complained of
problems. But had a customer last month with a noname brand laptop which
refused to communicate with the controller, even though same laptop worked
perfectly with a couple of other PCs I checked. And the problem was the
baud rate - kept getting framing errors. So yes, you can get caught with
off-rate values, only rarely, but enough to be a nuisance.

--
Regards,

Adrian Jansen
J & K MicroSystems
Microcomputer solutions for industrial control
 
J

Jan Panteltje

But how do you find the middle?
You have to sample at some speed higher than twice the baud
rate (probably 8 or 16 times) and work out where
the bits are.
This means that your idea of where the center of the bit is
must be out by at least +-0.5 sampling times.

This has to be added to the other timings.
Yes, well, in the software delay loop you are accurate to one nop, or part
of a microsecond.
In the hardware FPGA case, there is no limit how accurate you want the
counter.
You can sample at count ten of a 4 bit counter, or at count
32222 of a 16 bit counter.
It is up to you, as FPGA has high speed clock.
The same for finding the start of the start bit.
Indeed most practical things sample 16 or less :)
But to test for start start bit in software:
wait_start_bit:
testbit
if not set go to wait_start_bit
call 1 1/2 bit delay ; wait for middle first data bit
test bitvalue0
call 1 bit delay
test bitvalue1
etc..
you will be extremely close.

half bit delay:
for (i=0; i < WHATEVER; i ++) {nop }
nop ; calibration nops
nop
return

When you use a 16 bit counter for the baudrate,
your accuracy becomes clock / 65536, or
for a 10MHz clock 10 000 000 / 65536 = 152 ticks

When you use soft loop, as shown, your accuracy
is one nop, or 4 ticks (or so).
So, it all depends...

You could say: I want hardware UART because of
interrupt when RX char.
But if you use int on neg edge you can also detect start
of a async transmission, in interrupt do the rest.
But you would be interupted for the duration of all 10 bits.
Interesting stuff, to play with.

Hope I did not screw up here in this examples.
JP
 
Top