Com3 Questions/Observations

Started by Don Kinzer May 27, 2004
I noticed that my app runs quite a bit slower when I have Com3
opened. For example, a simple loop with some calculations takes
about 1.9ms with Com3 not opened. With Com3 opened, not sending or
receiving any characters, the same loop takes about 4.2ms.

I assume that this is overhead related to servicing Timer2 interrupts
which provide the serial timing for Com3.

Anyway, I was thinking about the provision for a parity bit on Com3
and wondered what happens if the BX receives a character with bad
parity. Is it dropped? Is there some indication that a parity error
occurred?

Also, at what rate is the Com3 input sampled? Typically in hardware
UARTS, the input is sampled at least at 4x the baud. This is done to
allow positioning the data bit samples somewhere in the middle of the
bit window after detecting a start bit.

To sample at 4x when supporting 19.2K baud, you'd have to have
interrupts at 76.8 KHz. At the BX's clock rate, that amounts to an
interrupt every 96 CPU cycles. That seem like not very many cycles
to implement a software UART.

I looked at the Timer2 settings on the BX and they didn't make any
sense. Perhaps the code is loading TCNT2 at various times
dynamically adjust the timing.



I've been searching the archinve trying to determine conceptually how
the serial port h/w and s/w works as I code my first BX24 app. The
questions you posed below are kind of along the lines of what I would
want to ask.

I looked in the h/w ref manual but saw no mention of uarts. I'm
guessing COM1 has a real UART for buffering data (hence it's high
speed capability)? If so, how big is the buffer? But for COM3 there
are just frequent interrupts to check for data?

Did you ever try lowering your baud rate to say 9600 from 19200 and
see how it affected your other work (e.g. would the time taken in your
example below drop from 4.2ms to perhaps 3ms?).

Is it fair to say that if I open the COM3 port, a serial sender such
as a Basic Stamp could send me 5 bytes at any time without any
synchronization (as long as I can call GetQueue to obtain the 5 bytes
before the BS2 would send again)?

In other words, can I make the BS2's job easy and not have it worry
about raising an interrupt line first, then synchronizing to send 5 bytes?

Maybe I need to read some Atmel docs, but how does the interrupt for
the serial port affect the regular time-slice interrupt interval (the
one that occurs at 512hz)? Is time slicing round-robin?

Thanks.

Harry

--- In , "Don Kinzer" <dkinzer@e...> wrote:
> I noticed that my app runs quite a bit slower when I have Com3
> opened. For example, a simple loop with some calculations takes
> about 1.9ms with Com3 not opened. With Com3 opened, not sending or
> receiving any characters, the same loop takes about 4.2ms.
>
> I assume that this is overhead related to servicing Timer2 interrupts
> which provide the serial timing for Com3.
>
> Anyway, I was thinking about the provision for a parity bit on Com3
> and wondered what happens if the BX receives a character with bad
> parity. Is it dropped? Is there some indication that a parity error
> occurred?
>
> Also, at what rate is the Com3 input sampled? Typically in hardware
> UARTS, the input is sampled at least at 4x the baud. This is done to
> allow positioning the data bit samples somewhere in the middle of the
> bit window after detecting a start bit.
>
> To sample at 4x when supporting 19.2K baud, you'd have to have
> interrupts at 76.8 KHz. At the BX's clock rate, that amounts to an
> interrupt every 96 CPU cycles. That seem like not very many cycles
> to implement a software UART.
>
> I looked at the Timer2 settings on the BX and they didn't make any
> sense. Perhaps the code is loading TCNT2 at various times
> dynamically adjust the timing.




--- In , "harrybstoner" <tedstoner@1...> wrote:
> I've been searching the archinve trying to determine conceptually
> how the serial port h/w and s/w works as I code my first BX24 app.

I don't have any direct knowledge of how the BX-24 Com3 is
implemented but my guess it that it is a "software UART". This means
that a timer is set up to interrupt at some multiple of the bit rate
(perhaps 2 or 4). When the interrupt fires, the software samples the
input to see if a "start bit" is present. If so, it sets state
information so that it can then sample the input again every bit time
and accumulate the serial data.

Output is easier since you don't have to deal with the asynchronous
nature of external devices sending you information. When you have a
character to send, you first send the start bit. On the next bit
cycle you send the LSB, etc. etc. until the entire byte is sent
(including parity bit) and then send a stop bit.

For both COM1 and COM3, the input and output buffer sizes are exactly
the queue sizes that you establish. Of course, for debug.print,
there is a pre-defined queue set aside for both input and output. I
haven't tried to determine how big they are.

> Maybe I need to read some Atmel docs, but how does the interrupt for
> the serial port affect the regular time-slice interrupt interval
> (the one that occurs at 512hz)? Is time slicing round-robin?

When you have Com3 open, a timer interrupt goes off on some multiple
of the baud rate (perhaps 2 or 4 times the baud rate). Since
responding to the timer interrupt consumes CPU time, your program
will run more slowly when Com3 open than it does with Com3 not open.
This doesn't interfere with the multi-tasking since the time to
service the software UART timer interrupt is most likely much less
than the RTC interrupt period.

You could probably devise a test to see how much overhead is incurred
by having Com3 open.

Don



Thanks Don. I downloaded and tested my code somewhat and crudely
measured the effects of having the com port open versus closed. I also
saw how changing the baud rate affected performance.

Please see http://pinnovations.com/pnv/basicx/index.html for results.

As expected, the faster the baud rate, the more the impact on performance.

Harry

--- In , "Don Kinzer" <dkinzer@e...> wrote:
>
> --- In , "harrybstoner" <tedstoner@1...> wrote:
> > I've been searching the archinve trying to determine conceptually
> > how the serial port h/w and s/w works as I code my first BX24 app.
>
> I don't have any direct knowledge of how the BX-24 Com3 is
> implemented but my guess it that it is a "software UART". This means
> that a timer is set up to interrupt at some multiple of the bit rate
> (perhaps 2 or 4). When the interrupt fires, the software samples the
> input to see if a "start bit" is present. If so, it sets state
> information so that it can then sample the input again every bit time
> and accumulate the serial data.
>
> Output is easier since you don't have to deal with the asynchronous
> nature of external devices sending you information. When you have a
> character to send, you first send the start bit. On the next bit
> cycle you send the LSB, etc. etc. until the entire byte is sent
> (including parity bit) and then send a stop bit.
>
> For both COM1 and COM3, the input and output buffer sizes are exactly
> the queue sizes that you establish. Of course, for debug.print,
> there is a pre-defined queue set aside for both input and output. I
> haven't tried to determine how big they are.
>
> > Maybe I need to read some Atmel docs, but how does the interrupt for
> > the serial port affect the regular time-slice interrupt interval
> > (the one that occurs at 512hz)? Is time slicing round-robin?
>
> When you have Com3 open, a timer interrupt goes off on some multiple
> of the baud rate (perhaps 2 or 4 times the baud rate). Since
> responding to the timer interrupt consumes CPU time, your program
> will run more slowly when Com3 open than it does with Com3 not open.
> This doesn't interfere with the multi-tasking since the time to
> service the software UART timer interrupt is most likely much less
> than the RTC interrupt period.
>
> You could probably devise a test to see how much overhead is incurred
> by having Com3 open.
>
> Don




--- In , "harrybstoner" <tedstoner@1...> wrote:
> I downloaded and tested my code somewhat and crudely
> measured the effects of having the com port open versus closed.
> I also saw how changing the baud rate affected performance.
>
> Please see http://pinnovations.com/pnv/basicx/index.html for
> results.
>
> As expected, the faster the baud rate, the more the impact on
> performance.

Good work! The results are about what I expected although the value
for 14400 is a bit odd. I would have expected it to be 50% more than
that for 9600.

Here's a tip. If you have access to a logic analyzer or an
oscilloscope, it makes this sort of timing measurement much easier.
I often set up a loop (if using an oscilloscope) or a sequence of
code (if using a logic analyzer) where I toggle an output at the
beginning and end of a sequence of instructions. It is then a simple
matter to determine the elapsed time. To minimize the effect of the
output toggling, use the Register.PortX insteat of PutPin(), e.g.

Register.PortC = Register.PortC Xor 1

This will toggle pin 12 each time it is executed and is much faster
than using PutPin().

You can also run the same timing loop without any target instructions
to measure what the loop overhead time is. Then you subtract that
from the measurement with the target instructions to determine the
actual execution time.

One side note here is that there is some "jitter" when you make these
measurements due to the overhead of servicing RTC interrupts, Com1
interrupts and Com3 interrupts (if Com3 is open). Of course, you
won't get any Com1 interrupts unless there are characters being sent
or received. If you want to reduce the jitter, you can disable the
RTC interrupt by writing zero to Register.TCCR0. Of course, if you
do this, multi-tasking will no longer work until you reset the system.

Don



Re: Com3 Questions/Observations
Re: Com3 Questions/Observations
> ... writing zero to Register.TCCR0 ...

Watch out.

If your code quickly disables interrupts you might never again get
control of the module to download anything else. If you choose to
tamper with the OS internals like this, add a Sleep(1.0) or Delay(1.0),
or similar, to the start of your code to give the IDE a chance to gain
control via ATN before you make it impossible.
Tom
Tom Becker
--... ...--
www.RighTime.com
The RighTime Clock Company, Inc., Cape Coral, Florida USA
+1239 540 5700



Re: Com3 Questions/Observations

--- In , "Tom Becker" <gtbecker@r...> wrote:
> > ... writing zero to Register.TCCR0 ...
>
> Watch out.
>
> If your code quickly disables interrupts you might never again get
> control of the module to download anything else. If you choose to
> tamper with the OS internals like this, add a Sleep(1.0) or Delay
> (1.0), or similar, to the start of your code to give the IDE a
> chance to gain control via ATN before you make it impossible.

Good point. I forgot about that.

However, this may be less of a problem than it at first appears. See
page 29 of the "Basic Express Compiler User's Guide" (V2.1).



> ... page 29 of the "Basic Express Compiler User's Guide" (V2.1)...

Yes. I believe, nevertheless, that I locked myself out of my first
BX-24 and could never again get control, no matter what I tried, after
stopping Timer0 in the first few lines of one experiment's code. If
there is a brief period between Reset and program execution to detect
ATN, it must be very brief. Tom
Tom Becker
--... ...--
www.RighTime.com
The RighTime Clock Company, Inc., Cape Coral, Florida USA
+1239 540 5700


--- In , "Tom Becker" <gtbecker@r...> wrote:

> > > ... writing zero to Register.TCCR0 ...
> >
> > Watch out.
> >
> > If your code quickly disables interrupts you might never again get
> > control of the module to download anything else. If you choose to
> > tamper with the OS internals like this, add a Sleep(1.0) or Delay
> > (1.0), or similar, to the start of your code to give the IDE a
> > chance to gain control via ATN before you make it impossible.
>
> Good point. I forgot about that.
>
> However, this may be less of a problem than it at first appears. See
> page 29 of the "Basic Express Compiler User's Guide" (V2.1).
>
The OOPic doesn't have this feature of BasicX (and a number of other
things but that is a different story) so they have to train their users
to write a 2 second delay at the beginning of every program. If the
OOPic locks up you have to go through a "cosmic wedgie" whatever that is
to get back working again.

Another reason to love the BasicX platform.

Mike




--- In , Mike Perks <basicx@a...> wrote:
> [...] you have to go through a "cosmic wedgie" [...]

I was thinking that if you had another AVR or similar microcontroller
you could hold the BX-24 in its reset state and perform SPI writes to
the external EEPROM to overwrite a rogue program. Perhaps a 'halt'
instruction at location zero would be all it would take.

I haven't done this but it would seem fairly easy to do using the 7
holes on the BX-24 between pin 1 and pin 24.

Tom, if you still have that "locked up" BX-24 I would give it a try
for you.

Don