Multiple calls to OLED cause NANO to reset

Hi,

I am working on alarm clock that will turn the light on. Setup is NANO + RTC 1307 + OLED 0,96".
To keep the code clean I have moved OLED, RTC and light control functions to classes. LED strips cause no problem, so I'll leave them out for time being.
I pass DateTime variable from instance of RTC-encapsulating class to instance of OLED-encapsulating class to display current date and time + information on alarm. All displays fine upon call of clockrun() routine. However, when I uncomment another routine responsible for displaying data related to setting up time and date - clocksetup() - NANO resets continously.
The code is work in progress, so it is not complete.
I tried overloading (unified DisplayData as name instead of specific names) but with no success.
If anyone has bumped into this problem or knows the solution I'll be grateful for hints on how to solve the issue.

main code:


#include "Arduino.h"

//LED strip related declarations
#include "LedLight.h"
const byte yellowPin = 11;
const byte whiteC1Pin = 10;
const byte whiteW1Pin = 9;
const byte whiteW2Pin = 6;
const byte whiteC2Pin = 5;
const byte redPin = 3;
LedLight ledLight(redPin, yellowPin, whiteC1Pin, whiteC2Pin, whiteW1Pin, whiteW2Pin);
//---

//OLED related declarations
#include "OledDisplay.h"
OledDisplay oledDisplay; // declaration of OledDisplay instance
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
//---

//clock section declatations
#include "ZegarRTC.h"
const byte modePin = 12;
const byte addPin = 8;
const byte delPin = 7;
const byte okPin = 4;

ZegarRTC zegarRTC;
DateTime dt;
byte wuHour = 24;
byte wuMins = 0;
bool isAlarmActive = true;

unsigned long milisAtLastUpdate = 0;
unsigned long sec2disp = 0;
//---

enum workMode 
{
  CLOCKRUN=1, CLOCKSETUP=2, ALARMSETUP=3, LAMP=4, SUNRISE=5, SUNSET=6
};

workMode currWorkMode;

void setup() 
{
    Serial.begin(9600);
    //control pins
    pinMode(modePin, INPUT_PULLUP);
    pinMode(addPin, INPUT_PULLUP);
    pinMode(delPin, INPUT_PULLUP);
    pinMode(okPin, INPUT_PULLUP);
    //led output pins
    pinMode(yellowPin, OUTPUT);
    pinMode(redPin, OUTPUT);
    pinMode(whiteC1Pin, OUTPUT);
    pinMode(whiteC2Pin, OUTPUT);
    pinMode(whiteW1Pin, OUTPUT);
    pinMode(whiteW2Pin, OUTPUT);
  
    oledDisplay.begin(display);
    oledDisplay.DisplayText("SUN CLOCK", 2, 10, 25, true); //uncommenting second call to OledDisplay methods (any) causes reset and displaying SUN CLOCK
    delay(2000);

    if (!zegarRTC.begin()) currWorkMode = CLOCKSETUP;
    else currWorkMode = CLOCKRUN;

}

void loop() 
{
    dt = zegarRTC.GetTimeDateToDisplay();
    
    if (digitalRead(modePin)==LOW){
      currWorkMode = currWorkMode + 1;
      if (currWorkMode > 6)
        currWorkMode = 1;
      delay(200);
    }
    
    //Serial.print("workMode: ");  // using Serial.print(ln) causes hickups
    //Serial.println(currWorkMode);

    switch (currWorkMode) {
        case CLOCKRUN:
          clockrun();
          break;
        case CLOCKSETUP:
          //clocksetup(); // uncommenting this call causes NANO to reset

        break;
        case ALARMSETUP:
          clockrun();
        break;
        case LAMP:
          clockrun();
        break;
        case SUNRISE:
          clockrun();
          sunrise();
        break;
        case SUNSET:
          clockrun(); 
        break;

    }
}

void clockrun()
{
    oledDisplay.ClearDisplay();
    oledDisplay.DisplayData(dt, currWorkMode+20, wuMins); //second param. only to display work mode as Serial.println hickups NANO completely
}

void clocksetup()
{
    oledDisplay.ClearDisplay();
    oledDisplay.DisplayData(dt, "CLOCK SETUP");
}

void sunrise()
{
      if (millis()-milisAtLastUpdate > 100)
      {
          ledLight.SimulateSunRise(sec2disp);
          milisAtLastUpdate = millis();
          sec2disp++;
      }
}

OledDisplay.h

#include "RTClib.h"
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

class OledDisplay
{
    public:
        int begin(Adafruit_SSD1306 display);
        void DisplayText(String txt, byte txtSize, byte posX, byte posY, bool clearDisplay);
        void DisplayData(DateTime dt, byte wuHour, byte wuMins);
        void DisplayData(DateTime dt, String info);
        void ClearDisplay();
    private:
      Adafruit_SSD1306 disp;
      void DisplayWakeUpTime(byte hour, byte mins);     
};

OledDisplay.cpp

//#include "Arduino.h"
#include "OledDisplay.h"
#define SCREEN_ADDRESS 0x3C
#define OLED_RESET     -1 // Reset pin # (or -1 if sharing Arduino reset pin)
Adafruit_SSD1306 disp;//(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);


OledDisplay::begin(Adafruit_SSD1306 display)
{//oled display init

    disp = display;

    if(!disp.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) 
    {
        Serial.println(F("SSD1306 allocation failed"));
    for(;;); // Don't proceed, loop forever
    }
    disp.clearDisplay();
}

void OledDisplay::ClearDisplay()
{
    disp.clearDisplay();
}

void OledDisplay::DisplayText(String txt, byte txtSize, byte posX, byte posY, bool clearDisplay)
{
    if (clearDisplay) disp.clearDisplay();

    disp.setTextSize(txtSize);
    disp.setTextColor(WHITE);
    disp.setCursor(posX, posY);
    disp.println((txt));

    disp.display();
}

void OledDisplay::DisplayData(DateTime dtClock, byte wuHour, byte wuMins)
{
    if (wuHour < 255) DisplayWakeUpTime (wuHour, wuMins);

    byte hour = dtClock.hour();
    byte mins = dtClock.minute();
    byte sec = dtClock.second();
    int year = dtClock.year();
    byte month = dtClock.month();
    byte day = dtClock.day();
    
    //hh:mm section
    disp.setTextSize(3);
    disp.setTextColor(WHITE);

    if (hour < 10) disp.setCursor(23, 30);
    else disp.setCursor(5, 30);
    disp.print(hour);

    if (mins < 10) 
    {
      disp.print(":0");
      disp.print(mins);
    }
    else
    {
      disp.print(":");
      disp.print(mins);
    } 

    //ss section
    disp.setTextSize(2);
    disp.setCursor(100, 37);

    if (wuMins < 255)
    {
      if (sec < 10)
      {
        disp.print("0");
        disp.println(sec);
      } 
      else disp.println(sec);
    }
    
    //date section
    disp.setTextSize(1);
    disp.setCursor(35, 57);
    disp.print(year);
    disp.print("-");
    disp.print(month);
    disp.print("-");
    if (day<10)
    {
      disp.print("0");
      disp.print(day);
    } else disp.print(day);
    
    disp.display();
}

void OledDisplay::DisplayWakeUpTime(byte hour, byte mins)
{
    //hh:mm section
    disp.setTextSize(1);
    disp.setTextColor(WHITE);

    if (hour < 10) disp.setCursor(13, 5);
    else disp.setCursor(7, 5);
    disp.print("Wake up at ");
    disp.print(hour);

    if (mins < 10) disp.print(":0");
    else disp.print(":");
    disp.println(mins);
  
    if (hour-1 < 10) disp.setCursor(13, 15);
    else disp.setCursor(7, 15);
    disp.print("Sunrise at ");
    disp.print(hour-1);

    if (mins < 10) disp.print(":0");
    else disp.print(":");
    disp.println(mins);
}

void OledDisplay::DisplayData(DateTime dt, String info)
{
    DisplayText(info, 2, 5, 25, true);
    DisplayData(dt, 255, 255);

}

Most likely your code just doesn't have enough memory.
The Adafruit_SSD1306.h library allocates 1k for the display buffer, while the Nano only has 2 k.
And you also wrote a bunch of your own classes.

Test your code on the Mega - if this fix the issue, you will know the path.

As a general advice - do not use Strings on boards with limited memory.

3 Likes

Can you post the code for the LedLight and ZegarRTC classes, so that the code can be compiled?
I agree with @0707, highly likely a memory issue, particularly since you are using String in some of the functions for the OLED display.

@david_2018 , the remaining code is posted below

LedLight.h

/*

  LedLight.h - Library for controlling lights in LedLightAlarmClock.
  Created by Krystian Sroka, Nov. 2023.
*/
#include "Arduino.h"
class LedLight
{
    public:
        LedLight (byte redPin, byte yellowPin, byte whiteC1Pin, byte whiteC2Pin, byte whiteW1Pin, byte whiteW2Pin);
        void SimulateSunRise(int timeElapsed);
        void SimulateFire();
        void MaxAll();
        void SetBrightnessCoeff(float brightnessCoeff);

        enum LightMode { SUNRISE=1, SUNSET=2, FIRE=3, MAXALL=4, MAXRY=5, MAXWHITE=6 };
        

    private:
      int redTime2max;
      int yellowTime2Max;
      int whiteWarmTime2Max;
      int whiteColdTime2Max;
      byte wC1Pin;
      byte wC2Pin;
      byte wW1Pin;
      byte wW2Pin;
      byte yPin;
      byte rPin;
      float brightness;

};

LedLight.cpp

#include "LedLight.h"

//LedLight::LightMode
//    { 
//      SUNRISE, SUNSET, FIRE, MAXALL, MAXRY, MAXWHITE 
//    }

//constructor
LedLight::LedLight (byte redPin, byte yellowPin, byte whiteC1Pin, byte whiteC2Pin, byte whiteW1Pin, byte whiteW2Pin)
    {
      rPin = redPin;
      yPin = yellowPin;
      wC1Pin = whiteC1Pin;
      wC2Pin = whiteC2Pin;
      wW1Pin = whiteW1Pin;
      wW2Pin = whiteW2Pin;
      brightness = 1;
    }

int redTime2Max = 600;
int yellowTime2Max = 1200;
int whiteWarmTime2Max = 1800;
int whiteColdTime2Max = 2400;

void LedLight::SimulateSunRise(int timeElapsed)
    {
      int wc = map (timeElapsed, 1500, 2400, 0, 255);
      int ww = map (timeElapsed, 1200, 1800, 0, 255);
      int yl = map (timeElapsed, 300, 1500, 0, 255);
      int rd = map (timeElapsed, 0, 600, 0, 255);

      if (rd < 0) rd = 0;
      if (yl < 0) yl = 0;
      if (ww < 0) ww = 0;
      if (wc < 0) wc = 0;
      if (rd > 255) rd = 255;
      if (yl > 255) yl = 255;
      if (ww > 255) ww = 255;
      if (wc > 255) wc = 255;

      analogWrite(wC1Pin, wc);
      analogWrite(wC2Pin, wc);
      analogWrite(wW1Pin, ww);
      analogWrite(wW2Pin, ww);
      analogWrite(yPin, yl);
      analogWrite(rPin, rd);
/*
      Serial.print (timeElapsed);
      Serial.print (": ");
      Serial.print (rd);
      Serial.print (", ");
      Serial.print (yl);
      Serial.print (", ");
      Serial.print (ww);
      Serial.print (", ");
      Serial.println (wc);*/
    }

void LedLight::MaxAll()
    {
      analogWrite(wC1Pin, 255);
      analogWrite(wC2Pin, 255);
      analogWrite(wW1Pin, 255);
      analogWrite(wW2Pin, 255);
      analogWrite(yPin, 255);
      analogWrite(rPin, 255);
    }

void LedLight::SimulateFire()
    {
      analogWrite(wC1Pin, 0);//(int) ((random(128)+35)*brightness));
      analogWrite(wC2Pin, 0);//(int) ((random(128)+35)*brightness));
      analogWrite(wW1Pin, (int) ((random(64)+35)*brightness));
      analogWrite(wW2Pin, (int) ((random(64)+35)*brightness));
      delay(random(32));
      analogWrite(yPin, (int) ((random(200)+55)*brightness));
      delay(random(128));
      analogWrite(rPin, (int) ((random(200)+55)*brightness));
      delay(random(128));

    }

void LedLight::SetBrightnessCoeff(float brightnessCoeff)
    {
      brightness = brightnessCoeff;
    }

ZegarRTC.h

#include "RTClib.h"

class ZegarRTC
{
    public:
        bool begin();
        //bool IsDateTimeValid();
        //bool IsAlarmSet();
        DateTime GetTimeDateToDisplay();
    private:
        RTC_DS1307 rtc;
        
        //RtcDS1307<TwoWire> rtc(Wire);
        DateTime dtCurr;
        DateTime dtAlarm;
        struct AlarmSettings{byte hr; byte mn;};
};

ZegarRTC.cpp

#include "ZegarRTC.h"

RTC_DS1307 rtc;
DateTime dtCurr;
DateTime dtAlarm;
struct AlarmSettings{byte hh; byte mm;};

bool ZegarRTC::begin()
{
    rtc.begin();
//    #if defined(WIRE_HAS_TIMEOUT)
//    Wire.setWireTimeout(3000 /* us */, true /* reset_on_timeout */);
//    #endif

    if (!rtc.isrunning()) return false;
    else return true;
}

DateTime ZegarRTC::GetTimeDateToDisplay()
{
    dtCurr = rtc.now();
    /*Serial.print(dtCurr.hour(), DEC);
    Serial.print(':');
    Serial.print(dtCurr.minute(), DEC);
    Serial.print(':');
    Serial.print(dtCurr.second(), DEC);
    Serial.println();*/
    return dtCurr;
}

@b707 , thanks for the hint. I'll rewrite the relevant parts

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