ESP32 I2C OLED stop working when attach interrupt occur

Hi all,
I'm working with an ESP32 dev kit V1; I'm trying to implement a simple menu in my code, and I'm doing few test on the i2c OLED (SSD1306) and a rotary encoder. Everything seem to work correctly until I use the serial.print, but when I try to add the oled display, something strange happen: at the beginning the display print the initial menu correctly, but when I click the rotary button, the display stop working. I post the code hoping that the problem will be more clear:

#include <Wire.h>               // Only needed for Arduino 1.6.5 and earlier
#include "SSD1306Wire.h"        // legacy: #include "SSD1306.h"

SSD1306Wire display(0x3c, SDA, SCL);   

#define SW 4
#define DT 2
#define CLK 15

volatile int lastEncoded = 0;
volatile long encoderValue = 0;
long lastencoderValue = 0;
int lastMSB = 0;
int lastLSB = 0;

volatile bool stampa=true;
volatile long timing = 0;

uint8_t layer = 0;
uint8_t functionMenuSel;
uint8_t subMenuSel;
uint8_t valueSel;
volatile int8_t sumVal;

typedef struct subMenu{
  String title;
  double val;
};

typedef struct functionMenu{
  String title;
  subMenu variables[3];
  String back = "back";
};

functionMenu Slider;
functionMenu TimeLapse;
functionMenu StopMotion;
functionMenu Impostazioni;
functionMenu Back;

functionMenu *menuList[5] = { &Slider, &TimeLapse, &StopMotion, &Impostazioni, &Back};

void setup() {
  
  Slider.title = "Slider";
  Slider.variables[0].title = "velocità";
  Slider.variables[0].val = 100;
  Slider.variables[1].title = "acellerazione";
  Slider.variables[1].val = 2.5;
  
  TimeLapse.title = "TimeLapse";
  TimeLapse.variables[0].title = "passo";
  TimeLapse.variables[0].val = 23;
  TimeLapse.variables[1].title = "pausa";
  TimeLapse.variables[1].val = 4.2;

  StopMotion.title = "StopMotion";
  
  Impostazioni.title = "Impostazioni";
  
  // put your setup code here, to run once:
  pinMode (DT, INPUT_PULLUP);
  pinMode (CLK, INPUT_PULLUP);
  pinMode (SW, INPUT);
  
  display.init();
  display.flipScreenVertically();
  display.setFont(ArialMT_Plain_10);
//  display.setFont(Roboto_Light_12);

  attachInterrupt(DT, updateEncoder, CHANGE);
  attachInterrupt(CLK, updateEncoder, CHANGE);
  attachInterrupt(SW, menuSel, RISING);

  Serial.begin (115200);

  display.init();

//  display.flipScreenVertically();
  display.setFont(ArialMT_Plain_10);
//  display.setFont(Roboto_Light_12);
  
}

void loop() {
  
  if (stampa){

    OLED_print();

    Serial.println();
    if (layer == 0) Serial.print("*");
    Serial.println (menuList[functionMenuSel]->title);
    if (layer == 1) Serial.print("*");
    Serial.println ((String)"  "+menuList[functionMenuSel]->variables[subMenuSel].title);
    if (layer == 2) Serial.print("*");
    Serial.println ((String)"    "+menuList[functionMenuSel]->variables[subMenuSel].val);
    
    delay(80);
    stampa = false;
  }
  
}

void OLED_print(){
  
  display.clear();

  if (layer == 0){
    display.setTextAlignment(TEXT_ALIGN_LEFT);
    for (int i; i<4; i++){
      display.drawString(12, (i*12), menuList[i]->title ); // (x pos, y pos, string) --> text align set the distribution of the text starting from the x pos
    }
    display.drawString(0, (functionMenuSel*12), ">" );
  }

  if (layer == 1){
    display.setTextAlignment(TEXT_ALIGN_LEFT);
    for (int i; i<2; i++){
      display.drawString(12, (i*12), menuList[functionMenuSel]->variables[i].title ); // (x pos, y pos, string) --> text align set the distribution of the text starting from the x pos
    }
    display.drawString(0, (subMenuSel*12), ">");
  }
  display.display();
}

void updateValue () {
  
  switch (layer) {
    case 0:
      functionMenuSel += sumVal;
      if (functionMenuSel > 3) functionMenuSel = 0;
      break;
      
    case 1:
      subMenuSel += sumVal;
      if (subMenuSel > 2) subMenuSel = 0;
      break;

    case 2:
      menuList[functionMenuSel]->variables[subMenuSel].val += sumVal;
      break;
  }
    stampa=true;
    timing=millis();
}

void menuSel () {
  if (millis() - timing>200){
    if (layer < 2) layer++; 
    else layer--; 
    if (layer==2 && (functionMenuSel == 4 || subMenuSel == 2)) layer = 0; 
    stampa=true;
    timing = millis();
  }
}

void updateEncoder() {
  int MSB = digitalRead(DT); //MSB = most significant bit
  int LSB = digitalRead(CLK); //LSB = least significant bit

  int encoded = (MSB << 1) | LSB; //converting the 2 pin value to single number
  int sum  = (lastEncoded << 2) | encoded; //adding it to the previous encoded value

  //if (sum == 0b1101 || sum == 0b0100 || sum == 0b0010 || sum == 0b1011) encoderValue ++;
  //if (sum == 0b1110 || sum == 0b0111 || sum == 0b0001 || sum == 0b1000) encoderValue --;
  
  if (sum == 0b1000){
    if (millis() - timing>80) {
      encoderValue ++;
      sumVal = 1;
      updateValue();
      timing = millis();
    }
    //else encoderValue +=10;
  }
  if (sum == 0b0010) {
    if (millis() - timing>80) {
      encoderValue --;
      sumVal = -1;
      updateValue();
      timing = millis();
    }
    //else encoderValue -=10;
  }

  lastEncoded = encoded; //store this value for next time

}

In the "OLED_print" function, I've tried to remove the "if" statements, so that the same menu page should be print regardless of the "layer" value, just to verify, but again when i push the rotary button, the oled stops working.
Probably I'm doing some basic errors, but I've been on it for too long, and I can't see it.
Thanks in advance for your help!

Fulvio

What GPIO's are the SCL and SDA lines hooked to?

What device is using those pins?

Nothing with the issue description matches with the title of your posting.

A strange way to use interrupts.

Why are those pins setup as interrupts?

Hi Idahowalker, thanks for answering!

What GPIO's are the SCL and SDA lines hooked to?

On the default ESP32 GPIO, that are respectively D21 and D22.

What device is using those pins?

The rotary encoder does;
SW --> switch button
DT --> encoder line A
CLK --> encoder line B

Nothing with the issue description matches with the title of your posting.

Maybe this was a little confusing, my bad. The aims of this phrase was to explaining that the problem isn't related to the menu selection and printing, because on the serial monitor (that print the same things of the oled) everything is printed correctly.

Why are those pins setup as interrupts?

Those pins are used to encode the direction of the rotary knob.
In addition, the switch pin (SW - rotary button) is attached to the ISR "menuSel" to read when the button is pressed and change the "layer" value accordingly:

attachInterrupt(SW, menuSel, RISING);

[...]

void menuSel () {
  if (millis() - timing>200){
    if (layer < 2) layer++; 
    else layer--; 
    if (layer==2 && (functionMenuSel == 4 || subMenuSel == 2)) layer = 0; 
    stampa=true;
    timing = millis();
  }
}

In the beginning the oled displays does what it supposed to, but as soon as I click the rotary button, the display stops showing anything at all, while the program is still running correctly (checked by the serial monitor).

I apologies for the previous bad description, i hope that now my problem is more clear!
Thanks!

Solved, it was a breadboard problem; seems that there is a pin line broken and the old was going in short circuit when pushing the switch due to the connection.

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