Rotary encoder and Raspi pico: interrupt handlers never trigger

I have a rotary encoder with push button (just the component, not on a breakout board) hooked up to a raspberry pico, with the rotary encoder pins A and B on pico GPIO 2 and 1 (pins 4 and 2), pin C to ground, and the switch pins connected to ground and pico GPIO 5 (pin 7), basically following every single rotary encoder tutorial on the planet, and I'm trying to read the with the following code:

#define ROTA       2    // GPIO2, pin 4
#define ROTB       1    // GPIO1, pin 2
#define SWITCH     5    // GPIO7, pin 7

int call_times = 0;
boolean boop = false;

void setup() {
  pinMode(ROTA, INPUT_PULLUP);
  pinMode(ROTB, INPUT_PULLUP);
  pinMode(SWITCH, INPUT_PULLUP);
  Serial.begin(115200);
  attachInterrupt(digitalPinToInterrupt(ROTA), handleRotary, RISING);
  attachInterrupt(digitalPinToInterrupt(ROTB), handleRotary, RISING);
  interrupts();
}

void loop() {
  int val = digitalRead(SWITCH);
  if (val == 0) {
    if (boop == false) {
      boop = true;
      Serial.println("boop");
    }
  } else {
    boop = false;
  }

  Serial.print(call_times);
  delay(100);
}

void handleRotary() {
  call_times++;
}

And this does nothing in terms of the call_times value. The switch works fine, plenty of boops to be had when pressing it, but the interrupt handler never gets called when using the rotary dial, the value of call_times stays zero. I removed the delay call just to make sure that wasn't interfering, but that makes no difference.

I figured I'd test the voltages to see what's going on, which is where things get head-scratchy: if I just set up ROTA and ROTB with pullup inputs with the attachInterrupt lines and interrupts() commented off, the voltages on both pins are 3.2V, as expected from a pulled up input. However, with the interrupt setup code in place and uncommented, the voltage on both pins is only 0.2V (i.e. so low that it'll always read a digital zero).

What am I forgetting to do? Or doing flat out wrong?

I had a similar issue. This is what I'm using now: Control-Surface/AHEncoder.cpp at 7b4cc67382731ad3fb4c174c6acb0ccb1c0ff081 · tttapa/Control-Surface · GitHub

1 Like

Glad to see it's not just me - I'm not too familiar with c++ programming, is there an easy equivalent for using that code in combination with the handleRotary void method as callback? I've modified it to this, but that might not be the right way to do it:

void encoder_init() {
  // enable pin change interrupts
  int P1 = digitalPinToInterrupt(encoderPin1);
  int P2 = digitalPinToInterrupt(encoderPin2);

  gpio_irq_callback_t readEncoderFunction = readEncoder;

  gpio_set_irq_enabled_with_callback(
    P1,
    GPIO_IRQ_EDGE_FALL | GPIO_IRQ_EDGE_RISE,
    true,
    readEncoderFunction
  );

  gpio_set_irq_enabled_with_callback(
    P2,
    GPIO_IRQ_EDGE_FALL | GPIO_IRQ_EDGE_RISE,
    true,
    readEncoderFunction
  );

  interrupts();
}

With the readEncoder function update to take the arguments required to be a gpio_irq_callback_t:

void readEncoder(unsigned int a, long unsigned int b) {
  call_times ++;
}

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