Interrupt Collisions - tips to minimize impact

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

I've recently found I'm seeing some issues with interrupts colliding, and I thought I'd check here with the experts to see if there are any tricks to minimize the problem.

This is currently on an ATmega8535.

I'm using two external interrupts to measure wheel RPM - a sensor on the wheels triggers the interrupts once per revolution and the interrupt routine calculates the RPM based on the elapsed count on the 16bit counter/timer 1

I'm also using an internal interrupt with a compare register on the 16 bit timer for a servo controller of the 1 to 2 msec pulse type. Here the interrupt routine toggles the output pin and updates the compare register based on how long it needs to wait for the next change.

The servo controller works great when the external interrupts aren't being triggered (e.g., wheels stopped). However, when I do run the wheels and trigger those external interrupts, the servo twitches, I assume because the external interrupts are throwing off the timing of the running of the internal interrupt that sets the servo control pulse timing

Here are my ideas:

+ increase the clock speed from 1MHz to 8MHz (adjust prescalers) so interrupts run faster

+ Change the RPM interrupt routines so that they save the counter value but then re-enable interrupts before doing any calculations

+ Switch to another ATmega that has a spare timer/counter I can use for the servo signal - this is a viable option, but it would be nice to stick with the current chip and the higher resolution I currently get on the servo control with my interrupt routine

I've also wondered if I can set some mode on the 16bit timer with a compare register so that the output pin is toggled by hardware when the compare matches, but then still have an interrupt routine that runs to calculate the next compare value.

Sorry for the long post, but this kind of brain teaser is what I like about programming, and I'm hoping someone with more knowledge will enjoy it too.

Thanks!
Tim

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

the most important tip: Keep your ISR's as short as possible. Do the absolute minimum in the ISR, service the hardware, set a flag, and exit. Leave any processing to be done lazily in your main-loop code. This will minimize the impact on any other interrupts that may be pending awaiting their turn at the CPU.

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

Quote:
I've also wondered if I can set some mode on the 16bit timer with a compare register so that the output pin is toggled by hardware when the compare matches, but then still have an interrupt routine that runs to calculate the next compare value.
Sure there is. Any of the PWM modes in fact. Just use either the compare match interrupts, or the overflow interrupt.

Regards,
Steve A.

The Board helps those that help themselves.

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

Thanks for the help glitch and Koshchi!

Quote:
the most important tip: Keep your ISR's as short as possible. Do the absolute minimum in the ISR, service the hardware, set a flag, and exit.

Thanks, I'll consider just saving the elapsed timer value and move the calculations to a routine called to get the RPM.

Quote:
Sure there is. Any of the PWM modes in fact. Just use either the compare match interrupts, or the overflow interrupt.

I kind of had that in mind, but I wasn't sure if it was okay to use a PWM mode that way (updating the compare register after each match). I might be running short on compare registers for the 16 bit timer. If I can use the same compare register in PWM mode both for a hardware output toggle and for triggering an interrupt service routine (to update the compare register's value), I'll be golden.

Thanks again!

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

Since you are trying to extract two timebases from the single 16-bit timer, I would go with the "leapfrog" method:

Use one compare register to record RPM timing info and generate an interrupt to initiate calculation.

Use another compare register to drive servo, using hw set/reset output pin on match. Generate an interrupt on each compare of this register as follows:
a) start of pulse (hw just drove the output pin HI): add value to compare register to get your servo pulse width, and set hw to drive pin LO on next match.
b) end of pulse (hw just drove output pin LO): add value to compare register to get 20ms servo window, or just fudge and add 18.5ms worth of time, and set hw to drive pin HI on next match.

The key is that you are using the hardware to both capture the exact input timing interval, and to output the extact servo pulse interval, so you will have no jitter. Your interrupts are not setting outputs or reading inputs, but only calculating the next values for automatic hardware driving. Thus, as long as you can always service each interrupt at some point before the corresponding signal time, you will have no glitches or twitches. The hw does the precise signal timing, and the interrupts are only used to calculate (at some leisure) the next hw settings.

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

Thanks kk6gm! I think that helps clarify the servo output. We'll see when I try to code it.

I'm not sure I fully understand the suggestion on the RPM measuring side:

Quote:
Use one compare register to record RPM timing info and generate an interrupt to initiate calculation.

I'm very sorry, but I don't follow that. I'm currently capturing the timing from the 16bit timer with an external interrupt triggered by a sensor on the wheel. Is there someway to use a compare register here that I'm not getting? I think I need the external interrupt to record the timing - can't see a way around that. Perhaps you're suggesting the compare register to trigger periodic calculation of the RPM (from the saved timings).

Thanks again!

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

Sorry, I wrote "compare register" when I meant "capture register". That's why I prefer the term "match" to "compare" since it's very different from "capture". You'll use a capture register that automatically gets updated when your sensor triggers the capture pin. That same event will generate a capture interrupt. If you're now driving an external interrupt pin from the sensor, that interrupt will go away, replaced by the capture interrupt.

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

Thanks for clarifying kk6gm. I think I should start using a capture register for at least one wheel. I have two wheels to measure RPM, and I think there's only one capture register, so I think one will have to rely on an interrupt routine to record the time for one wheel.

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

Oh well, there goes the elegance of the solution. Just do whatever you can to make sure the RPM interrupt(s) run with as little latency as possible.

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

if you have the ability to adjust the hardware design, you can add a mux infront of the ICP pin, and then alternate between sampling the RPM at each wheel. Not unlike how one could control multiple servos from a single PWM output.

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

glitch wrote:
if you have the ability to adjust the hardware design, you can add a mux infront of the ICP pin, and then alternate between sampling the RPM at each wheel. Not unlike how one could control multiple servos from a single PWM output.
Better yet, if three pins are available,
dedicate one to each wheel and have a wired and at the ICP pin.

"For every Christmas tree lit before Thanksgiving,
an elf drowns a baby reindeer"

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

"wired and" or "wired or" would work depending on polarity of the signal. However if the two events are very close together you can miss one.

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

After a quick thread review:

-- I'd think you are crippling yourself at 1MHz. Is there a reason to run so slow?

-- The mention of 8MHz and 1MHz seems to imply internal oscillator. Is that so? If so, how are you going to get any kind of accuracy on your input(s) and output(s)? In particular, how will you get (more or less) exactly 1.5ms so your servo doesn't drift?

-- There is hardware assist for counting using the Tn pins.

-- How can I ICP thee? Let me count the ways. ICP1 pin. Analog comparator using ACIC. Analog comparator and any of the ADC channels (if not using ADC) using ACME.

-- Why an '8535? Won't a '164 cost less and give you more toyz? (But still only one 16-bit timer.)

In any case, re-calculating every wheel RPM seems like overkill and can certainly bog you down at high speeds. Before going further, what are the max and min RPMs?

-- One servo? I guess I was thinking robot-type, with a sensor on each wheel and a servo for each wheel. So that would be two servos.

As the servo period is slow (in AVR terms) of min 1ms to react, a free-running timer1 would let you "leapfrog" OCR1A (or OCR1B) every hit. In a short ISR, you decide what to do at the next hit, and how many ticks ahead it is.

Now, if we do that on the 16-bit timer, we can't use T1. T0 is still there; the overflow on timer1 could trigger a capture of the T0 counts for one wheel.

For the other, ICP is available.

Now, one RPM and two servos is "cleaner". ;) You have to get into a pretty big AVR to get two 16-bit timers. Mega162 if you don't need A/D.
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

Great thoughts and suggestions, thanks!

I'm liking the mux idea, from Lee's comments, I'm thinking I can use the analog comparator and ACME to use it's built in mux to select the pin that's being used. I don't need ADC

Quote:
I'd think you are crippling yourself at 1MHz. Is there a reason to run so slow?
No reason, it'll be 8MHz

Quote:
The mention of 8MHz and 1MHz seems to imply internal oscillator. Is that so? If so, how are you going to get any kind of accuracy on your input(s) and output(s)? In particular, how will you get (more or less) exactly 1.5ms so your servo doesn't drift?
Yes, internal oscillator. Hadn't thought about accuracy/drift, I'll watch out for it.

Quote:
Why an '8535? Won't a '164 cost less and give you more toyz? (But still only one 16-bit timer.)
8535 because I had one, and I had a probably misguided desire to not use a chip that's overkill. This is for a hobby project, so the cost between the chips doesn't matter. I have a 644, and I might switch to that. But I had started on the 8535 and wanted to see what I could learn to make it work.

Quote:
In any case, re-calculating every wheel RPM seems like overkill and can certainly bog you down at high speeds. Before going further, what are the max and min RPMs?
RPM between 500 and 3,000. I think with the mux idea, I will not recalc every revolution. I'll have PID depending on the RPM, and that PID code will run about every 100msec

Quote:
One servo? I guess I was thinking robot-type, with a sensor on each wheel and a servo for each wheel. So that would be two servos.
It's for a pitching machine, for soft foam balls. The servo is a rocker to release the next ball.

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

glitch wrote:
"wired and" or "wired or" would work depending on polarity of the signal. However if the two events are very close together you can miss one.
That is why one uses three pins.
The non-ICP pins tell you who, possibly both, is talking.

Another possibility is to arrange for one signal
to be noticeably longer than the other.
There will be performance degradation.
A short signal tells you where it came from.
A long signal also tells you where it came from,
but might mask a short signal.
A very long signal implies overlapping signals
without telling you which came first.
If your data processing can live with those limitations,
you only need the ICP.

"For every Christmas tree lit before Thanksgiving,
an elf drowns a baby reindeer"

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

Thanks for the additional help.

Quote:
That is why one uses three pins.
The non-ICP pins tell you who, possibly both, is talking.

I'm not so sure on how I'd wire the three pins. I'm using a phototransistor as the sensor, and it's currently pulling down the external interupt pin (which has internal pullup on) when it senses a wheel revolution. So I gather I want the sensor on wheel one to pull down the ICP and a "wheel1" pin, while the sensor on wheel two pulls down the ICP and a "wheel2" pin.

So both have to pull down the ICP, but I have to avoid cross talk. What if I had diodes from the ICP to the "Wheel1" and "Wheel2" pins allowing current to flow from ICP to a "Wheeln" pin (but not reverse)?

That is:

Wheel1Pin ---|<--- ICP --->|--- Wheel2Pin

(where '|<' and '>|' are diodes)

So if I pull down a wheel pin, it will pull down the ICP, but not the other wheel's pin??

You can tell I fumble my way through the electronics parts of this project.

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

timwhunt wrote:
So both have to pull down the ICP, but I have to avoid cross talk. What if I had diodes from the ICP to the "Wheel1" and "Wheel2" pins allowing current to flow from ICP to a "Wheeln" pin (but not reverse)?

That is:

Wheel1Pin ---|<--- ICP --->|--- Wheel2Pin

(where '|<' and '>|' are diodes)

So if I pull down a wheel pin, it will pull down the ICP, but not the other wheel's pin??

Correct.

"For every Christmas tree lit before Thanksgiving,
an elf drowns a baby reindeer"