Need help dealing with "colliding" interrupts

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

Hello,

I am relatively new to real-time programming, but have been doing a lot of reading (especially on this forum) trying to get up to speed.

I have written code for the ATMega128 to receive (and time) pulses coming in on ICP1 while simultaneously sending and receiving serial data across the serial port. The problem is, my input capture interrupt seems to get held up (significantly at times) by the serial port communication, and when I attempt to capture the time of the pulses coming in on ICP1, get incorrect (or very delayed) values at times, due to this problem. This sort of "collision" of interrupts only occurs once every 15-20 seconds it seems, but it bothers me that it is happening at all. Could anyone recommend a technique to help deal with this problem? I thought that by using the input capture port, delays in the interrupt would not be an issue since the timer value is latched into a register which can be read out at a later time. But apparently my serial port communication is taking so long that, occasionally, a new pulse comes in before I have been able to read out the time value from the ICP register from an old pulse. I have tried changing my serial receive ISR function from 'SIGNAL' to 'INTERRUPT' in the hopes that this would allow the incoming pulses on ICP1 to not be missed or delayed, but the serial communication would not work at all using INTERRUPT rather than SIGNAL, so I switched it back how I had it.

Thanks,
James

Last Edited: Thu. May 26, 2005 - 06:12 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

DO NOT USE INTERRUPT, use Signal instead. Using Interrupt allows your ISR to be interrupted which
is probably why you are getting strange results.

Randy

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

jdowns wrote:
I have tried changing my serial receive ISR function from 'SIGNAL' to 'INTERRUPT' in the hopes that this would allow the incoming pulses on ICP1 to not be missed or delayed, but the serial communication would not work at all using INTERRUPT rather than SIGNAL, so I switched it back how I had it.

As you discovered, using INTERRUPT for the UART interrupts doesn't work. For an Rx interrupt, the interrupt isn't cleared until the character is read from the UART. SIGNAL causes interrupts to be re-enabled before this happens so you get stuck in an endless interrupt loop.

What you could do is effectively hand code what SIGNAL does (re-enable global interrupts) with a slight modification. In your Rx interrupt handler, first disable the Rx interrupt then enable global interrupts (sei). Now, go on with your normal processing. Before leaving, disable global interrupts (cli), re-enable the Rx interrupt. The reti at the end of the interrupt handler will re-enable global interrupts.

You probably need to something similar in your Tx interrupt handler.

Don

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

Randy,

Thank you for your suggestion.

Originally, I used nothing but the SIGNAL keyword for all of my interrupts. But when I started noticing strange results, i.e. some events seemed like they were being missed, I thought that maybe the use of the SIGNAL macro was causing me to miss interrupts. So I tried using the INTERRUPT macro instead, but immediately grabbing the time value in the first line of the ISR, so that if it got interrupted by another ISR, I would still have the correct time value at that point. Anyway, that was my thinking. Is this not the best way to go about such things?

Also, what happens if I use SIGNAL for my input capture ISR and then a serial port message starts coming in from my serial device? Will I miss this serial message? Or will it come in garbled? Is there a standard way of dealing with multiple interrupts (one from the uart and one from the icp) coming in at the same time?

Don,

Thank you for your input as well. I will experiment with your suggestions and let you know what happens. Thank you very much.

Sincerely,
James

Last Edited: Tue. May 24, 2005 - 09:49 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

jdowns wrote:
Also, what happens if I use SIGNAL for my input capture ISR and then a serial port message starts coming in from my serial device? Will I miss this serial message?

Unless your input capture ISR execution time exceeds the serial character transmission time, you shouldn't have a problem. At least some of the AVR UARTS contain a small receive FIFO - this would give you even more time.

Another thought: why does your UART ISR(s) take an inordinate amount of time. Maybe the correct fix is to reduce the UART ISR execution times.

Don

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

Quote:
Another thought: why does your UART ISR(s) take an inordinate amount of time. Maybe the correct fix is to reduce the UART ISR execution times.

I may have mis-diagnosed the problem. All I know is that my input capture ISR works flawlessly on its own. It is not until I turn on an external device which starts sending and receiving serial data that the problem with my input captures begins. I will investigate this more tonight and try out your suggestions.

Thank you very much.

James

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

donblake wrote:
At least some of the AVR UARTS contain a small receive FIFO

Really? Which ones are these?

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

Quick question, what are you receiving the uart characters with, to determine the latency? You should be aware that PC based UARTS have FIFOs that are several characters deep, and will not generate an interrupt immediately on the first received character, but rather must first time out for several character times before an interrupt is generated. Alternatively the UART will also generate an interrupt when the full watermark is met.

As for using interrupt/signal... use signal for your ICP routine, you definitely do not want that one to be pre-empted by another routine. For your USART Rx routine, use signal, read UDR (and USR if needed) immediately, and then enable global interrupts again, allowing it to be interrupted, before continuing to process the received data.

From the code you posted none of your interrupts appear to be too long to cause a problem, unless your ICP events are very close together (with the potential exception of the ICP handler, which appears to have been abbreviated). Your RX routine should boil down to a dozen or so clocks, if this is too much latency for you, then you should start thinking if the AVR has what it takes for your application. Or look at alternative ways to approach your problem, where timing is not quite so strict.

Writing code is like having sex.... make one little mistake, and you're supporting it for life.

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

EW wrote:
donblake wrote:
At least some of the AVR UARTS contain a small receive FIFO

Really? Which ones are these?

From the ATmega8 documentation:
Quote:
However, the receive buffering has two improvements that will affect the compatibility in some special cases:
• A second Buffer Register has been added. The two Buffer Registers operate as a circular FIFO buffer. Therefore the UDR must only be read once for each incoming data! More important is the fact that the Error Flags (FE and DOR) and the ninth data bit (RXB8) are buffered with the data in the receive buffer. Therefore the status bits must always be read before the UDR Register is read. Otherwise the error status will be lost since the buffer tate is lost.

Don

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

Problem Solved!!!

Thank you all very much for the help!!! I first changed my ICP interrupt from INTERRUPT to SIGNAL... which seemed to help the glitching problems, but not completely. I left my UART Rx interrupt using the SIGNAL keyword also. Then I took "glitch's" suggestion of enabling global interrupts with sei() in my UART Rx interrupt right after reading the character, and all of my glitching problems completely went away. Apparently my UART Rx interrupt was taking a bit too long and interfering with incomnig pulses on the ICP port, and enabling global interrupts just after the read in my UART ISR allowed them to still get processed.

Thank you very much for all of your help!

Sincerely,
James

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

Be wary, it may be possible for you to overflow your stack now. If a 2nd UART character is received before the first one is done processing, you will have multiple instances of your UART ISR on the stack. My 'suggestion' above was more of a work-around than a recommendation. I strongly suggest re-organizing your ISR's to be as short as possible, and leaving the heavy processing for your main loop.

Writing code is like having sex.... make one little mistake, and you're supporting it for life.

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

Thanks, Don, for the reference!

Eric