HELP: Not able to capture pin change value

Hello Everybody,

I started doing some experiments to explore interrupt driven approaches and encountered something strange. My PCINT ISR is firing alright but I am not able to capture the Port state afte the change had happened. I am using a UNO board.

My setup is simple. I have one UNO (UNO-1) board that I am using as stimulus generator. I have started a I2C master on this UNO using wire library and it sends a message once every 5 seconds. I am monitoring the SCL pin (A5) using a Digital oscilloscope. The captured waveform on the scope correctly shows SCL to have a period of 10us (100KHz). The SCL pin changes state every 5us during a I2C transfer. So far so good...

I have taken another UNO (UNO-2), and connected GND of both boards. A wire from SCL of UNO-1 is connected to A1 pin of UNO-2.

My small sketch running on UNO-2 is to print the PORTC value (A0-A5 is part of PORTC) after the first change. I hold the reset button of UNO-1, then open Serial monitor of UNO-2 (which restarts UNO-2), wait for 5-7 seconds to make sure A1 is not changing on UNO-2, and then release UNO-1 reset. The pin change happens on A1 as expected and the ISR fires.

But the value of the PORTC that is captured inside ISR is not showing the changed pin state. Since I have activated pull up on A1, the initial state of A1 should be 1 and it is. Hence when A1 pin change ISR fires, A1 must have gone Low and I would expect the value of bit[1] of PORTC to be 0. But the captured value of A1 still shows High.

Here is my Sketch.

// Include the required Wire library for I2C

int a1_pin_change_cnt=0;
bool cap1=false;
bool printed = false;
byte portc_val=0;

void setup() {
  delay(1000);
  Serial.begin(9600);
  InitialiseIO();
}

void InitialiseIO(){
  Serial.println("Initializing");
  Serial.print("PORTC Value (Binary) Before Pin Config= "); Serial.println(PORTC, BIN);
  pinMode(A1, INPUT);
  digitalWrite(A1, HIGH);   // Configure internal pull-up resistor
  Serial.print("PORTC Value (Binary) After Pin Config= "); Serial.println(PORTC, BIN);
  
  //Interrupt Setup
  cli();    // switch interrupts off while messing with their settings  
  PCICR =0x02;          // Enable PCINT1 interrupt
  PCMSK1 = 0b00000010; //Mask all except A1
  sei();    // turn interrupts back on
  Serial.println("Init Done");

}

ISR(PCINT1_vect) {
  // Interrupt service routine. Every single PCINT8..14 (=ADC0..5) change
  // will generate an interrupt: but this will always be the same interrupt routine

  //Capture value of PORTC after the first pin change 
  if (!cap1) {
    //Wait for A1 to settle down to its new level
    //delayMicroseconds(1); //As of Arduino 0018, delayMicroseconds() no longer disables interrupts.
    portc_val = PORTC; //capture PORTC value
    cap1 = true; //Stop capturing
  }
  a1_pin_change_cnt++;
}

void loop() {
  Serial.println(a1_pin_change_cnt);
  delay(1000); //delay function does not disable interrupts

  if (cap1 && !printed) {
    Serial.print("Captured PORTC Value (Binary) after A1 Pin change= "); Serial.println(portc_val, BIN);
    printed = true;
  }
 
}

And here is Serial Monitor Log

Initializing
PORTC Value (Binary) Before Pin Config= 0
PORTC Value (Binary) After Pin Config= 10
Init Done
0
0
0
0
0
0
0
0
0
0
Captured PORTC Value (Binary) after A1 Pin change= 10
20
20
20
20
20
40
40
40
40
40
60
60

The Oscilloscope shows 20 changes in SCL for each transfer and a1_pin_change_cnt in my code is showing increment of 20. SO, the ISR is firing properly.

I have kept the ISR extremely small. I even inserted a 1 microsecond delay between pin change and value capture to make sure A1 settles down to its new value. But this did not help. A1 still shows '1'.

It will be of great help for my learning if anybody can point my mistake.

Best Regards,
Kish

All the variables used by the ISR and loop() need to be volatile. None of yours are.

Thanks Paul for pointing it out. I now made 3 variables volatile. But I still don't seem to get the changed A1 value.

This is new sketch now...

// Include the required Wire library for I2C

volatile int a1_pin_change_cnt=0;
volatile bool cap1=false;
bool printed = false;
volatile byte portc_val=0;

void setup() {
  delay(1000);
  Serial.begin(9600);
  InitialiseIO();
}

void InitialiseIO(){
  Serial.println("Initializing");
  Serial.print("PORTC Value (Binary) Before Pin Config= "); Serial.println(PORTC, BIN);
  pinMode(A1, INPUT);
  digitalWrite(A1, HIGH);   // Configure internal pull-up resistor
  Serial.print("PORTC Value (Binary) After Pin Config= "); Serial.println(PORTC, BIN);
  
  //Interrupt Setup
  cli();    // switch interrupts off while messing with their settings  
  PCICR =0x02;          // Enable PCINT1 interrupt
  PCMSK1 = 0b00000010; //Mask all except A1
  sei();    // turn interrupts back on
  Serial.println("Init Done");

}

ISR(PCINT1_vect) {
  // Interrupt service routine. Every single PCINT8..14 (=ADC0..5) change
  // will generate an interrupt: but this will always be the same interrupt routine

  //Capture value of PORTC after the first pin change 
  if (!cap1) {
    //Wait for A1 to settle down to its new level
    //delayMicroseconds(1); //As of Arduino 0018, delayMicroseconds() no longer disables interrupts.
    portc_val = PORTC; //capture PORTC value
    cap1 = true; //Stop capturing
  }
  a1_pin_change_cnt++;
}

void loop() {
  Serial.println(a1_pin_change_cnt);
  delay(1000); //delay function does not disable interrupts

  if (cap1 && !printed) {
    Serial.print("Captured PORTC Value (Binary) after A1 Pin change= "); Serial.println(portc_val, BIN);
    printed = true;
  }
 
}

The output is same.

Initializing
PORTC Value (Binary) Before Pin Config= 0
PORTC Value (Binary) After Pin Config= 10
Init Done
0
0
0
0
0
0
0
0
0
Captured PORTC Value (Binary) after A1 Pin change= 10
19
19
19
19
19
39
39
39
39
39
59
59

Is PORTC right register to read in? Is it supposed to reflect External Pin changes?

Best Regards,
Kish

To read the value on pins, you read PINx, PORTx is what you write to to control pin state when the pins are set as outputs.

Hi DrAzzy,

Thanks so much. I changed my code from PORTC to PINC and it works now.

So relieved...:slight_smile: