possible to miss messages when using UART?

Go To Last Post
16 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi - so I'm working on a program that is controlled through the UART. The computer attached to the AVR sends commands over serial to the AVR that sets various parameters for the AVR (whcih is essentially acting as a signal generator). The AVR is programmed so that it is constantly checking the UART for new commands, but then the signal generating part of the code is entirely timer interrupt driven (thus it interrupts the UART checking code)

I had first been thinking that I would need to send one byte to the computer, then have the AVR send a byte back saying it's ready for the next byte, etc. But just for kicks I tried skipping sending a byte back, and just have the AVR assume it wouldn't miss any commands. This worked without any problems at all - but I also wonder if it's because the ISRs are very short (I think less than 10 clock cycles), and I was only running the UART at 9600 baud.

So my question is this: Is there some sort of built in protection in the serial protocol/AVRs/UARTs/computer/etc. that forces the computer to be send the next byte only when the AVR is ready for it? My worry is that when the ISRs start to get more complicated (and they will get very complicated and lenghty) that I could miss entire commands (like say two commands are sent while the AVR is in an ISR, so I'm worried that the first would be lost due to receiving the second).

So is this a problem? Hopefully I'm explaining myself OK... Thanks!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Use recieve interupt on the uart. Wont miss any chars then.

Imagecraft compiler user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
Is there some sort of built in protection in the serial
protocol/AVRs/UARTs/computer/etc. that forces the computer to be send
the next byte only when the AVR is ready for it?

No, nothing builtin. The UART does have a builtin buffer (1-2 bytes
depending on model) and an Overrun indicator to tell you (after the fact)
if you've lost something.
Quote:
My worry is that when the ISRs start to get more complicated ...
that I could miss entire commands

You can use XON/XOFF flow control or (as you suggested) build a byte-by-
byte flow control protocol. Before you do that, though, you should do
some arithmetic: Running at 9600bps you have about 1ms to deal with
each byte; at e.g. 4MHz that's 4000 cycles, which is 400x the time you're
currently estimating for the ISRs, so they would have to grow quite a
bit before they'd interfere.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

bobgardner wrote:
Use recieve interupt on the uart. Wont miss any chars then.

I thought about that - but the problem is that the function generation part of the code is event driven, and thus if the avr were running a UART ISR and it came time for a timer ISR to be run, the timer ISR wouldn't be called due to the AVR running the UART ISR.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Don't spend so much time in ISRs. Think about it--spending much more than one character time (yeah, I know that the AVRs are double-buffered or 2+ buffered) is an invitation for less than rock-solid UART communications.

There are ways to say "send only when I'm ready". Search for information on "hardware handshaking" and "software handshaking".

Lee

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

mckenney wrote:
Quote:
Is there some sort of built in protection in the serial
protocol/AVRs/UARTs/computer/etc. that forces the computer to be send
the next byte only when the AVR is ready for it?

No, nothing builtin. The UART does have a builtin buffer (1-2 bytes
depending on model) and an Overrun indicator to tell you (after the fact)
if you've lost something.
Quote:
My worry is that when the ISRs start to get more complicated ...
that I could miss entire commands

You can use XON/XOFF flow control or (as you suggested) build a byte-by-
byte flow control protocol. Before you do that, though, you should do
some arithmetic: Running at 9600bps you have about 1ms to deal with
each byte; at e.g. 4MHz that's 4000 cycles, which is 400x the time you're
currently estimating for the ISRs, so they would have to grow quite a
bit before they'd interfere.

AVR UARTs have a buffer? I didn't know that. Where would that be in the datasheet? I forgot about the overrun indicator - I could always check that and just simply hope that I hadn't missed more than one byte.

You're right though - as long as I keep the ISRs fairly simple I shouldn't have any problems. But the other problem is if the actual UART code gets too lenghty. See - the whole reason for my interest in this is that right now control of the AVR is entirely binary. I use the first 4 bits for the command, and the second 4 bits for a parameter of the command. I'd like to eventually have it be entirely ascii - so somebody could just fire up hyperterminal and control it from there. Thus the code will have to be a good deal more complex (for example, I'll have to deal with converting multiple digit ascii decimal to 2 byte binary).

Last Edited: Sat. Jan 1, 2005 - 04:00 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

theusch wrote:
Don't spend so much time in ISRs. Think about it--spending much more than one character time (yeah, I know that the AVRs are double-buffered or 2+ buffered) is an invitation for less than rock-solid UART communications.

There are ways to say "send only when I'm ready". Search for information on "hardware handshaking" and "software handshaking".

Lee

OK - I looked it up (specifically - I was looking at this page: http://bugclub.org/beginners/mod...) - and it sounds to me like if I were to use software handshaking, I would have to have that written into the code on both the avr and the computer side. But with hardware handshaking, specifically the RTS and CTS lines, it sounds like that would be entirely hardware, so even MS hyperterminal would be able to handle it. On the AVR side - I could just control those two pins via two I/O pins and a MAX232, correct?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Many communications subsystems (such as teminal emulators) will support XON/XOFF software handshaking. To say hardware handshaking is "entirely hardware" is somewhat misleading--there >>are<< interfaces that watch the lines in the chip, but on (say) the PC side I'd expect that a driver is watching the control signals.

I've done many high-speed (up to 115k) AVR interfaces, many with nearly continouous communication at least during testing. I don't miss messages or characters, and I've never used hardware or software handshaking on a simple UART link. Keep your ISRs short, and use interrupt-driven serial comms.

Remember, the only critical part is the RX servicing & tucking the characters away. The messages can be processes at your leisure. You haven't said what you are doing in the lenthy ISR(s); my recommendation: "Just say 'No'." Grab the needed data when the event occurs, mark the mainline as ready to do the processing, and then let that processing get interrupted by the RX ISR--a few microseconds every character time.

Lee

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The uart recieve interrupt is only a dozen instructions.... should run in less than a MICROSECOND.... push a couple regs, get the char, get the rx buffer pointer, store the char, inc the pointer, pop a couple regs, get out.

Imagecraft compiler user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
avr were running a UART ISR and it came time for a timer ISR to be run, the timer ISR wouldn't be called due to the AVR running the UART ISR.

Interrupts can be interrupted - what language are you using? For example if it is C with avr-gcc you can use the INTERRUPT() macro instead of the SIGNAL() macro to allow interrupts to be interrupted.

Set the timer ISR as non-interruptable, which means that the UART won't interrupt it. However the UART ISR is interruptable, so the timer ISR will interrupt it.

-Colin

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

c_oflynn wrote:
Quote:
avr were running a UART ISR and it came time for a timer ISR to be run, the timer ISR wouldn't be called due to the AVR running the UART ISR.

Interrupts can be interrupted - what language are you using? For example if it is C with avr-gcc you can use the INTERRUPT() macro instead of the SIGNAL() macro to allow interrupts to be interrupted.

Set the timer ISR as non-interruptable, which means that the UART won't interrupt it. However the UART ISR is interruptable, so the timer ISR will interrupt it.

-Colin

Colin, Colin, Colin--do I need to go into the whole nested-interrupt thing again? [It is pretty much like bignendian-littleendian and C vs. ASM. :) ]

Quote:
...Interrupts can be interrupted ...

Yes, they can. And there are many advocates of doing that on this Forum. They also: love to see their stack needs grow dramatically; open themselves up for cascading interrupts and a runaway stack; need a lot more thought about data interlocking and atomic operations than a simple foreground-background system; and SPEND AS MUCH TIME DOING THE NESTED-INTERRUPT OVERHEAD AS THEY WOULD TO GET-IN-AND-GET-OUT OF A "NORMAL" RX OR TIMER EVENT. (oops, my CapsLock 'accidentally' stuck.)

But do what you want--you will anyway. I've been married long enough to know that.

Lee

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
Set the timer ISR as non-interruptable, which means that the
UART won't interrupt it. However the UART ISR is interruptable, so the
timer ISR will interrupt it.

Personally, I wouldn't recommend (particularly to a novice) making either
interruptible, but if I were to, I'd recommend just the opposite:
1) The UART interrupt is (presumably) small, and the timer large, so the
timer should be interruptible by the UART.
2) Using INTERRUPT() for RXC and UDRE fits somewhere between "tricky"
and "impossible".

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

This would be a whole lot simpler if you would post the code for your frequency generator nleahcim. The whole point is moot if your singal generation code takes up a small amount of space. The lower your baud rate the less chance you'll have of having interupts collide (becase the uart is spending most of it's time waiting for data) It also depends on how often you're going to be sending bytes to the AVR, I doubt this is going to be a continous stream you're just going to get periodic updates of the frequency, in which case the UART buffer will save you from about 90% of possible interupt problems. Just make sure your buttons are properly debounced and that end of the code is running as efficiantly as you can and you'll never run into problems, so long as you don't keep adding features that take up more time to process.

-Curiosity may have killed the cat
-But that's why they have nine lives

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Sceadwian wrote:
This would be a whole lot simpler if you would post the code for your frequency generator nleahcim. The whole point is moot if your singal generation code takes up a small amount of space. The lower your baud rate the less chance you'll have of having interupts collide (becase the uart is spending most of it's time waiting for data) It also depends on how often you're going to be sending bytes to the AVR, I doubt this is going to be a continous stream you're just going to get periodic updates of the frequency, in which case the UART buffer will save you from about 90% of possible interupt problems. Just make sure your buttons are properly debounced and that end of the code is running as efficiantly as you can and you'll never run into problems, so long as you don't keep adding features that take up more time to process.

Well at this point it is nowhere near complicated enough to cause a byte to be missed - so there's no point just yet.

A couple questions though: if the UART is buffered, does that mean I could receive two bytes, then read the first byte, and then read in the second byte?

Also, I thought interrupts couldn't be interrupted? Or would you just have the first command of your ISR be SEI so that interrupts would be enabled again? Would there be anything additional one would have to do to make that work?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You could make the timer code just increment a variable (6 bit? 16 bit? 32 bit? how long an interval do you need to measure?). Now both your interrupt handler and you usart handler run in much less than a microsecond each. Now the avr can service both interrupts, go out back for a smoke, come back and calculate the time diff and all that then start over.

Imagecraft compiler user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
if the UART is buffered, does that mean I could receive two bytes,
then read the first byte, and then read in the second byte?

Read the datasheet for your device. Some models have a 1-byte buffer
overwritten when the next byte is complete, giving you 1 character-time
to service it. Other models have a 2-byte buffer, plus the shift register
can hold a 3rd byte until the 4th byte starts, giving you just-barely-3
character times to service it.
Quote:
Or would you just have the first command of your ISR be SEI so
that interrupts would be enabled again?

That's the Executive Summary, but as soon as you do this you open a
considerable can-of-worms which I suggest you avoid unless/until
you absolutely need it. At the very least you'll need a very clear picture
of the dynamics of your program, which from the sounds of it (you still
sound unsure whether your ISRs will run for 1us or 1ms) hasn't gelled yet.