Is there a way to have INTF constantly watch the pins, but not execute the interrupt handler?

I need to monitor asynchronously if the INPUT pin is active for a period of time. The current practice is to set up an interrupt handler that sets a flag bool to true as soon as the pin is active. The main thread then periodically checks this flag and decides what to do based on its value. For example:

bool Flag;
static void SetFlag() {
  Flag = true;
}
void setup() {
  Flag = false;
  pinMode(18, INPUT);
  attachInterrupt(digitalPinToInterrupt(18), SetFlag, RISING);
}
void loop() {
  if (Flag) {
    Flag = false;
    //Do some time-consuming tasks
  } else {
    Flag = false;
    //Do something else
  }
}

However, I found that the function of this Flag variable and the hardware register EIFR are duplicative: they are both set to true when the pin is active. So I thought, can we just replace this flag with EIFR? Let loop() check the EIFR directly to decide what to do.

But the problem is, it doesn't seem like EIFR continues to monitor pins without enabling interrupts? However, if interrupts are enabled, the CPU will immediately call the interrupt handler when it sees that the EIFR is set, and then return the EIFR to false. At the same time, I can't use noInterrupts() to disable all interruptions, because I also need to use a timer. So is there some intermediate state in this system that allows the EIFR to keep an eye on the pin but not trigger the interrupt handler?

Not to put too fine a point on it, but so what? It works; move on.

Writing flags for each pin activity adds a lot of code complexity and degrades performance. If the hardware provides ready-made registers, I'd like to make the most of it.

One line of code, which compiles to a single machine instruction ("sbr").

That's quite an extraordinary claim, and does not match my experience. So I will not be losing any sleep over it or spending any time worrying about it.

HI, @ebolachan

Can you please tell us what your project is?
Where is the pulse coming from and what does detection of this pulse length do as an output?

Thanks.. Tom.. :smiley: :+1: :coffee: :australia:

Have you checked how many cycles the INTx ISR takes? I did count 41 for a 328P processor (interrupt on pin 2) so that's roughly 2.5 microseconds. You might be using a Mega or something else, not sure.

IMPLEMENT_ISR(INT0_vect, EXTERNAL_INT_0)
 400:	1f 92       	push	r1
 402:	0f 92       	push	r0
 404:	0f b6       	in	r0, 0x3f	; 63
 406:	0f 92       	push	r0
 408:	11 24       	eor	r1, r1
 40a:	2f 93       	push	r18
 40c:	3f 93       	push	r19
 40e:	4f 93       	push	r20
 410:	5f 93       	push	r21
 412:	6f 93       	push	r22
 414:	7f 93       	push	r23
 416:	8f 93       	push	r24
 418:	9f 93       	push	r25
 41a:	af 93       	push	r26
 41c:	bf 93       	push	r27
 41e:	ef 93       	push	r30
 420:	ff 93       	push	r31
 422:	e0 91 00 01 	lds	r30, 0x0100	; 0x800100 <__data_start>
 426:	f0 91 01 01 	lds	r31, 0x0101	; 0x800101 <__data_start+0x1>
 42a:	09 95       	icall
 42c:	ff 91       	pop	r31
 42e:	ef 91       	pop	r30
 430:	bf 91       	pop	r27
 432:	af 91       	pop	r26
 434:	9f 91       	pop	r25
 436:	8f 91       	pop	r24
 438:	7f 91       	pop	r23
 43a:	6f 91       	pop	r22
 43c:	5f 91       	pop	r21
 43e:	4f 91       	pop	r20
 440:	3f 91       	pop	r19
 442:	2f 91       	pop	r18
 444:	0f 90       	pop	r0
 446:	0f be       	out	0x3f, r0	; 63
 448:	0f 90       	pop	r0
 44a:	1f 90       	pop	r1
 44c:	18 95       	reti

Reading a port using direct port manipulation is faster.
An instruction like uint8_t pins = PINC which reads pins A0 to A5 in one go translates to a single machine instruction (328P processor) and hence 62.5 nanoseconds.

    uint8_t pins = PINC;
 67e:	26 b1       	in	r18, 0x06	; 6

If I remember correctly,on the ATmega328P, EIFR flags are set by pin events according to EICRA even if EIMSK is cleared, allowing you to poll them in loop() without triggering interrupts, while other enabled interrupts like timers keep working.

Did you try?

EDIT: I did not remember correctly. EIFR flags can only be cleared when the interrupt is actually triggered, and this happens automatically during the interrupt handling process

so no go.

EIFR is not a register to control a changing a pin, it is a register to indicate an interrupt firing . So it can't be used without of interrupt.

If you can do without interrupts then you can call cli(). The flags will then be set (I think) without any service routine being called. I'm not sure this is a practical solution though.

Yeah, EIFR latches that there was an interrupt until the bits are reset.
They get reset automagically when entering the ISR, but if you have the ISR disabled, you'll need to reset it manually by writing a one to the appropriate register bit...