Pin Change Interrupt calling twice?!

I set a Pin Change Interrupt on an ATMega644 MCU but the final result is not exactly what I expected.. Though the trigger is a clear, 500 Hz, 250 ns pulse width signal (comes form an AFE4490 chip Data Ready pin), the ISR is running twice:

pci2

What's more, sometimes, randomly, the second ISR is missing:

pci1

Well, it would be the normal case but the vast majority of interrupts are duplicated.

Here is the code:

void setup() {
  pinMode(PIN_PC1, INPUT); // PCINT17 pin defined as input

  cli();
  PCICR  = B00000100; // PORTC active for INT (PCINT23:16 pins enabled for interrupt)
  PCMSK2 = B00000010; // PCINT17 pin active
  sei();
}

ISR(PCINT2_vect) {
  // 10 µs pulse width square wave on PC7 to check ISR cycles:
  PORTC |= (1<<PC7); // set HIGH
  delayMicroseconds(10);
  PORTC &= ~(1<<PC7); // set LOW
}

I have no idea what's the problem...

  • George Cs. -

but should it be otherwise? There are two changes in the incoming impulse - first low to high, and then high to low, so interrupt fires twice

It sounds logic, but in this case why ISR is triggered sometimes just once? As you can see it in the second image.

Then maybe something like :

ISR(PCINT2_vect) {
  if ( PINC & B00000010 ) {  // PIN_PC1
    // 10 µs pulse width square wave on PC7 to check ISR cycles:
    PORTC |= (1<<PC7); // set HIGH
    delayMicroseconds(10);
    PORTC &= ~(1<<PC7); // set LOW
  }
}

I don't know for sure, I can only guess.
Your pulse is too short compared to the length of the interrupt itself, so the second interrupt has to wait for the first to finish. Probably in some cases something clears the wait flag before the second interrupt fires... but what - I have no idea.
If you want the interrupt to fire once - replace CHANGE irq with RAISING or FAILING

In this case nothing happens...

pci0

yes, because in time of interrupt the impulse is over

OK. what happens here ? :

ISR(PCINT2_vect) {
  // 10 µs pulse width square wave on PC7 to check ISR cycles:
  PORTC |= (1<<PC7); // set HIGH
  delayMicroseconds(10);
  PORTC &= ~(1<<PC7); // set LOW
  PCIFR = B00000100;  // clear interrupt flag explicitly (corrected)
}

(including correction by OP)

If you want the interrupt to fire once - replace CHANGE irq with RAISING or FAILING

As far as I know, Pin Change Interrupts cannot be set in this way.

Compiler didn't like it: " 'PIFC2' was not declared in this scope" :frowning:

you can choose the pin with External irq that supports failing and raising irq's

Sorry. Typo. PCIF2

PCIF2 doesn't relate to register, but meanwhile I found it on the atmega644 docs:

So I set it:

 PCIFR = B00000100;  // clear interrupt flag explicitly

And it works!!! I absolutely don't understand why this line must be inserted here, but it works!

Many thanks!!

obviously it resets the second interrupt flag

I see now that I gave you the bit mnemonic instead of the register name. I'm not familiar with that specific MCU but anyway you worked it out. It has simply cleared the pending second (unwanted) interrupt (as @b707 has said)

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.