Waking up interrupts inside a loop

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

Hi,

I'm building a software for Atmega644p @ 8Mhz which needs to run a timer interrupt quite accurately once every 16 ms to do some timing-critical tasks. In addition, I have some critical areas around the main program that may not be interrupted by this interrupt, that I have protected by enclosing them between cli() and sei(). I am absolutely positive that these protected areas do not take over 16 ms, but they are still making the timer interrupt lose it's sync.

What I'm unsure of, is whether my code should work as I intended. Let's say that I need to run do_something_minor() for 1000 times (which WILL take over 16 ms), and give a chance for the timer interrupt to run between these cycles. Should this kind of code work for that?

for (i=0; i<1000; i++) {
    cli();
    do_something_minor();
    sei();
    }

In practice it seems that the timer interrupt will not trigger inside the for-loop. Should I wait for some time after sei() to get it to trigger before doing cli() again? Is there a minimum delay for interrupts to start triggering after cli()?

regards,

Slintone

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

That loop will be something like

CLI
CALL do_something
SEI
BRANCH back

If an interrupt occurs the timer will set an IF flag bit. Once the SEI is executed at the next opcode fetch (the branch) the system will see the IF flag set and branch into the appropriate ISR. So, yes, this would allow a long process to be interrupted even if the chance is only given on the fetch of the BRANCH and the CLI

Cliff

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

Also remember that one instruction will execute after a sei, and cli is immediate, so if you juggled those instructions in the loop so a cli instruction follows the sei, it won't work. The 'invisible' rjmp/branch is sitting in the middle of those 2 instructions in your example (giving a chance for the irq between the branch and the cli).

(I assume this applies only when the I bit goes from 0->1, which a sei/reti would normally do. But if you had a sei/reti when the I bit was already set, I think the one instruction after sei does not apply. The datasheets don't really spell that out.)

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

slintone wrote:
I'm building a software for Atmega644p @ 8Mhz which needs to run a timer interrupt quite accurately once every 16 ms to do some timing-critical tasks. In addition, I have some critical areas around the main program that may not be interrupted by this interrupt, that I have protected by enclosing them between cli() and sei(). I am absolutely positive that these protected areas do not take over 16 ms, but they are still making the timer interrupt lose it's sync.
8 MHz/( (1/16)KHz ) = 128,000 is neither small nor a power of 2.
How are you getting it?
Are you assigning the timer a fixed value in the ISR?
If so, that could be the problem.
128,000 = 1024*125.
A prescale factor of 1024 and a TOP value
of 124 in CTC mode would do the right thing.
15 ms critical sections would still cause a lot of jitter,
but the average would be right.

Iluvatar is the better part of Valar.

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

Thanks for the input everyone. The interrupt is a timer overflow from a timer which is clocked from an external clock source. If my example in the first post should work, the problem must be somewhere else... I'll do some more debugging, lets see...