How interrupts really work?

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

Hello all.
Let's look at this code

int main()
{
  //something
  for(;;)
  {
    sei();
    asm("nop");
    cli();
    //something
  }
   ...

Timer2 (8-bit) works in CTC mode and generates an interrupt every 10ms. I don't wont to be interrupted anywhere else in my code, except on the begining of the loop.
Datasheet says :
"When using the SEI instruction to enable interrupts, the instruction following SEI will be exectuted before any pending interrupts.."

So, my coude should execute SEI, then NOP and then CPU should execute any pending interrupts before executing CLI instruction? But that doesn't happen. No interrupts happen. If I put 5-6x nop-s same thing.

Why? What's wrong? How much "time" has to pass before CPU executes pending (int. flag set) interrupts after the SEI instruction?

Thank you very much !

Last Edited: Fri. Jul 27, 2007 - 04:02 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I'm looking......

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

I looked at the code - what now? Do you have any questions?

Markus

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

How long do we have to look?

Klaus
********************************
Look at: www.megausb.de (German)
********************************

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

Sorry guys, I accidentally pressed submit instead of preview :D

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

Just so you know that program (using GCC which it looks like you are using too) produces:

int main() 
{ 
  92:	cf 93       	push	r28
  94:	df 93       	push	r29
  96:	cd b7       	in	r28, 0x3d	; 61
  98:	de b7       	in	r29, 0x3e	; 62
  //something 
  for(;;) 
  { 
    sei(); 
  9a:	78 94       	sei
    asm("nop"); 
  9c:	00 00       	nop
    cli(); 
  9e:	f8 94       	cli
    //something 
  } 
  a0:	fc cf       	rjmp	.-8      	; 0x9a 

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

Are you sure there are pending interrupts? Because after calling sei() the corresponding interrupt service routines should immediately be called *if* there are any interrupt request flags set for interrupts you previously enabled. (each interrupt has an enable flag and a request flag. And watch out for setting the rising/falling edge right where possible, ISCxx flags)

Markus

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

Now we see a lot more....

Quote:
Why? What's wrong? How much "time" has to pass before CPU executes pending (int. flag set) interrupts after the SEI instruction?

Have you enabled the timer1 interrupt?

What´s your whole code?

Does your code really make sense? In my eyes an interrupt should be executed as soon as possible - in most cases.
Why don´t you just:
"if interrupt flag is set then do ... and clear interrupt flag"

Klaus
********************************
Look at: www.megausb.de (German)
********************************

Last Edited: Fri. Jul 27, 2007 - 04:08 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
Just so you know that program (using GCC which it looks like you are using too) produces:

Yes' it's OK, right?

I have some multitasking in that for(;;), so you don't think thats all the code :)

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

Uhh..OK I'll now copy-paste all my code. Please wait a little to delete everthing not important for interrupts.


#include 
#include 

volatile unsigned char count=0;

int main(void)
{
	LCDInit();
	I2CInit();
	//INT0 falling edge & pull up
	DDRD&=~(1<<PIN2);
	PORTD|=(1<<PIN2);
	MCUCR|=(1<<ISC01);
	GICR|=(1<<INT0);
		
//8-bit Timer2 na 10ms CTC mode
	OCR2=79;
	TIMSK=(1<<OCIE2);
	TCCR2=(1<<WGM21)|(1<<CS22)|(1<<CS21)|(1<<CS20);		

	for(;;)
	{
		sei();
		asm("nop");
		asm("nop");
		asm("nop");
		asm("nop");
		cli();
		//TASK_1
		if(count==0)
		{	
			//...
		}
		//TASK_2
		if(count>=90)
		{
			//...
			
			count=0;
		}
		//TASK_3
		//************************
		if((I2CStart())==0x08)
		{
		  //...	
		}
		 
	}
	return 0;
}

//Timer2 interrupt
ISR(TIMER2_COMP_vect)
{
	count++;
}
Last Edited: Fri. Jul 27, 2007 - 04:21 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

By the way, before we get any further please tell us that you are not using the AVR Studio simulator to test this code. It's support for timers is, frankly, abysmal.

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

clawson wrote:
By the way, before we get any further please tell us that you are not using the AVR Studio simulator to test this code. It's support for timers is, frankly, abysmal.

:D In AVR Studio every thing works fine, but when I flash ATmega8 things change to bad

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

Ah so you made the code work in the faulty simulator but it doesn't in a real AVR - well there's a surprise.

By the way how are you determining that "things chage to bad" in the mega8?

Presumably you are saying that you're not seeing the "if count>=90" work being done? Is that flashing an LED or something?

Remember that the simulator also goes 100's if not 1000's of times slower than a real AVR and if you are just flashing an LED that if you flash one at more than about 10-15 times a second you'll never see it flash (this is why TV and movies work!) and it'll just look like it's on all the time.

Cliff

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

clawson wrote:

/cut

Heh.. When I put SEI before

for(;;)

every thing works fine. When I put

sei();
asm(nop);
cli();

inside the loop it doesn't work any more.

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

I don't mean to hijack your thread but I'm super curious. Why do you only want to get interrupted in only one place in your code? I've never even been concerned about where I am when I get interrupted and now you have me curious.

Go electric!
Happy electric car owner / builder

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

Quote:
Heh.. When I put SEI before
...
every thing works fine. When I put

SEI before the loop and CLI inside the loop works? Can´t believe this.

Klaus
********************************
Look at: www.megausb.de (German)
********************************

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

sgomes wrote:
I don't mean to hijack your thread but I'm super curious. Why do you only want to get interrupted in only one place in your code? I've never even been concerned about where I am when I get interrupted and now you have me curious.

It's because some functions inside the loop has to be completed before INT0 happens.

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

MegaUSBFreak wrote:

SEI before the loop and CLI inside the loop works? Can´t believe this.

Uhh..that can't work. If I would do that no interrupts would happen after cli instruction executed.

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

I think that sgomes was suggesting that if there is only one point in your code where an interrupt can be handled then a simple flag set by the interrupt might be enough.
This is a generalisation, but usually one only disables interrupts in a critical section of code that cannot be disturbed. If you want to deal with an interrupt at a particular point in your program then you set a flag in the interrupt routine to notify the main program that it needs to do something.
sei and cli affect all interrupts. That might be undesirable too. (eg you have interrupt driven comms).

I hope this helps.

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

Broxbourne wrote:
/
/cut

Thank you for you're answer !

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

Like I said, I hope it helps.
Sometimes an interrupt only says something happened. There is not always a need to respond immediately. That is when flags are good.
Most of all, keep you interrupts simple and short to execute. While you are in an interrupt routine other actions are delayed/lost.
If you decide to disable interrupts within another interrupt routine, then you are piling on special cases that may eventually breakdown. Keep it simple.

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

Quote:
then a simple flag set by the interrupt might be enough.

I don´t find this useful.
Why only set a flag in the interrupt.

Why not use the interrupt flag itself?
No ISR required.
Check if interrupt flag is set, if so, then do some code and clear the flag.

Klaus
********************************
Look at: www.megausb.de (German)
********************************