Go Down

Topic: Problems using interrupts  (Read 525 times) previous topic - next topic

sterretje

I'm not talking about the interrupt enable bit; for each interrupt there is a bit in a register that indicates that the interrupt occurred; for the external interrupts, look at the EIFR register description

Quote
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 Ibit
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.
I've added the emphasis.

Further
Quote
When an interrupt occurs, the Global Interrupt Enable I-bit is cleared and all interrupts are disabled. The user software can write logic one to the I-bit to enable nested interrupts. All enabled interrupts can then interrupt the current interrupt routine. The I-bit is automatically set when a Return from Interrupt instruction - RETI - is executed.
Emphasis added.

Both quotes are taken from ATmega48A/PA/88A/PA/168A/PA/328/P [DATASHEET], Atmel-8271J-AVR- ATmega-Datasheet_11/2015.
If you understand an example, use it.
If you don't understand an example, don't use it.

Electronics engineer by trade, software engineer by profession. Trying to get back into electronics after 15 years absence.

GolamMostafa

Yes! The interrupt flag is automatically cleared when the MCU vectors at the corresponding ISR. This is the flag that actually triggers the interrupt logic; therefore, it has to be cleared so that the same interrupt source can again trigger the interrupt logic once the MCU returns to the Main Line Program (MLP). I have edited my Post#14 based on your information of Post#15.



gfvalvo

#17
Oct 12, 2018, 02:34 pm Last Edit: Oct 12, 2018, 09:47 pm by gfvalvo
OP: Your technique of constantly attaching / detaching interrupts is too much work. And, it's inelegant / ugly. Much better to just ignore the extra interrupts. Something like this (untested, but it compiles):
Code: [Select]
enum states {waitingInt1 = 0, waitingInt2, resultReady, resetDelay};
volatile uint8_t currentState = waitingInt1;

const uint8_t vibPin1 = 2;
const uint8_t vibPin2 = 3;
const uint8_t ledPin = 13;

volatile uint32_t int1Time;
volatile uint32_t int2Time;
volatile uint32_t stateTimer;
uint32_t timeInterval;
const uint32_t maxWaitTime = 1 * 1000UL;
const uint32_t resetTime = 5 * 1000UL;


void setup() {
  Serial.begin(115200);
  pinMode(vibPin1, INPUT);
  pinMode(vibPin2, INPUT);
  pinMode(ledPin, OUTPUT);
  attachInterrupt(digitalPinToInterrupt(vibPin1), pin1_ISR, RISING);  // Just use one edge from sensor. RISING or FALLING, not CHANGE
  attachInterrupt(digitalPinToInterrupt(vibPin2), pin2_ISR, RISING);  // Just use one edge from sensor. RISING or FALLING, not CHANGE
}

void loop() {
  uint32_t localInt1Time, localInt2Time, interval;

  uint32_t currentMillis = millis();
  noInterrupts();
  switch (currentState) {
    case resultReady:
      currentState = resetDelay;
      localInt1Time = int1Time;
      localInt2Time = int2Time;
      stateTimer = millis();
      interrupts();
      interval = localInt2Time - localInt1Time;
      Serial.print("Interrupt 1 Time = ");
      Serial.println(localInt1Time);
      Serial.print(", Interrupt 2 Time = ");
      Serial.println(localInt2Time);
      Serial.print(", Interval Time = ");
      Serial.println(interval);
      Serial.println();
      break;

    case waitingInt1:
      interrupts();
      break;

    case waitingInt2:
      // See if we've waited too long for second interrupt
      if ((currentMillis - stateTimer) >= maxWaitTime) {
        currentState = waitingInt1;
      }
      interrupts();
      break;

    case resetDelay:
      // See if reset delay has expired
      if ((currentMillis - stateTimer) >= resetTime) {
        currentState = waitingInt1;
      }
      interrupts();
      break;

    default:
      interrupts();
      break;
  }
}

void pin1_ISR() {
  if (currentState == waitingInt1) {
    int1Time = micros();
    stateTimer = millis();
    currentState = waitingInt2;
  }
}

void pin2_ISR() {
  if (currentState == waitingInt2) {
    int2Time = micros();
    currentState = resultReady;
  }
}

GolamMostafa

#18
Oct 12, 2018, 02:59 pm Last Edit: Oct 12, 2018, 03:03 pm by GolamMostafa
@gfvalvo (Post#17)

Is it essential to execute the following two pinMode() instructions when the attachInterrupt() automatically configures the DPin-2 and DPin-3 as interrupt lines?
Code: [Select]
pinMode(vibPin1, INPUT);
pinMode(vibPin2, INPUT);

gfvalvo

Is it essential to execute the following two pinMode() instructions when the attachInterrupt() automatically configures the DPin-2 and DPin-3 as interrupt lines?
Code: [Select]
pinMode(vibPin1, INPUT);
pinMode(vibPin2, INPUT);

Perhaps not. But, it doesn't hurt anything and is only executed ONCE in setup(). So, why would you care?

Plus, it makes what's going on explicitly clear.

GolamMostafa

So, why would you care?
A poster takes time for his readers, and he expects feedback? 

DKWatson

By default all I/O pins are configured as INPUT (on AVR processors) and all global variables are initialized to zero/NULL. This may not be the case on other platforms with other compilers. As @gfvalvo rightly pointed out, it never hurts and is considered good programming style to initialize everything.
Live as if you were to die tomorrow. Learn as if you were to live forever. - Mahatma Gandhi

GolamMostafa

#22
Oct 12, 2018, 04:36 pm Last Edit: Oct 12, 2018, 04:37 pm by GolamMostafa
As @gfvalvo rightly pointed out, it never hurts and is considered good programming style to initialize everything.
Doing so, I am afraid that we are undermining the tremendous efforts that the Arduino Team are employing to facilitate our Arduino Platform based programming jobs?

gfvalvo

Of course, the point is not at all germane to the OP's question.

wbanz

OP: Your technique of constantly attaching / detaching interrupts is too much work. And, it's inelegant / ugly. Much better to just ignore the extra interrupts. Something like this (untested, but it compiles):
Many thanks for taking the time to provide a detailed suggestion to solve why problem. It is appreciated.
One of the problems I have is that I do not know which interrupt is going to occur first and using interrupt/nointerrupt it did not work as I had expected so I switched to turning off the specific interrupt which occurred first etc.
However, even using no interrupt I had the same problem, and that is that if other interrupts are received, one of them is saved when interrupts are turned off, and it is processed when interrupts are turned back on.

My problem is purging that saved interrupt - I need it to go away, which is what I thought     EIFR = bit (INTF0
    EIFR = bit (INTF1); should do, but it does not.

gfvalvo

Again, you don't need to "purge" the extra interrupts, just IGNORE them. The code I posted does just that. Once a given interrupt occurs the ISR just ignores subsequent firings of the same interrupt until the two-interrupt sequence and reset delay is complete.

My code works under the assumption that vibPin1 always occurs first. Guess maybe I didn't read your original post carefully enough. Anyway the state machine technique I posted can easily be adapted to work when EITHER interrupt occurs first.

wbanz

Again, you don't need to "purge" the extra interrupts, just IGNORE them. The code I posted does just that. Once a given interrupt occurs the ISR just ignores subsequent firings of the same interrupt until the two-interrupt sequence and reset delay is complete.

OK, I misunderstood what you meant by ignore but understand how you have implemented that.
Many thanks. This has been really helpful.

DKWatson

An alternative is to clear all interrupt flags before exiting the ISR as these will have been set if an interrupt occurred while global interrupts was disabled. This is how the processor knows there's a pending interrupt.
Live as if you were to die tomorrow. Learn as if you were to live forever. - Mahatma Gandhi

wbanz

An alternative is to clear all interrupt flags before exiting the ISR as these will have been set if an interrupt occurred while global interrupts was disabled. This is how the processor knows there's a pending interrupt.
I Guess that was my initial question - how do you clear all interrupt flags?

DKWatson

You have a copy of the datasheet?
Live as if you were to die tomorrow. Learn as if you were to live forever. - Mahatma Gandhi

Go Up