Programm freezing after some time

Good evening,

im new to arduino. Here i'm trying to make a oled menu controlled with 3 buttons, also i'm using a Arduino UNO.

The code works so far, but after 5 minutes or so, it freezes.
I tried a couple of methods to stop it from freezing, without success.

Does anybody know what could be wrong with my code?

Thank you!

#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <AccelStepper.h>
#include <avr/pgmspace.h>

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

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

Adafruit_SSD1306 SSD1306 = Adafruit_SSD1306(); 

int menu = 1;

const int dirPin PROGMEM = 2;
const int stepPin PROGMEM = 3;

const int DownButton PROGMEM = 7;
const int UpButton PROGMEM = 6;
const int OkButton PROGMEM = 5;

int motorinterface = 1;
int stepMaxSpeed = 5000;
int stepAccel = 1000;

AccelStepper stepper = AccelStepper(motorinterface,stepPin,dirPin);

int GEWICHT = 0;

int OK;
int CursorPos = 1;
int PrevCursorPos;
String Cur=">";


//----------------------------------------Setup Routine--------------------------------
void setup () 
{
    Serial.begin(9600);
    Wire.begin();
    display.begin(SSD1306_SWITCHCAPVCC, 0x3C); // Address 0x3D for 128x64


    
    stepper.setMaxSpeed(stepMaxSpeed);
    stepper.setAcceleration(stepAccel);
    pinMode(UpButton,INPUT_PULLUP);
    pinMode(DownButton,INPUT_PULLUP);
    pinMode(OkButton,INPUT_PULLUP);
    pinMode(stepPin,OUTPUT);
    pinMode(dirPin,OUTPUT);

    display.clearDisplay();

}

//----------------------------------------MainMenu--------------------------------

void MainMenu()
{
  
  menu = 1;
  if(CursorPos > 3)
  {
    CursorPos = 1;
  }
  else if (CursorPos < 1)
  {
    CursorPos = 3;
  }
  if(OK == 1 && CursorPos == 1) // menuauswahl
  {
    menu = 2;
    OK = 0;
    PrevCursorPos = CursorPos;
  }
  display.clearDisplay();
  display.setTextColor(WHITE);
  display.setTextSize(1);

  display.setCursor(0,0);
  display.print(F("JOKER Durchstosstest"));
  display.setCursor(10,20); display.print(F("mm/min:  ")); display.print(F(stepMaxSpeed));
  if (CursorPos == 1)
  {
    display.setCursor(0,20); display.print(F(Cur));
  }
  display.setCursor(100,20);display.print(CursorPos);
    if (CursorPos == 2)
  {
    display.setCursor(0,30); display.print(F(Cur));
  }
  display.setCursor(10,30); display.print(F("Max kg:  ")); display.print(F(GEWICHT)); display.print(F("kg"));
    if (CursorPos == 3)
  {
    display.setCursor(30,50); display.print(F(Cur));
  }
   display.setCursor(40,50); display.print(F("Start!"));
}

//--------------------------------------Untermenu-geschwindigkeit------------------------------------
void  mm_minuten()
{
    
    
  if(!digitalRead(DownButton))
  {
    Serial.println(F("Down pressed!"));
    stepMaxSpeed++;
  }
  
  if(!digitalRead(UpButton))
  {
    Serial.println(F("Up pressed!"));
    stepMaxSpeed--;
  }
 if(!digitalRead(OkButton))
  {
    menu = 1;
    OK = 0;
    CursorPos = PrevCursorPos;
    while(!digitalRead(OkButton));
  }
  display.clearDisplay();
  display.setCursor(0,0);display.print(F("Milimeter/Minute"));

  
  display.setCursor(10,30); display.print(F("mm/min:"));
  display.setCursor(64,30); display.setTextSize(2);
  display.print(F(stepMaxSpeed));
  display.setTextSize(1);

  
}


//-----------------------------------------loop Function-----------------------------------------
void loop()
{
  display.clearDisplay();

   if (stepMaxSpeed > 10000 || stepMaxSpeed < 1000)
    {
      stepMaxSpeed = 5000;
    }
  if (menu == 1)
  {
    MainMenu();
    Buttons();
  }
  else if (menu == 2)
  {
    mm_minuten();
    
    
  }
  display.display();
}

//-------------------------------------------What does the Button do?----------------------------
void Buttons()
{
  downbutton();
  upbutton();
  okbutton();
}
//--------------------------------------------------

void downbutton()
{
  if(!digitalRead(DownButton))
    {
      //Serial.println(F("Down pressed!"));
      CursorPos++;     
      while(!digitalRead(DownButton));
    }
}
//-------------------------------------------------
void upbutton()
{
  if(!digitalRead(UpButton))
    {
      //Serial.println(F("Down pressed!"));
      CursorPos--;     
      while(!digitalRead(UpButton));
    }
}
//-------------------------------------------------
void okbutton()
{ 
  if(!digitalRead(OkButton))
    {
      //Serial.println(F("Down pressed!"));
      OK = 1;  
      PrevCursorPos = CursorPos;   
      while(!digitalRead(OkButton));
    }
}
//---------------------Refresh Display--------------------------
void refresh()
{
  display.display();
  delay(00);
  display.clearDisplay();
}

You could be running out of memory, so check the loader report. The graphics libraries take up a lot of space.

This is wrong, but it is hard to guess what might happen. The F() macro is for character strings, to be stored in program memory. I'm surprised it even compiles.

  display.print(F(stepMaxSpeed));

I don't think this works either:

String Cur=">";
...
   display.setCursor(0,30); display.print(F(Cur));

If a delay is required here, "00" does nothing useful.

void refresh()
{
  display.display();
  delay(00);
  display.clearDisplay();
}

In the IDE preferences page, turn on compiler warnings and verbose output for compilation and loading, and inspect the messages.

I modified the code a bit, but it still freezes...

Here's the loader report:

d:\Users\Jp\Documents\Arduino\libraries\Adafruit_GFX_Library\Adafruit_GFX.cpp: In member function 'virtual void Adafruit_GFX::invertDisplay(bool)':
d:\Users\Jp\Documents\Arduino\libraries\Adafruit_GFX_Library\Adafruit_GFX.cpp:1532:39: warning: unused parameter 'i' [-Wunused-parameter]
 void Adafruit_GFX::invertDisplay(bool i) {
                                       ^
Sketch uses 20890 bytes (64%) of program storage space. Maximum is 32256 bytes.
Global variables use 821 bytes (40%) of dynamic memory, leaving 1227 bytes for local variables. Maximum is 2048 bytes.
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <AccelStepper.h>
#include <avr/pgmspace.h>

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

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

Adafruit_SSD1306 SSD1306 = Adafruit_SSD1306(); 

int menu = 1;

const int dirPin PROGMEM = 2;
const int stepPin PROGMEM = 3;

const int DownButton PROGMEM = 7;
const int UpButton PROGMEM = 6;
const int OkButton PROGMEM = 5;

int motorinterface = 1;
int stepMaxSpeed = 5000;
int stepAccel = 1000;

AccelStepper stepper = AccelStepper(motorinterface,stepPin,dirPin);

int GEWICHT = 0;

int OK;
int CursorPos = 1;
int PrevCursorPos;
const String Cur=">";


//----------------------------------------Setup Routine--------------------------------
void setup () 
{
    Serial.begin(9600);
    //Wire.begin();
    display.begin(SSD1306_SWITCHCAPVCC, 0x3C); // Address 0x3D for 128x64


    
    stepper.setMaxSpeed(stepMaxSpeed);
    stepper.setAcceleration(stepAccel);
    pinMode(UpButton,INPUT_PULLUP);
    pinMode(DownButton,INPUT_PULLUP);
    pinMode(OkButton,INPUT_PULLUP);
    pinMode(stepPin,OUTPUT);
    pinMode(dirPin,OUTPUT);

    display.clearDisplay();
    //display.drawBitmap(0,0, bitmap_joker,128,64,WHITE);
    //display.display();
    delay(2000);

}

//----------------------------------------MainMenu--------------------------------

void MainMenu()
{
  
  menu = 1;
  if(CursorPos > 3)
  {
    CursorPos = 1;
  }
  else if (CursorPos < 1)
  {
    CursorPos = 3;
  }
  if(OK == 1 && CursorPos == 1) // menuauswahl
  {
    menu = 2;
    OK = 0;
    PrevCursorPos = CursorPos;
  }
  else if (OK == 1 && CursorPos == 2)
  {
    menu = 3;
    OK = 0;
  }
  display.clearDisplay();
  display.setTextColor(WHITE);
  display.setTextSize(1);

  display.setCursor(0,0);
  display.print("JOKER Durchstosstest");
  display.setCursor(10,20); display.print("mm/min:  "); display.print(stepMaxSpeed);
  if (CursorPos == 1)
  {
    display.setCursor(0,20); display.print(Cur);
  }
  display.setCursor(100,20);display.print(CursorPos);
    if (CursorPos == 2)
  {
    display.setCursor(0,30); display.print(Cur);
  }
  display.setCursor(10,30); display.print("Max kg:  "); display.print(GEWICHT); display.print("kg");
    if (CursorPos == 3)
  {
    display.setCursor(30,50); display.print(Cur);
  }
   display.setCursor(40,50); display.print("Start!");
}

//--------------------------------------Untermenu-geschwindigkeit------------------------------------
void  mm_minuten()
{
    
    
  if(!digitalRead(DownButton))
  {
    Serial.println("Down pressed!");
    stepMaxSpeed++;
  }
  
  if(!digitalRead(UpButton))
  {
    Serial.println("Up pressed!");
    stepMaxSpeed--;
  }
 if(!digitalRead(OkButton))
  {
    menu = 1;
    OK = 0;
    CursorPos = PrevCursorPos;
    while(!digitalRead(OkButton));
  }
  display.clearDisplay();
  display.setCursor(0,0);display.print("Milimeter/Minute");

  
  display.setCursor(10,30); display.print("mm/min:");
  display.setCursor(64,30); display.setTextSize(2);
  display.print(stepMaxSpeed);
  display.setTextSize(1);

  
}
//-----------------------------------------Max. Kraft Menu-----------------------------
void max_kraft()
{
  if(!digitalRead(DownButton))
  {
    Serial.println("Down pressed!");
    stepMaxSpeed++;
  }
  
  if(!digitalRead(UpButton))
  {
    Serial.println("Up pressed!");
    stepMaxSpeed--;
  }
 if(!digitalRead(OkButton))
  {
    menu = 1;
    OK = 0;
    CursorPos = PrevCursorPos;
    while(!digitalRead(OkButton));
  }
  display.clearDisplay();
  display.setCursor(0,0);display.print("Druckkraft");

  
  display.setCursor(60,50); display.print("Kilogramm");
  display.setCursor(50,20); display.setTextSize(2);
  display.print(GEWICHT);
  display.setTextSize(1);

}

//-----------------------------------------loop Function-----------------------------------------
void loop()
{
  

   if (stepMaxSpeed > 10000 || stepMaxSpeed < 1000)
    {
      stepMaxSpeed = 5000;
    }
  if (menu == 1)
  {
    MainMenu();
    Buttons();
  }
  else if (menu == 2)
  {
    mm_minuten();
  }
  else if (menu ==3)
  {
    max_kraft();
  }

  refresh();
  
}

//-------------------------------------------What does the Button do?----------------------------
void Buttons()
{
  downbutton();
  upbutton();
  okbutton();
}
//--------------------------------------------------

void downbutton()
{
  if(!digitalRead(DownButton))
    {      
      CursorPos++;     
      while(!digitalRead(DownButton));
    }
}
//-------------------------------------------------
void upbutton()
{
  if(!digitalRead(UpButton))
    {      
      CursorPos--;     
      while(!digitalRead(UpButton));
    }
}
//-------------------------------------------------
void okbutton()
{ 
  if(!digitalRead(OkButton))
    {
      OK = 1;  
      PrevCursorPos = CursorPos;   
      while(!digitalRead(OkButton));
    }
}
//---------------------Refresh Display--------------------------
void refresh()
{
  display.display();
  delay(10);
  display.clearDisplay();
}

I don't see anything obviously wrong. What is the last output from the program before it freezes?

Put Serial.println() statements in various places so you can see where code is being executed, or not.

If you actually have a motor/driver/motor power supply connected, consider power supply noise problems. If not, remove the motor code and all other extraneous code, in order to isolate the problem.

I can't answer you question, but I can say that I have had the same freezing problem on many occassions, using the same Oled, library, and I2C as yours.

I have a number of projects that work fine with the Oled and I2C set up. I also have a number of projects that annoyingly freeze after a time. I am tempted to think that it is the I2C layout that is the cause, but I have no hard proof.
It's either the library or the I2C connection. I have spent a considerable time testing things, but cannot determine the exact cause of the freeze. In all the testing, the library and I2C were the common factors. The freezing occurs using the full Adafruit library, and also the cut down text version of the library.Again, that leads me to suspect the I2C layout.

I now use SPI (7 wire) Oleds. I have had no freezing with these whatsoever.
I fit the SPI Oleds into the problematic I2C projects, and the problem goes away. Changing over to SPI requires a library change in my programs. It also requires a rewrite of the majority of my Oled display functions because the fonts are different in the I2C and SPI libraries. The rest of the program structures remain the same.

Steve

Bill (bperrybap) has reported a nasty bug in the i2C library - clearly the one that is "biting" you.

I anticipate his explanation. :grin:

Thank you for your answers.

I did already try the serial.println.
It often freezes after I pressed some buttons, but It also freezes when i let the arduino boot up and wait.

I think I try the 7wire spi oled.

Bill (bperrybap) has reported a nasty bug in the i2C library

Link please. Not that I'm surprised.

Paul__B:
Bill (bperrybap) has reported a nasty bug in the i2C library - clearly the one that is "biting" you.

I anticipate his explanation. :grin:

Hi Paul__B

Could you point me to any discussion, or any further information, on the bug that bperrybap discovered?
I have a big pile of i2c Oleds going to waste!

Thanks

Steve

edit: Sorry, just noticed that jremmington had already asked.

I could be wrong.

I was expecting Bill to chime in - perhaps send him a PM.

Paul__B:
Bill (bperrybap) has reported a nasty bug in the i2C library - clearly the one that is "biting" you.

I anticipate his explanation. :grin:

I wouldn't take the credit for the reporting of these types of issues.

I've seen multiple i2c type issues over the years on multiple Arduino platforms that can cause things to misbehave, lookup the processor, or cause a display to freeze.
The issues are different but can look similar or the same if just looking at the display and not digging a bit deeper.
i.e. in some cases the processor may be locked up in others the display is corrupted or in others the display stops working.

If on a platform like the esp8266, then there could be a watchdog happening from code running to long before returning back from loop()
using delay(0) is an easy and portable way to release the processor to the background thread on those platforms like the esp8266 that may need it. It is essentially the same as calling yield() without having to do any conditional checks to see if yield() is supported.

Depending on the platform, I have seen i2c issues related to

  • timing between i2c requests, (pic32, will cause a processor lockup)
  • sending single byte i2c transfers (I can't remember the platform (not the AVR), but it causes an immediate lockup of processor)
  • corruption of i2c signals (issue for many platforms, can corrupt slaves, lockup slaves, or lockup the main processor)
  • SSD1306 timing issue - I seem to have a vague memory of some kind of issue that could be worked around for that display.
    I believe Oliver has mentioned this for his u8glib library. - but my memory is vague on this so I may be misremembering something.

The key to trying to track down the issue is knowing what is really happening.
Is the processor locking up (I assume this is running on is an AVR) or is the display no longer responding.

@Paul__B, If you are referring to the lockup issue in the AVR Wire library,
while I noticed the AVR Wire code that can cause this condition when looking over the Wire code many years ago and have experienced this issue myself for many years, I wouldn't credit myself with the reporting of it as a bug.
This lockup issue was reported many years ago, and there has been quite the fight & drama over trying to fix

The biggest issue is that there is no way to truly fix this issue in s/w since it a h/w issue yet many of biggest and most vocal complainers simply do not understand the complications around this issue and believe that it can be fully resolved in software.
It can't.
When there is signal corruption, bad things can happen, the processor can send data to the wrong slave, it can send the wrong data to the correct slave, or on some platforms can lockup up the processor. What happens depends on where the signal corruption happens during a transfer.

This AVR wire library issue of i2c signal corruption could be what is causing the "freeze" in this situation.

I recently ran into this lockup issue with another/different i2c LCD device.
In that case it turned out to be a h/w issue on the i2c LCD device (A hd44780 type display with RGB backlight).
The LCD module can create noise on the i2c signals.

The issue is that if there is electrical signal corruption of the i2c signals, it can cause the Wire library to think that there is another master on the bus. If that happens, then the Wire library will back off the bus and wait forever for that other non existent master to complete a transaction. There is no timeout to terminate this wait. (at least not until recently).

@lejonny, from the posts so far, it wasn't clear to me if the AVR processor is locking up / not responding, or if the display is no longer responding and the AVR is still running.

Can you help clarify this?
This will help narrow down where else to start looking.

--- bill