ISR processing time [Solved]

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

Toggling an LED in a while loop takes about 2.5uS with a 3.6864MHz xtal.

Using the following code:

#include  
#include 


// F_CPU defined in the makefile as 3.6864MHz
#define RED_LED_PORT PORTC
#define RED_LED_DDR DDRC
#define RED_LED_DATA_BIT PC2

#define FOREVER for(;;)


volatile uint8_t flag = 0;


int main(void)
{
// PortD, all inputs pull up enabled
   DDRD = 0x00;  // 0000 0000
   PORTD = 0xFF; // 1111 1111

// initialise INT0   
   EIMSK &= ~(1<<INT0); // disable INT0 to ensure no interrupts are generated
   EICRA  = 0x00;        // make sure all bits are zero (low level on INT0 generates interrupt)
   EIFR   = (1<<INTF0); // clear any pending interrupts, note: = not |=
   EIMSK |= (1<<INT0);  // enable INT0

// set PC2 to output
   RED_LED_DDR  |= (1<<RED_LED_DATA_BIT);
   
   sei();
   
   FOREVER
   {
      if (flag == 1)
      {
         flag = 0;
         
         RED_LED_PORT ^= (1<<RED_LED_DATA_BIT);
      }   
   }   
}

ISR (INT0_vect)
{
   flag = 1;
}

increases this toggle time to 1.5mS, ie 1000 times slower.

Am I doing something wrong?

Thanks,
davef

Last Edited: Tue. Nov 8, 2011 - 09:08 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If you have selected a level interrupt, consider what happens when the level is always low.

The IRQ fires forever. As soon as you finish processing the ISR(), it executes one instruction in the foreground and services the ISR() again ... and again ...

If you choose level IRQs you normally disable afterwards, or change the level, or anything ...

David.

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

Thank you, now I see. I am just trying to work out how quickly an interrupt can toggle a port. I'll think a bit harder!

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

Ah, 25uS . . . that's better!

#include  
#include 


// F_CPU defined in the makefile as 3.6864MHz
#define RED_LED_PORT PORTC
#define RED_LED_DDR DDRC
#define RED_LED_DATA_BIT PC2

#define FOREVER for(;;)


volatile uint8_t flag = 0;


int main(void)
{
// PortD, all inputs pull up enabled
   DDRD = 0x00;  // 0000 0000
   PORTD = 0xFF; // 1111 1111

// initialise INT0   
   EIMSK &= ~(1<<INT0); // disable INT0 to ensure no interrupts are generated
   EICRA  = 0x00;        // make sure all bits are zero (low level on INT0 generates interrupt)
   EIFR   = (1<<INTF0); // clear any pending interrupts, note: = not |=
   EIMSK |= (1<<INT0);  // enable INT0

// set PC2 to output
   RED_LED_DDR  |= (1<<RED_LED_DATA_BIT);
   
   sei();
   
   FOREVER
   {
      if (flag == 1)
      {
         flag = 0;
         
         RED_LED_PORT ^= (1<<RED_LED_DATA_BIT);
         EIMSK |= (1<<INT0);  // enable INT0
      }   
   }   
}

ISR (INT0_vect)
{
   flag = 1;
   EIMSK &= ~(1<<INT0);
}

Thanks again.
Dave

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

If speed is the issue here why use interrupts anyway? The fastest way to react to an inbound event would be to poll the input state of the pin in a tight loop and set the output as soon as the input is seen to change. Entry to ISRs is typically going to take 20..30 cycles and may also suffer from one or two cycles of jitter depending on the foreground opcode that has to finish.

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

Because I thought interrupts were faster :( I see what you are getting at. So, use an oscilloscope triggered off the input pin change to measure the delay to set some output pin?

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

int main(void) {
	DDRB = (1 << 0);
	while(1) {
		if (PINB & (1 << 1)) {
			PORTB |= (1 << 0);
		}
	}
} 

generates:

	DDRB = (1 << 0);
  be:	81 e0       	ldi	r24, 0x01	; 1
  c0:	87 bb       	out	0x17, r24	; 23
	while(1) {
		if (PINB & (1 << 1)) {
  c2:	b1 9b       	sbis	0x16, 1	; 22
  c4:	fe cf       	rjmp	.-4      	; 0xc2 
			PORTB |= (1 << 0);
  c6:	c0 9a       	sbi	0x18, 0	; 24
  c8:	fc cf       	rjmp	.-8      	; 0xc2 

Kind of tricky to get any tighter than that.

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

Good that looks like a few cycles there. However, isn't there a problem in that while you are in this tight loop you can't do anything else?

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

Quote:

isn't there a problem in that while you are in this tight loop you can't do anything else?


Yes. It's your choice - do you need the very fastest response possible or are you willing to sacrifice that for the ability to do some other work. There comes a point (after not very long) when ISR is the "fastest" response.

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

What is the aim of this exercise? Fastest response to toggle a port pin responding to an external event?

Or repetitive toggling--e.g., generating a square wave?

Besides telling the goal, tell what AVR model you are using.

We can infer what toolchain. That toolchain isn't known for skinny ISRs.

2.5us @3.6864MHz? 9 or 10 clocks? SBI+RJMP is 4 clocks.

SBI+RETI right in the vector table should get the toggle done in 5-8 clocks, and ready for another event (repeated) in about 12 clocks.

A skinny conventional ISR would add a couple more clocks for the RJMP/JMP to the ISR. Good luck with the infinite-value toolchain unless you want to go naked.

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

Quote:

That toolchain isn't known for skinny ISRs

Ah but remember that toolchain contains an assembler - the world is your oyster!

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

theush,

Quote:
Fastest response to toggle a port pin responding to an external event?
Yes.

WinAVR and the ATmega88/328 series. With a 16MHz clock that time should drop to 0.5uS, which effectively removes this concern from the list of issues.

Thanks,
Dave

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

Quote:

With a 16MHz clock that time should drop to 0.5uS, which effectively removes this concern from the list of issues.

Tell me again how you will see a change in the state of an AVR output pin <=500ns, 8 AVR clocks, with a GCC ISR.

I'd like to see the solution.

(Why not just use a flip-flop?)

Lee

[edit] But now comes the fun part. How can I do this with an AVR? Pick one edge of the trigger signal--say, rising. Set up an AVR timer with external clock on the Tn pin. Set up the timer in CTC mode, with a compare match of 0. Set the output pin to Toggle on Compare Match.

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

Using the 2nd code clip, 3rd posting from the top.

I am just holding INT0 low, toggling an output port and use a 'scope to watch what is going on.

As well as looking at two transitions I also read the timebase setting incorrectly :oops:

At 3.6864MHz each transition is 12uS long. I apologise for the error.

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

Quote:

Using the 2nd code clip, 3rd posting from the top.

No way in h... is that going to toggle any LED in 8 AVR clocks.
...
Quote:

At 3.6864MHz each transition is 12uS long.

OK, that makes a bit more sense. 45 clocks. With some jitter.

I'm way confused now. You are just letting a low-level interrupt fire? What practical use is that in the real world? I thought the goal was to

Quote:

Fastest response to toggle a port pin responding to an external event?
Yes.

What event is that?

Perhaps if you tell what you need to do then solutions become more obvious. For example, you have ignored/discarded the flip-flop mention. You pay no attention to an alternate method using a timer. And you are still XORing a port bit when Atmel gave us a SBI pin toggle on newer AVR models. And we still don't know if these are repetitive events, and if so how far apart.

I guess I'm out of this game unless I get a clear understanding of the rules.

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

theusch,

Quote:
What event is that?

Eventually, I was going to provide a level change and use the pin change interrupt capability on the ATmega88.

It is probably no use in the real world. In my fumbling attempt I was just trying to get an idea of long it would take a port to react to one interrupt. I could have set the 'scope up to trigger on one interrupt and try to measure the delay to the output changing, but thought that doing it repetitively would mean that I wouldn't need to actually provide an interrupt source.

The flip-flop idea didn't seem appropriate as I want the uP to do "other stuff".

Thank you for hint about the SBI pin toggle, I'll look into that.

The events are repetitive and I was just trying to see how much I could reduce the time between those events.

I am happy with the results and even happier with the SBI suggestion.

Cheers,
davef