amazed
July 11, 2023, 7:04am
1
Hello,
Speaking of ATmega328P, what would be the correct/best order to attach/detach an interrupt and clear its flag?
For example when detaching an interrupt:
noInterrupts();
EIFR = bit(INTF0); //clear interrupt flag
detachInterrupt(digitalPinToInterrupt(RTC_INT_PIN));
interrupts();
In case of an edge or logic change happens between flag clear and detaching the interrupt, the flag could be set again and after enabling interrupts globally, the corresponding interrupt vector could be executed?
Edit: I just found a hint at EIFR register description:
Bit 1 – INTF1: External Interrupt Flag 1
When an edge or logic change on the INT1 pin triggers an interrupt request, INTF1 becomes set (one). If the I-bit in SREG and the INT1 bit in EIMSK are set (one), the MCU will jump to the corresponding interrupt vector. The flag is cleared when the interrupt routine is executed. Alternatively, the flag can be cleared by writing a logical one to it. This flag is always cleared when INT1 is configured as a level interrupt.
So External Interrupt Request 0 Enable (INT0
in EIMSK
) and External Interrupt Flag 0 (INTF0
in EIFR
) bit has to be set for corresponding interrupt vector execution? Based on this, the order might not matter.
J-M-L
July 11, 2023, 7:11am
2
why would you clear the flag upon detaching the interrupt? once it's detached, you won't trigger anyway
if it's an issue, it's best done when you attach the ISR if you don't want to be annoyed by pending interrupts
there is an open issue on this topic
opened 06:36PM - 15 Nov 12 UTC
This is [Issue 510](http://code.google.com/p/arduino/issues/detail?id=510) moved… from a Google Code project.
Added by 2011-03-23T05:33:55.000Z by [kylehard...@gmail.com](http://code.google.com/u/109794696396332004807/).
Please review that bug for more context and additional comments, but update this bug.
Original labels: Type-Defect, Priority-Medium, Component-Core
### Original description
**What steps will reproduce the problem?**
Use this code:
```arduino
/*
Attach your interrupt signaling button to DPIN2
Attach you attachInterrupt button to DPIN13
Fire up the serial monitor:
The first number shows if the interrupt is currently attached.
The second number shows if the interrupt is in a signaled state, i.e. if it is prepared to fire off the ISR.
Note that in normal operation, this interrupt ready flag is unset immediately upon call of the ISR.
The third number shows a count of the calls to isrSignal, within which it is incremented by 1.
Follow these steps:
Trigger your interrupt signaling button once.
You will see that the interrupt is detached by (EIMSK & 0x1) being 0.
(EIFR & 1) will be 0, as the trigger flag is not seen at this point in the code: The interrupt triggers and the flag is cleared.
The count will be 1.
Trigger the interrupt signal button again.
EIMSK & 1 will not change: The interrupt was already not attached.
EIFR & 1 will now be 1, because the interrupt flag signals regardless of whether an interrupt is attached.
The count will still be 1, as the ISR was not called due to the interrupt not being attached.
Now press your attachInterrupt button to cause the interrupt to be reattached.
EIMSK & 1 will be 1. The ISR is reattached.
EIFR & 1 will be 0: The flag has been cleared.
The count will be 2. This is wrong, it should be 1 as the ISR should only have been called
once: The first time the interrupt button was pressed. The second time the button was pressed,
the interrupt was not attached, so the user does not expect intervening triggers of the interrupt
to cause an immediate call to the ISR upon reattachment.
*/
# define INTERRUPT_SIGNAL_PIN 2
# define ATTACH_INTERRUPT_PIN 13
volatile boolean signaled = false;
volatile long signalCounter = 0;
void setup () {
Serial.begin(115200);
pinMode(INTERRUPT_SIGNAL_PIN,INPUT);
pinMode(ATTACH_INTERRUPT_PIN,INPUT);
attachInterrupt(0,isrSignal,RISING);
}
void loop () {
if (digitalRead(ATTACH_INTERRUPT_PIN) == HIGH) {
attachInterrupt(0,isrSignal,RISING);
}
Serial.print( EIMSK, BIN );
Serial.print(' ');
Serial.print( EIFR, BIN );
Serial.print(' ');
Serial.println( signalCounter );
}
void isrSignal () {
detachInterrupt(0);
signalCounter++;
signaled = true;
}
```
**What is the expected output? What do you see instead?**
Explained in the comment in the code.
**What version of the Arduino software are you using? On what operating**
**system? Which Arduino board are you using?**
This issue is seen in version 0022 of the IDE on Windows XP using a Duemilanove. However, this issue has nothing to do with any of this: See below.
**Please provide any additional information below.**
The solution to this issue is to read the datasheet for certain Atmegas, for example the 1284P, which on page 69 says:
When changing the ISCn bit, an interrupt can occur. Therefore, it is recommended to first disable INTn by clearing its Interrupt Enable bit in the EIMSK Register. Then, the ISCn bit can be changed. Finally, the INTn interrupt flag should be cleared by writing a logical one to its Interrupt Flag bit (INTFn) in the EIFR Register before the interrupt is re-enabled.
This is in reference to attaching an interrupt and is in the EICRA subsection of the External Interrupts section.
The short version: The interrupt flag should be unset when an interrupt is attached, otherwise the ISR can be triggered immediately upon attachment.
The fix involves a modification to WInterrupts.c. Currently, there is a switch() full of #ifs, each condition containing a variation of the following two lines of code:
```
EICRA = (EICRA & ~((1 << ISC00) | (1 << ISC01))) | (mode << ISC00);
EIMSK |= (1 << INT0);
```
The first line sets EICRA, which determines under which interrupt triggers conditions an ISR will be triggered (RISING, FALLING, etc.). The second line activates the correct bit in EIMSK high, which enables the external interrupt pin.
The fix is the addition of two more lines of code:
```
EIMSK &= ~(1 << INT0); //Added
EICRA = (EICRA & ~((1 << ISC00) | (1 << ISC01))) | (mode << ISC00);
EIFR |= (1 << INTF0); //Added
EIMSK |= (1 << INT0);
```
The first added line makes sure that the external interrupt pin is disabled while changing the value of EICRA, as recommended in the datasheet. The second added line clears the interrupt triggered flag. It looks like the flag is being set by use of |=, but this is the correct method. See page 69: "Alternatively, the flag can be cleared by writing a logical one to it."
This fix is tested and fully working.
The first added line of code, which disables the external interrupt pin, is not required for this specific fix. However, it is recommended in the datasheet and seems to be able to help in certain fringe conditions.
amazed
July 11, 2023, 7:37am
3
So both INT0
in EIMSK
and INTF0
in EIFR
bit has to be set for corresponding interrupt vector execution.
Thanks, this was not clear.
J-M-L
July 11, 2023, 7:40am
4
you can see what they do in the source code for void detachInterrupt()
basically playing just with EIMSK
void detachInterrupt(uint8_t interruptNum) {
if(interruptNum < EXTERNAL_NUM_INTERRUPTS) {
// Disable the interrupt. (We can't assume that interruptNum is equal
// to the number of the EIMSK bit to clear, as this isn't true on the
// ATmega8. There, INT0 is 6 and INT1 is 7.)
switch (interruptNum) {
#if defined(__AVR_ATmega32U4__)
case 0:
EIMSK &= ~(1<<INT0);
break;
case 1:
EIMSK &= ~(1<<INT1);
break;
case 2:
EIMSK &= ~(1<<INT2);
break;
case 3:
EIMSK &= ~(1<<INT3);
break;
case 4:
This file has been truncated. show original
amazed
July 11, 2023, 7:46am
5
Yes, I saw that. That's why I started to refer to INT0
in EIMSK
.
system
Closed
January 7, 2024, 7:46am
6
This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.