简体   繁体   中英

ESP32 can't display text on OLED from Timer ISR

Problem

I have an ESP32 T-call SIM800L with I2C OLED connected using the Adafruit_SSD1306 library. It works just fine when calling the displayText() function in either setup or loop, although I have a timer interrupt set at 1Hz where I attempt to display a message on the OLED but it just doesn't work. The ISR itself definitely works, I have a count variable which increments on each interrupt and I print that out to the serial monitor (I know you shouldn't really be doing serial stuff in ISR's but it still works) so the ISR is definitely interrupting correctly. The weird thing is that I swear I had it working before (displaying in the ISR) so I am convinced it is possible. I've tried removing everything else in the ISR and just including the display functions but with no success.

Any help is greatly appreciated

Code:

#include <Adafruit_SSD1306.h> //OLED
#include <Adafruit_GFX.h>

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 32 // OLED display height, in pixels

// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
#define OLED_RESET     -1 // Reset pin # (or -1 if sharing Arduino reset pin)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

volatile int count = 0;

void setupDisplay () 
{

  if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) // Address 0x3C for 128x32
  
  { 
    Serial.println(F("SSD1306 allocation failed"));
    for(;;); // Don't proceed, loop forever

  }
}

void displayText(int count) 
{

  display.clearDisplay();
  display.setTextSize(1); // Draw 2X-scale text
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(0, 0);
  display.print(count);
  display.display();      // Show initial text

}

///* create a hardware timer */
hw_timer_t * timer = NULL;

void IRAM_ATTR onTimer()
{
count++;
Serial.println(count);
//displayText(count);


  display.clearDisplay();
  display.setTextSize(1); // Draw 2X-scale text
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(0, 0);
  display.print("Display from ISR");
  display.display();      // Show initial text

}

void setup() 
{
  Serial.begin(115200); 

  setupDisplay();
  displayText(count);

  timer = timerBegin(0, 80, true);
  timerAttachInterrupt(timer, &onTimer, true);
  timerAlarmWrite(timer, 1000000, true);
  timerAlarmEnable(timer);
  Serial.println("start timer");
}

void loop()
{

}

Serial Monitor Prinout

start timer
1
2
3
4
5
6
7
8
9
10

You're doing way too much in the interrupt handler.

Interrupt handlers shouldn't call high level functions unless you know that they're reentrant - that is they lock out interrupts while manipulating hardware or data structures in order to keep things consistent - and that they're available for execution in RAM (have been copied in from flash storage, which is what the IRAM_ATTR modifier guarantees).

Interrupt handlers should also run for as little time as possible, as they prevent the ESP32 from servicing other interrupts.

Your program may at times work if you don't do these things. It may also randomly stop working or start crashing or exhibiting what we like to call "undefined behavior" when you make small changes to it.

Instead of calling Serial.println() or any of your display methods, set a volatile boolean flag to indicate that there's work to be done, and do the work in loop() .

Try this instead:

volatile boolean work_to_be_done = false;

void IRAM_ATTR onTimer()
{
count++;
work_to_be_done = true;
}

void loop()
{
  if(work_to_be_done)
  {
    Serial.println(count);
    //displayText(count);


    display.clearDisplay();
    display.setTextSize(1); // Draw 2X-scale text
    display.setTextColor(SSD1306_WHITE);
    display.setCursor(0, 0);
    display.print("Display from ISR");
    display.display();      // Show initial text

    work_to_be_done = false;
  }
}

You could also write loop() to detect that count had changed, but I prefer the clarity of maintaining a flag that indicates there's something to be done.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM