Interrupt Question

I recently encountered a problem, that I am having difficulty solving. Can any please shed some light on this topic?

There is a hardware timer counter, which counts from 0 to 59. When it rollovers from 59 to 0 it will trigger an interrupt handler ISR1.


ISR1( ) ( will increase TS by 1). { #### A TS++; }

There is another interrupt handler ISR2, which can happen at anytime and has a higher priority than ISR1. ISR2 will want to get the exact time from the TS value and also the value of the hardware counter.

ISR2( ) {

... GetTime(); ...


What is a good way to implement this?

If ISR2 preempts ISR1 at instruction #### A, will it be able to get the correct values of TS and the hardware counter?

For example: If the hardware counter is at 0 and TS should be at 100, how do I ensure that I retrieve hardware counter 0 and TS=100 and not hardware counter 0 and TS=99.


Reply to
Adam Caruso
Loading thread data ...


I'd probably disable higher priority interrupts for a couple of instructions - but, in some systems, that may not be possible?

Mike Harding

Reply to
Mike Harding

I doubt it. This guy was posting about Unix and VxWorks back in 2001. I would guess that his college days were back at Towson in about 1997.

As for a real answer, this is a classic problem of developing a software extension to a hardware counter. It is a bit tricky to be sure that you have a consistent low-order and high-order part of the total counter (hardware plus higher-order software extension).

The fact that ISR2 has higher priority and can presumably interrupt ISR1 makes this especially difficult. You don't know in ISR2 whether you interrupted just before or just after the TS++ in ISR1. There is no way to tell from the information available to ISR2. Unless you change some groundrules, I would say the problem is unsolvable.

Here is a solution that requires changing some groundrules. Ensure that ISR2 is called at least three times in every counter overflow period. If this cannot be done, then provide a poll event of this frequency. At each such poll, sample the hardware counter. Compare the sampled count with the previous count, modulo 60. If the result is 0 to 30, then assume the count is just going up. If the result is

31 to 59, then assume the count has overflowed. In the case of overflow, do a TS++. Forget about ISR1 entirely. It is useless. Use this poll method to maintain a consistent TS and counter value. Do a poll on every ISR2 and if necessary at other times, often enough to ensure that you don't miss any overflows. That will work.

-Robert Scott Ypsilanti, Michigan

Reply to
Robert Scott

If the higher priority ISR2, which is caused by a higher priority but unrelated event to isr1, can stand to be off by one ISR1 time, record both the hardware timer and the TS counter. ISR1 must be able to shut off ISR2 some way, because incrementing its counter TS and saving the H/W is non-atomic. For instance with a "isr_disable" ISR1code "isr_enable" sequence. Using this, ISR1 can never interrupt ISR2, and ISR2 cannot interrupt ISR1 while it is updating the ram copy of TS and the hardware register.

There are many inherently racy conditions. If you guarantee a winner to all races that is ok. It is better to prevent the race and guarantee atomicity of data.

Regards ~Steve

Reply to
Steve Calfee

There is also a big processor dependency here. If the processor is 32-bit and TS is a 32-bit value, the incrementing process may be atomic. In that case, the TS value will either be correct, or may be one count low, as the timer has triggered ISR1 (which has not been serviced). In that case you can poll the hardware timer register to see if there is a pending interrupt from the timer. If so, make a local copy of TC and increment it.

If the incrementing process is not atomic, it gets a bit more complicated, as you may have to detect an increment in progress. You may be able to do this by having ISR1 update two copies of TC. If the first one is different from the second, an increment is in progress, and you can take appropriate action. (the action to take is intuitively obvious to the casual observer---as my physics prof. was fond of saying---yeah, right!)

I suspect there is even more complexity added if ISR1 has to update some timer hardware to keep the timing going. In that case, you may have to ensure that ISR2 doesn't take more than one timer tick.

How do you time the polling? What if some elements of the main program loop take longer than the desired polling interval? (I sometimes get into that area when doing operations with CF cards.)

It would help a bit if we knew whether TS was counting microseconds, milliseconds, or seconds. I hate to make assumptions based on

60 being some sort of magic number.

Mark Borgerson

Reply to
Mark Borgerson

Then this method won't work. The solution is very application-dependent. If you can guarantee that polling is never held off for more than 1/3 (actually 1/2, but I like to add some margin) of the overflow period then it will work.

I have used a method something like this to extend the 16-bit 8254 counter in regular PCs to a 32-bit count.

-Robert Scott Ypsilanti, Michigan

Reply to
Robert Scott

What processor do you use? Most motorola processors lock the low byte of their counters in a buffer if you access teh high byte first. This way, as long as you read the high byte first and then the low byte, you are sure of getting the value of the counter when you initiated the read.

Also there MPU/MCUs don't allow you to preempt and interrupt with another unless you explicitly clear the interrupt mask. The interrupt mask is set when you enter the interrupt.

-- Arya

Reply to

solving. Can

and has

from the



counter 0 and

Hi, If possible my approach would be to move the TS increamenting step to a task.I would make ISR1 to release a semaphore and make the task increamenting the value of TS to pend for it.At the task what ever I am increamenting,I will make another copy of it.Use that copy to read the updated value from another ISR. As far Aryas reply,masking may or maynot be involved in the OPs case.If masking is enabled then theres no question of ISR2 preempting ISR1.So from what he describes it seems that masking is not involved in his case.

Regards, s.subbarayan

Reply to

It seems that it is not possible to resolve the ambiguity of this problem within the constraints described.

As long as ISR1 can be interrupted the state of TS cannot be determined by ISR2 under all conditions.

There will always exist at least one meta state where the sequence of requests for ISR1 and ISR2 is unknowable.

Many methods have been described in this thread that can minimize this ambiguity. Most of them have been used to solve this problem in the real world but the only deterministic solution is to change the problem.

Reply to
Keyser Soze


Like... stop interrupts for a bit?

Mike Harding

Reply to
Mike Harding

Disabling interrupts can not fix the problem only reduce the occurrence rate. If it was homework you would be getting a D.

A high priority interrupt which depends on data generated in a low priority interrupt is a contradiction. Probably the result of fuzzy thinking in the system design or hardware restrictions.

If the interrupt priorities can be exchanged the solution is simple, otherwise some other agent is needed to help the high priority interrupt know the validity of data from the other or to do the work of the other in a different way.

Reply to

I would think that the solution is very hardware dependent. If the processor in question requires that an ISR re-enable ints if there is to be pre-emption by higher priority interrupts then there is no problem. Even thought ISR2 is a higher priority it can be blocked by ISR1 just by not enabling INTs in the routine. If the processor in question guarantees that the at least one instruction is executed in an ISR when it has occurred then make the first instruction a disable interrupts. Basically you need to use some way to temporarily raise the priority of ISR1 or consider it a critical section and block other INTs. You gotta' do a Kirk and change the parameters of the test ;).


Reply to
James Beck

Now that I REALLY think about it, there would still be a problem if ISR2 were running when the hardware timer overflowed. If ISR2 were being responded to when the hardware timer rolled over to 0 ISR1 would still be blocked and the counts would be wrong. Oh, well, I guess that's why we don't use interrupts in this manner, huh?


Reply to
James Beck

The relative priorities of the interrupts is a moot point. The third element (the timer) is running all the time, and cannot be interrupted (by definition). All that has to happen is for the timer to roll over between the time ISR2 is invoked and ISR2 actually reads the timer.

There really is no way to solve this problem without knowing the hardware involved. For example, if this were an AVR, I could simply (Ha!) 1) read the timer, 2) read the RAM value, 2) read the timer overflow interrupt flag, 3) if the interrupt flag is set, read the timer again and increment the value read from RAM. E.g.

ISR2() { uint8_t lsb; uint8_t msb;

lsb = TCNT0; // timer count register msb = timer0_msb; // incremented by T0 Ovf ISR

if (TIFR & _BV(TOV0)) // pending T0 Ovf interrupt { lsb = TCNT0; ++msb; }

timestamp = ((uint16_t)msb

Reply to
Dave Hansen

...and here is a solution that changes the problem a little bit.

Make ISR1 have higher priority than anything else that might be dealing with GetTime(), including ISR2. ISR1 can continue to be:

interrupt ISR1() {TS++;} //..whenever hardware counter overflows..

Now, when anybody (main program or ISR2) wants to get a consistent long time, it does this:


FirstTS = TS; //..initial fetch of overflow count LowOrderAnswer = hardware counter; SecondTS = TS; //..second fetch of overflow count if(sign bit of LowOrderAnswer is set) HighOrderAnswer = FirstTS; else HighOrderAnswer = SecondTS;

return (HighOrderAnswer with LowOrderAnswer);

If the hardware counter sign bit is set, you can be sure the first fetch of TS is consistent with it. If the hardware counter sign bit is not set, then you can be sure the second fetch of TS is consistent with it. Most of the time the two fetches of TS are the same. But on those occasions when they are different, this routine always picks the right one, provided ISR1 is enabled during this time.

-Robert Scott Ypsilanti, Michigan

Reply to
Robert Scott

In which case with the correct priorities ISR1 will have interrupted ISR2 and incremented the software timer extension. The only problem is when ISR1 occurs between ISR2 reading the software extension and the hardware timer which is simply detected by reading the software extension again and noting that any change must have been caused by a hardware timer rollover.

The OP stated the random (ISR2) interrupt will interrupt the timer (ISR1) handler.

Reply to

Redefining the problem to one where ISR2 is responsible to measuring the time of an event to a high resolution and ISR1 is responsible for keeping track of time over a long period. We can solve the ambiguity by adding another hardware counter.

The additional counter must have a roll over period longer than the interrupt rate of ISR1.

The addition counter is never reset by software and is used to provide time correlation between ISR1 and ISR2.

With this in place the solution is:

When ISR2 begins execution it:

1) Sample the time correlation counter.

2) Place the sample in a queue to be serviced by ISR1.

When ISR1 begins execution it:

1) Samples the time correlation counter.

2) Sample the number of events in the ISR2 queue.

3) Updates the long time period counter.

4) Process the events from the ISR2 time stamp queue and correlates them to the long time period counter.

5) Then posts ISR2 events for use by the application.

This solution limits the event signaling rate of ISR2 to the tick rate of ISR1.

The combined execution time of ISR1 plus all of the possible ISR2 interrupts must be less than the interrupt rate of ISR1. If not you will run out of real time and could only execute this on a quantum subspace controller.

------------------------------------------------- Quantum Subspace Controllerä a trademark of Yoyodyne Propulsion Systems. John Bigboote says: "Can't make an overthruster with out one."

Reply to
Keyser Soze

... snip ...

The reader needs to be at a lower priority than the timer. Then, to get a consistent set of values, the reader should:

  1. Read the register 2. Read the overflow counter. 3. Reread the register.

If the register counts agree, the reading is consistent, else go back to step 2. This time things should work, barring a foolishly short period between timer ticks.

"If you want to post a followup via, don't use
 the broken "Reply" link at the bottom of the article.  Click on 
 Click to see the full signature
Reply to

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.