Setup continually Loops - If Program or Dynamic Memory use over 50%

I have a Sketch that has the Setup() code continually looping. HW is UNO R3.
In Setup() there is some code then three possible calls to code to check if a particular button is pressed during Arduino powerup/reset.
They are:
CheckSetRTC();
CheckSetSlotButton();
CheckClearSlotButton();

Now here is the issue.
If I comment out these calls to CheckSetSlotButton() and CheckClearSlotButton() and compile the code I assume that the compiler realises that those two are not called in the program and creates a shorter set of instructions to load into the Arduino. The actual functions are still in the Sketch code.

If I Compile only with CheckSetRTC(); uncommented; I get:
Sketch uses 17642 bytes (54%) of program storage space
Global variables use 816 bytes (39%) of dynamic memory
The program loads and runs into Loop() OK

If I Compile with CheckSetRTC() and CheckSetSlotButton(); uncommented; I get:
Sketch uses 19270 bytes (59%) of program storage space
Global variables use 973 bytes (47%) of dynamic memory
The program loads and displays DJS Starting in Setup() and does not appear to go into Loop()

If I Compile with CheckSetRTC() and CheckSetSlotButton(); and CheckClearSlotButton();uncommented; I get:
Sketch uses 20390 bytes (63%) of program storage space
Global variables use 1069 bytes (52%) of dynamic memory
and the program loads and displays DJS Starting in Setup() over and over again.

It seems there is a issue related to how long the code is triggering a Arduino internal reset.
Any ideas on how to fix? Thanks

/**************************************************************************
 RDF TX START STOP TIMER - Arduino UNO
 **************************************************************************/
/* HARDWARE
 Arduino UNO - ATMega328P Bare IC
 Level Converter module - not currently used
 RTC with EEPROM module
 OLED Display
 Relay module or MOSFET Power Switching Circuit
 Switches
 --------
 Black  Yellow  White   Yellow  Green     White       Red
 MENU   DOWN    ENTER   UP      CANCEL    TX TEST     RESET
 D5     D6      D7      D8      D9        4           RST Capacitor

 TIME
 Time = Month * 1000000 + Day * 10000 + Hour * 100 + Minute

 **************************************************************************/
//#include "Arduino.h"
#include "uRTCLib.h"
//#include <SPI.h>
//#include <Wire.h>
#include <uEEPROMLib.h>

// uEEPROMLib eeprom;
uEEPROMLib eeprom(0x57);

//For the larger 128x64 display
//SCL = On Nano A5 // On MEGA D21  // On UNO  // On Bare ATMega328P
//SDA = On Nano A4 // On MEGA D20  // On UNO //  On Bare ATMega328P
//#include <Adafruit_GFX.h>
#include <Adafruit_SH110X.h>
#define i2c_Address 0x3c  //initialize with the I2C addr 0x3C Typically eBay OLED's
#define SCREEN_WIDTH 128  // OLED display width, in pixels
#define SCREEN_HEIGHT 64  // OLED display height, in pixels
#define OLED_RESET -1     //   QT-PY / XIAO
Adafruit_SH1106G display = Adafruit_SH1106G(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

// uRTCLib rtc;
//SCL = On Nano A5 // On MEGA D21  // On UNO  // On Bare ATMega328P
//SDA = On Nano A4 // On MEGA D20  // On UNO //  On Bare ATMega328P
uRTCLib rtc(0x68);

// I/O pins
// Need to add Analoge pins to test battery voltage
#define RDFTXBAT1VOLTS 0
#define RDFTXBAT2VOLTS 0

#define RDFTXPWRMOSFET1 14
#define RDFTXPWRRLY1_ON 10
#define RDFTXPWRRLY1_OFF 11
#define RDFTXPWRRLY2_ON 12
#define RDFTXPWRRLY2_OFF 13

#define SW_TX_TEST 4
#define SW_MENU 5
#define SW_DOWN 6
#define SW_ENTER 7
#define SW_UP 8
#define SW_CANCEL 9

#define DEBOUNCE_DELAY 100

// For UP DOWN switch counting
int Counter = 0;  //use int so can detect -ve numbers if we dec 0
byte SetStep = 0;
byte CurrentSlot = 0;
bool ExitRTCSet = true;
bool ExitSLOTSet = true;
bool ExitSLOTSelect = true;
bool ExitSLOTClear = true;

#define YEAR_INDEX 0
#define MONTH_INDEX 1
#define DAY_INDEX 2
#define DoW_INDEX 3
#define HOUR_INDEX 4
#define MINUTE_INDEX 5
#define SAVE_INDEX 6
#define QUIT_INDEX 7

#define SLOT_ON_MONTH_INDEX = 0
#define SLOT_ON_DAY_INDEX = 1
#define SLOT_ON_HOUR_INDEX = 2
#define SLOT_ON_MIN_INDEX = 3
#define SLOT_OFF_MONTH_INDEX = 4
#define SLOT_OFF_DAY_INDEX = 5
#define SLOT_OFF_HOUR_INDEX = 6
#define SLOT_OFF_MIN_INDEX = 7
#define SLOT_SAVE_INDEX 8

//                       0  1  2  3  4  5
//                       Y  M  D DoW h  m
byte RTCNewValues[] = { 24, 1, 1, 0, 0, 0 };
byte SetRTCMax[] = { 40, 12, 31, 6, 23, 59 };  // For rollover detect
byte SetRTCMin[] = { 24, 1, 1, 0, 0, 0 };      // For rollover min
byte SetSLOTMin[] = { 1, 1, 0, 0, 1, 1, 0, 0 };
byte SetSLOTMax[] = { 12, 31, 23, 59, 12, 31, 23, 59 };  // One dat the day per Feb code will get changed in SW based on Month selected
byte MonthDayMax[] = { 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
byte SLOTNewValues[] = { 0, 0, 0, 0, 0, 0, 0, 0 };  // Used to hold the slot values entered by user before commiting values to the EEPROM
byte OnOffProg[] = { 1, 2, 4, 5, 1, 2, 4, 5 };

 char buffer[11];
const char DoW_0[] PROGMEM = "SUN";  // We store DoW strings here
const char DoW_1[] PROGMEM = "MON";
const char DoW_2[] PROGMEM = "TUE";
const char DoW_3[] PROGMEM = "WED";
const char DoW_4[] PROGMEM = "THUR";
const char DoW_5[] PROGMEM = "FRI";
const char DoW_6[] PROGMEM = "SAT";
const char* const DoWs[] PROGMEM = { DoW_0, DoW_1, DoW_2, DoW_3, DoW_4, DoW_5, DoW_6 };

const char SetBanner_0[] PROGMEM = "YEAR";  // We store Setting display Banner strings here
const char SetBanner_1[] PROGMEM = "MONTH";
const char SetBanner_2[] PROGMEM = "DAY";
const char SetBanner_3[] PROGMEM = "DofW";
const char SetBanner_4[] PROGMEM = "HOUR";
const char SetBanner_5[] PROGMEM = "MIN";
const char SetBanner_6[] PROGMEM = "SAVE = UP";
const char SetBanner_7[] PROGMEM = "QUIT";
const char* const SetBanners[] PROGMEM = { SetBanner_0, SetBanner_1, SetBanner_2, SetBanner_3, SetBanner_4, SetBanner_5, SetBanner_6, SetBanner_7 };

const char S_OFF_0[] PROGMEM = "S0 OFF";  // We store RDF OFF setting Banner strings here
const char S_OFF_1[] PROGMEM = "S1 OFF";
const char S_OFF_2[] PROGMEM = "S2 OFF";
const char* const RDFOffBanners[] PROGMEM = { S_OFF_0, S_OFF_1, S_OFF_2 };

const char S_ON_0[] PROGMEM = "S0 ON";  // We store RDF ON setting Banner strings here
const char S_ON_1[] PROGMEM = "S1 ON";
const char S_ON_2[] PROGMEM = "S2 ON";
const char* const RDFOnBanners[] PROGMEM = { S_ON_0, S_ON_1, S_ON_2 };

const char SlotBanner_0[] PROGMEM = "SLOT 0";  // We store RDF ON setting Banner strings here
const char SlotBanner_1[] PROGMEM = "SLOT 1";
const char SlotBanner_2[] PROGMEM = "SLOT 2";
const char* const SlotBanners[] PROGMEM = { SlotBanner_0, SlotBanner_1, SlotBanner_2 };

// EEPROM location defintions
#define EEP_ON_MONTH 0
#define EEP_ON_DAY 1
#define EEP_ON_HOUR 2
#define EEP_ON_MIN 3
#define EEP_OFF_MONTH 4
#define EEP_OFF_DAY 5
#define EEP_OFF_HOUR 6
#define EEP_OFF_MIN 7

#define EEP_SLOT0 0x00
#define EEP_SLOT1 0x10
#define EEP_SLOT2 0x20

// To convert clock MM/DD hh:mm to a number for easy value comparison to start/stop RDF TX
// Ingnore the Year as RDF TX will not occur over New Year period
unsigned long RTC_TimeVal;

// To convert Slot0 MM/DD hh:mm to a number for easy value comparison to start/stopRDF TX
unsigned long on_Time0;
unsigned long off_Time0;

bool Tx = false;

void setup() {
  bool ExitRTCSet = true;
  bool ExitSLOTSet = true;
  byte SetStep = 0;

  Serial.begin(9600);
  delay(1000);  // wait for console opening
  Serial.println("DJS Starting");
  delay(500);

  //Configure the RTC
  rtc.disable32KOut();  //Do not need this signal in the RDF TX Power Control

  // Pin for controlling the power to the RDF TX unit set as output
  pinMode(RDFTXPWRMOSFET1, OUTPUT);

  // Pins for input switches
  pinMode(SW_TX_TEST, INPUT_PULLUP);
  pinMode(SW_UP, INPUT_PULLUP);
  pinMode(SW_DOWN, INPUT_PULLUP);
  pinMode(SW_ENTER, INPUT_PULLUP);
  pinMode(SW_MENU, INPUT_PULLUP);
  pinMode(SW_CANCEL, INPUT_PULLUP);

  URTCLIB_WIRE.begin();

  //For the 128x64 OLED display
  display.begin(i2c_Address, true);  // Address 0x3C default
  // Clear the buffer.
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(SH110X_WHITE);
  //As a boot screen display the current Date and Time
  display.setCursor(0, 0);
  display.println("RDF TX ON/OFF TIMER");
  display.println("     DJS 2024");
  display.println(" ");
  display.println("Current RTC is");
  display.println("Date");
  displayDate(true);
  display.println("Time");
  displayTime(true);
  display.display();
  delay(500);

  // Run the following line during development to pre-load the RTC with current date and time
  // rtc.set(second, minute, hour, dayOfWeek, dayOfMonth, month, year)
  //rtc.set(0, 50, 17, 5, 4, 7, 24);

  CheckSetRTC();
  CheckSetSlotsButton();
  CheckClearSlotsButton();

}  //Setup End

void loop() {
  // Display current Date Time
  display.clearDisplay();
  display.setTextSize(1);
  display.setCursor(0, 0);
  displayDate(false);
  display.println("           TX");
  displayTime(true);

  for (int i = 0; i <= 2; i++) {
    display.print("S0 ON :");
    if (eeprom.eeprom_read(EEP_ON_DAY + (0x10 * i)) == 0 && eeprom.eeprom_read(EEP_ON_MONTH + (0x10 * i)) == 0 && eeprom.eeprom_read(EEP_ON_HOUR + (0x10 * i)) == 0 && eeprom.eeprom_read(EEP_ON_MIN + (0x10 * i)) == 0) {
      display.println(" - NOT SET");
    } else {
      displayZeroPaddedEEPROMData(EEP_ON_DAY + (0x10 * i), false);
      display.print("/");
      displayZeroPaddedEEPROMData(EEP_ON_MONTH + (0x10 * i), false);
      display.print(" ");
      displayZeroPaddedEEPROMData(EEP_ON_HOUR + (0x10 * i), false);
      display.print(":");
      displayZeroPaddedEEPROMData(EEP_ON_MIN + (0x10 * i), false);
      display.print(" ");
      if (IsSlotON(i)) {
        display.println("ON");  //need to calc this
      } else {
        display.println("");
      }
    }
    display.print("S0 OFF:");
    if (eeprom.eeprom_read(EEP_OFF_DAY + (0x10 * i)) == 0 && eeprom.eeprom_read(EEP_OFF_MONTH + (0x10 * i)) == 0 && eeprom.eeprom_read(EEP_OFF_HOUR + (0x10 * i)) == 0 && eeprom.eeprom_read(EEP_OFF_MIN + (0x10 * i)) == 0) {
      display.println(" - NOT SET");
    } else {
      displayZeroPaddedEEPROMData(EEP_OFF_DAY + (0x10 * i), false);
      display.print("/");
      displayZeroPaddedEEPROMData(EEP_OFF_MONTH + (0x10 * i), false);
      display.print(" ");
      displayZeroPaddedEEPROMData(EEP_OFF_HOUR + (0x10 * i), false);
      display.print(":");
      displayZeroPaddedEEPROMData(EEP_OFF_MIN + (0x10 * i), false);
      display.println("");
    }
  }
  display.display();

  // TBD - If building the Dual Battery Relay Switched version will need to check which Battery we will connect to the RDF TX
  if (IsSlotON(0) || IsSlotON(1) || IsSlotON(2)) {
    // TURN ON THE TX POWER RELAY
    digitalWrite(RDFTXPWRMOSFET1, HIGH);  
  } else {
    // TURN OFF THE TX POWER RELAY
    digitalWrite(RDFTXPWRMOSFET1, LOW);  
  }
  //delay(500);
}  // End Loop


//*********************************************************
//     ____ _     _____    _    ____    ____  _     ___ _____ ____
//    / ___| |   | ____|  / \  |  _ \  / ___|| |   / _ \_   _/ ___|
//   | |   | |   |  _|   / _ \ | |_) | \___ \| |  | | | || | \___ \ 
//   | |___| |___| |___ / ___ \|  _ <   ___) | |__| |_| || |  ___) |
//    \____|_____|_____/_/   \_\_| \_\ |____/|_____\___/ |_| |____/
//
//*********************************************************
void CheckClearSlotsButton(void) {
  if (digitalRead(SW_UP) == LOW) {  // As the SW_UP was held down during power up, we do the SLOT clearing.
    Serial.println("Entering SLOT Clearing Menu");
    delay(DEBOUNCE_DELAY);
    while (digitalRead(SW_UP) == LOW) {}  //Wait for SW_UP to be released
    ExitSLOTClear = false;
    ExitSLOTSelect = false;
    SetStep = 0;
    CurrentSlot = 0;

    while (ExitSLOTClear == false) {
      while (ExitSLOTSelect == false) {
        // Display the three slot options with a selection pointer
        display.clearDisplay();
        display.setCursor(0, 0);
        display.setTextSize(2);  // Display the top line banner for what we are doing
        display.println("CLEAR SLOT");
        displayCursor(0);
        strcpy_P(buffer, (char*)pgm_read_word(&(SlotBanners[0])));
        display.println(buffer);
        displayCursor(1);
        strcpy_P(buffer, (char*)pgm_read_word(&(SlotBanners[1])));
        display.println(buffer);
        displayCursor(2);
        strcpy_P(buffer, (char*)pgm_read_word(&(SlotBanners[2])));
        display.println(buffer);
        display.display();
        if (digitalRead(SW_UP) == LOW) {
          delay(DEBOUNCE_DELAY);
          CurrentSlot++;
          if (CurrentSlot == 3) {
            CurrentSlot = 0;
          }
        }
        if (digitalRead(SW_DOWN) == LOW) {
          delay(DEBOUNCE_DELAY);
          CurrentSlot--;
          if (CurrentSlot == 255) {
            CurrentSlot = 2;
          }
        }
        if (digitalRead(SW_ENTER) == LOW) {  //The selected slot is remebered by global CurrentSlot
          delay(DEBOUNCE_DELAY);
          while (digitalRead(SW_ENTER) == LOW) {}  //Wait for SW_ENTER to be released
          ExitSLOTSelect = true;
        }

        if (digitalRead(SW_CANCEL) == LOW) {  //Get out of SLOT clearing
          delay(DEBOUNCE_DELAY);
          display.clearDisplay();
          display.setCursor(0, 0);
          display.setTextSize(2);
          display.println("QUITING");
          display.println("SLOTS");
          display.println("CLEAR");
          display.display();
          delay(2000);
          ExitSLOTSelect = true;
          ExitSLOTClear = true;
        }
      }  //End while(ExitSLOTSelect)

      // Having selected a SLOT (CurrentSlot) we now confirm with user to clear the Start End Date/Times
      display.clearDisplay();
      display.setCursor(0, 0);
      display.println("CLEARING");
      strcpy_P(buffer, (char*)pgm_read_word(&(SlotBanners[CurrentSlot])));
      display.println(buffer);
      display.println("ENTER or");
      display.println("EXIT");

      // Refresh the display with the new information
      display.display();

      // Check Enter for next step
      if (digitalRead(SW_ENTER) == LOW) {
        delay(DEBOUNCE_DELAY);
        while (digitalRead(SW_ENTER) == LOW) {}  //Wait for SW_ENTER to be released
        //Clear SLOT data in EEPROM
        for (int i = 0; i <= 7; i++) {
          //  eeprom.eeprom_write(addr, data)
          if (!eeprom.eeprom_write(i + (0x10 * CurrentSlot), 0)) {
            Serial.println("EEPROM Write Failed");
          }
        }
        display.clearDisplay();
        display.setCursor(0, 0);
        display.setTextSize(2);
        display.println("SLOT DATA");
        display.println("CLEARED");
        display.display();
        delay(3000);
        ExitSLOTClear = true;
      }
      if (digitalRead(SW_CANCEL) == LOW) {
        delay(DEBOUNCE_DELAY);
        ExitSLOTClear = true;
      }
    }  // End while(ExitSLOTClear == false)

    if (digitalRead(SW_CANCEL) == LOW) {
      delay(DEBOUNCE_DELAY);
      ExitSLOTClear = true;
    }
  }  // End (digitalRead(SW_UP) == LOW)
}

//*********************************************************
//     ____  _____ _____   ____  _     ___ _____ ____
//    / ___|| ____|_   _| / ___|| |   / _ \_   _/ ___|
//    \___ \|  _|   | |   \___ \| |  | | | || | \___ \ 
//     ___) | |___  | |    ___) | |__| |_| || |  ___) |
//    |____/|_____| |_|   |____/|_____\___/ |_| |____/
//
//*********************************************************
void CheckSetSlotsButton(void) {
  // There ar three possible Slots to store Start and End RDF TX times. Slot_0 to Slot_2
  // Will assume a RDF TX will not go through midnight as we need to get some sleep.
  // So basically an RDF TX will start and stop on the same day.
  // Slot times should not overlap
  if (digitalRead(SW_DOWN) == LOW) {  // As the SW_DOWN was held down during power up, we do the SLOT Date/Time setting.
    Serial.println("Entering SLOT Date/Time Setting Menu");
    delay(DEBOUNCE_DELAY);
    while (digitalRead(SW_DOWN) == LOW) {}  //Wait for SW_DOWN to be released
    ExitSLOTSet = false;
    ExitSLOTSelect = false;
    SetStep = 0;
    CurrentSlot = 0;
    SLOTNewValues[SetStep] = SetSLOTMin[SetStep];  // eg 1 for the Set MONTH
    //or
    //Preload the new values with current RTC values. Saves on button presses when setting Date / Time
    rtc.refresh();
    SLOTNewValues[0] = rtc.month();
    SLOTNewValues[1] = rtc.day();
    SLOTNewValues[2] = rtc.hour();

    while (ExitSLOTSet == false) {
      while (ExitSLOTSelect == false) {
        // Display the four slot options with a selection pointer
        display.clearDisplay();
        display.setCursor(0, 0);
        display.setTextSize(2);  // Display the top line banner for what we are setting
        display.println("SET SLOT");
        displayCursor(0);
        strcpy_P(buffer, (char*)pgm_read_word(&(SlotBanners[0])));
        display.println(buffer);
        displayCursor(1);
        strcpy_P(buffer, (char*)pgm_read_word(&(SlotBanners[1])));
        display.println(buffer);
        displayCursor(2);
        strcpy_P(buffer, (char*)pgm_read_word(&(SlotBanners[2])));
        display.println(buffer);
        display.display();
        if (digitalRead(SW_UP) == LOW) {
          delay(DEBOUNCE_DELAY);
          CurrentSlot++;
          if (CurrentSlot == 3) {
            CurrentSlot = 0;
          }
        }
        if (digitalRead(SW_DOWN) == LOW) {
          delay(DEBOUNCE_DELAY);
          CurrentSlot--;
          if (CurrentSlot == 255) {
            CurrentSlot = 2;
          }
        }
        if (digitalRead(SW_ENTER) == LOW) {
          delay(DEBOUNCE_DELAY);
          while (digitalRead(SW_ENTER) == LOW) {}  //Wait for SW_ENTER to be released
          ExitSLOTSelect = true;
        }
        if (digitalRead(SW_CANCEL) == LOW) {  //Get out of SLOT setting
          delay(DEBOUNCE_DELAY);
          display.clearDisplay();
          display.setCursor(0, 0);
          display.setTextSize(2);
          display.println("QUITING");
          display.println("SLOTS");
          display.println("NO");
          display.println("SAVE");
          display.display();
          delay(2000);
          ExitSLOTSelect = true;
          ExitSLOTSet = true;
        }
      }

      // Having selected a SLOT (CurrentSlot) we now load the Start End Date/Times
      display.clearDisplay();
      display.setCursor(0, 0);
      display.setTextSize(2);  // Display the top line banner for what we are setting
      if (SetStep <= 3) {
        strcpy_P(buffer, (char*)pgm_read_word(&(RDFOnBanners[CurrentSlot])));
      } else {
        strcpy_P(buffer, (char*)pgm_read_word(&(RDFOffBanners[CurrentSlot])));
      }
      display.println(buffer);
      strcpy_P(buffer, (char*)pgm_read_word(&(SetBanners[OnOffProg[SetStep]])));
      display.println(buffer);

      // Display the data Value for this setting
      if (SetStep < SLOT_SAVE_INDEX) {
        display.setTextSize(4);
        display.println(SLOTNewValues[SetStep]);
      }
      // Save window goes here
      if (SetStep == SLOT_SAVE_INDEX) {
        display.clearDisplay();
        display.setCursor(0, 0);
        display.setTextSize(2);
        display.println(" ENTER To");
        display.println("   Save");
        display.print("  SLOT ");
        display.println(CurrentSlot);
        display.println("or QUIT");
      }

      // Refresh the display with the new information
      display.display();

      //Check the UP and DOWN buttons for Value Counter
      if (digitalRead(SW_UP) == LOW) {
        delay(DEBOUNCE_DELAY);
        while (digitalRead(SW_UP) == LOW) {}  //Wait for SW_UP to be released
        SLOTNewValues[SetStep]++;
        if (SLOTNewValues[SetStep] > SetSLOTMax[SetStep]) {
          SLOTNewValues[SetStep] = SetSLOTMin[SetStep];
        }
      }

      if (digitalRead(SW_DOWN) == LOW) {
        delay(DEBOUNCE_DELAY);
        while (digitalRead(SW_DOWN) == LOW) {}  //Wait for SW_DOWN to be released
        SLOTNewValues[SetStep]--;
        if (SLOTNewValues[SetStep] > SetSLOTMax[SetStep]) {  // Byte 0 decrement rollover to 255
          SLOTNewValues[SetStep] = SetSLOTMax[SetStep];
        }
        if (SLOTNewValues[SetStep] < SetSLOTMin[SetStep]) {
          SLOTNewValues[SetStep] = SetSLOTMax[SetStep];
        }
      }

      // Check Enter for next step
      if (digitalRead(SW_ENTER) == LOW) {
        delay(DEBOUNCE_DELAY);
        while (digitalRead(SW_ENTER) == LOW) {}  //Wait for SW_ENTER to be released
        //will need to check if we can copy previous entry as start point or are we at the last step
        switch (SetStep) {
          case 0:  //Moving from Month ON to Day ON
            SetStep++;
            //SLOTNewValues[SetStep] = SetSLOTMin[SetStep];  //as have moved to new data location update initial data
            break;
          case 1:  //Moving from Day ON to Hour ON
            SetStep++;
            //SLOTNewValues[SetStep] = SetSLOTMin[SetStep];  //as have moved to new data location update initial data
            break;
          case 2:  //Moving from Hour ON to Minute ON
            SetStep++;
            SLOTNewValues[SetStep] = SetSLOTMin[SetStep];  //as have moved to new data location update initial data
            break;
          case 3:  //Moving from Minute ON to Month OFF, so copy Month ON as a start value
            SetStep++;
            SLOTNewValues[SetStep] = SLOTNewValues[SetStep - 4];  //as have moved to new data location update initial data
            break;
          case 4:  //Moving from Month OFF to Day OFF, so copy Day ON as a start value
            SetStep++;
            SLOTNewValues[SetStep] = SLOTNewValues[SetStep - 4];  //as have moved to new data location update initial data
            break;
          case 5:  //Moving from Day off to Hour OFF, so copy Hour ON as a start value
            SetStep++;
            SLOTNewValues[SetStep] = SLOTNewValues[SetStep - 4];  //as have moved to new data location update initial data
            break;
          case 6:  //Moving from Hour OFF to Minute OFF, so copy Minute ON as a start value
            SetStep++;
            SLOTNewValues[SetStep] = SLOTNewValues[SetStep - 4];  //as have moved to new data location update initial data
            break;
          case 7:  //Moving from Minute OFF to SAVE message. Do not copy any data
            SetStep++;
            break;
          case 8:  //Moving from SAVE message to do SAVE. Copy data to EEPROM
            //save data to EEPROM
            for (int i = 0; i <= 7; i++) {
              //  eeprom.eeprom_write(addr, data)
              if (!eeprom.eeprom_write(i + (0x10 * CurrentSlot), SLOTNewValues[i])) {
                //Serial.println("EEPROM Write Failed");
              } 
            }

            display.clearDisplay();
            display.setCursor(0, 0);
            display.setTextSize(2);
            display.println("SLOT DATA");
            display.println("SAVED");
            display.display();
            delay(3000);
            ExitSLOTSet = true;
            break;
          default:
            // Nothing to see here
            break;
        }
      }

      if (digitalRead(SW_CANCEL) == LOW) {
        delay(DEBOUNCE_DELAY);
        ExitSLOTSet = true;
      }
    }
  }  // End (digitalRead(SW_DOWN) == LOW)
}

//*********************************************************
//    ____  _____ _____   ____ _____ ____
//   / ___|| ____|_   _| |  _ \_   _/ ___|
//   \___ \|  _|   | |   | |_) || || |
//    ___) | |___  | |   |  _ < | || |___
//   |____/|_____| |_|   |_| \_\|_| \____|
//
//*********************************************************
void CheckSetRTC(void) {
  //To fully set the RTC the user needs to input all Y,M,D,DoW,h,m. The seconds will be set to 00 on save
  //To enable time setting the SW_MENU must be held during power up
  //Month, Day, DayofWeek, Hours and Minutes will roll over.
  //A press on SW_CANCEL will exit and does NOT store the entered values into the RTC
  //The buttons are:
  // MENU   DOWN   ENTER   UP  CANCEL
  // To save the entered data into the RTC:
  //   Enter required value with the UP and DOWN buttons
  //     Press ENTER
  //     Display will move to the next RTC item - repeat above
  //     When on the Save RTC display - Pressing UP will save the data into the RTC
  //     When on the Save RTC display - Pressing CANCEL will exit not saving the data into the RTC

  if (digitalRead(SW_MENU) == LOW) {  // As the SW_MENU was held down during power up, we do the RTC Date/Time setting.
    Serial.println("Entering RTC Setting Menu");
    ExitRTCSet = false;
    SetStep = 0;
    Counter = SetRTCMin[SetStep];  // eg 24 for the Set YEAR
    delay(DEBOUNCE_DELAY);
    while (digitalRead(SW_MENU) == LOW) {}  //wait for button release
    while (ExitRTCSet == false) {
      display.clearDisplay();
      display.setCursor(0, 0);
      display.setTextSize(2);  // Display the top line banner for what we are setting
      strcpy_P(buffer, (char*)pgm_read_word(&(SetBanners[SetStep])));
      display.println(buffer);
      if (SetStep <= MINUTE_INDEX && SetStep != DoW_INDEX) {  // Show the data as a number
        display.setTextSize(5);
        display.println(RTCNewValues[SetStep]);
      }
      if (SetStep == DoW_INDEX) {  // Show the data as text
        display.setTextSize(5);
        strcpy_P(buffer, (char*)pgm_read_word(&(DoWs[Counter])));
        display.println(buffer);
        //Serial.println(buffer);
      }
      if (SetStep == SAVE_INDEX) {  // Show the data that will be stored in the RTC
        if (RTCNewValues[DAY_INDEX] <= 9) { display.print("0"); }
        display.print(RTCNewValues[DAY_INDEX]);
        display.print("/");
        if (RTCNewValues[MONTH_INDEX] <= 9) { display.print("0"); }
        display.print(RTCNewValues[MONTH_INDEX]);
        display.print("/");
        display.println(RTCNewValues[YEAR_INDEX]);

        display.print("  ");
        strcpy_P(buffer, (char*)pgm_read_word(&(DoWs[RTCNewValues[DoW_INDEX]])));
        display.println(buffer);

        if (RTCNewValues[HOUR_INDEX] <= 9) { display.print("0"); }
        display.print(RTCNewValues[HOUR_INDEX]);
        display.print(":");
        if (RTCNewValues[MINUTE_INDEX] <= 9) { display.print("0"); }
        display.print(RTCNewValues[MINUTE_INDEX]);
        display.print(":");
        display.println("00");
        display.display();

        while (1) {
          if (digitalRead(SW_UP) == LOW) {
            delay(DEBOUNCE_DELAY);
            while (digitalRead(SW_UP) == LOW) {  //wait for button release
              //Serial.println("Waiting for SW_UP release");
            }
            //save the data to RTC
            //rtc.set(second, minute, hour, dayOfWeek, dayOfMonth, month, year);
            Serial.println("Saving RTC");
            rtc.set(0, RTCNewValues[MINUTE_INDEX], RTCNewValues[HOUR_INDEX], RTCNewValues[DoW_INDEX], RTCNewValues[DAY_INDEX], RTCNewValues[MONTH_INDEX], RTCNewValues[YEAR_INDEX]);
            ExitRTCSet = true;
            break;
          }
          if (digitalRead(SW_CANCEL) == LOW) {
            delay(DEBOUNCE_DELAY);
            //Serial.println("QUIT - No RTC Save");
            //Do not save into RTC
            ExitRTCSet = true;
            break;
          }
        }
      }

      display.display();
      //delay(100);

      //Check the UP and DOWN buttons
      if (digitalRead(SW_UP) == LOW) {
        delay(DEBOUNCE_DELAY);
        Counter++;
        if (Counter > SetRTCMax[SetStep]) {
          Counter = SetRTCMin[SetStep];
        }
      }
      if (digitalRead(SW_DOWN) == LOW) {
        delay(DEBOUNCE_DELAY);
        Counter--;
        if (Counter < SetRTCMin[SetStep]) {
          Counter = SetRTCMax[SetStep];
        }
      }
      RTCNewValues[SetStep] = Counter;
      //Serial.print("Counter: ");
      //Serial.println(Counter);

      if (digitalRead(SW_ENTER) == LOW) {
        delay(DEBOUNCE_DELAY);
        while (digitalRead(SW_ENTER) == LOW) {
        }
        SetStep++;
        if (SetStep >= 8) {
          SetStep = QUIT_INDEX;
        }
        if (SetStep < SAVE_INDEX) {
          Counter = SetRTCMin[SetStep];  // have moved to a new setting option so load the Min value
        }

        if (SetStep == QUIT_INDEX) {
          // DO NOT Save the RTC temp data to the RTC
          // Clear the RTC temp data
        }
        if (SetStep >= 8) {
          SetStep = QUIT_INDEX;
        }
      }

      if (digitalRead(SW_CANCEL) == LOW) {
        delay(DEBOUNCE_DELAY);
        //Need to cancel any RTC changes
        ExitRTCSet = true;
      }
    }
  }  //End digitalRead(SW_MENU) == LOW)
}

//* CALC LONG TIME ***********************************
unsigned long CalcLongTime(byte Month, byte Day, byte Hour, byte Minute) {
  return Month * 1000000 + Day * 10000 + Hour * 100 + Minute;
}

//* IS SLOT ON ***********************************
bool IsSlotON(byte Slot) {
  rtc.refresh();
  if (CalcLongTime(rtc.month(), rtc.day(), rtc.hour(), rtc.minute())
        >= CalcLongTime(eeprom.eeprom_read(EEP_ON_MONTH + (0x10 * Slot)), eeprom.eeprom_read(EEP_ON_DAY + (0x10 * Slot)), eeprom.eeprom_read(EEP_ON_HOUR + (0x10 * Slot)), eeprom.eeprom_read(EEP_ON_MIN + (0x10 * Slot)))
      && CalcLongTime(rtc.month(), rtc.day(), rtc.hour(), rtc.minute())
           < CalcLongTime(eeprom.eeprom_read(EEP_OFF_MONTH + (0x10 * Slot)), eeprom.eeprom_read(EEP_OFF_DAY + (0x10 * Slot)), eeprom.eeprom_read(EEP_OFF_HOUR + (0x10 * Slot)), eeprom.eeprom_read(EEP_OFF_MIN + (0x10 * Slot)))) {
    return true;
  } else {
    return false;
  }
}

//* DISPLAY ZERO PADDED EEPROM DATA ***********************************
void displayZeroPaddedEEPROMData(unsigned int EEP_Address, bool DoCR) {
  if (eeprom.eeprom_read(EEP_Address) <= 9) {
    display.print("0");
  }
  display.print(eeprom.eeprom_read(EEP_Address));
  if (DoCR == true) {
    display.println("");
  }
}

//* DISPLAY CURSOR ***********************************
void displayCursor(byte row) {  //uses the global CurrentSlot
  if (CurrentSlot == row) {
    display.print("> ");
  } else {
    display.print("  ");
  }
}

//* DISPLAY DATE ***********************************
void displayDate(bool DoLF) {
  rtc.refresh();
  if (rtc.day() <= 9) {
    display.print("0");
  }
  display.print(rtc.day());
  display.print("/");
  if (rtc.month() <= 9) {
    display.print("0");
  }
  display.print(rtc.month());
  display.print("/");
  if (rtc.year() <= 9) {
    display.print("0");
  }
  display.print(rtc.year());
  if (DoLF == true) {
    display.println("");
  }
}

//* DISPLAY TIME ***********************************
void displayTime(bool DoLF) {
  rtc.refresh();
  if (rtc.hour() <= 9) {
    display.print("0");
  }
  display.print(rtc.hour());
  display.print(":");
  if (rtc.minute() <= 9) {
    display.print("0");
  }
  display.print(rtc.minute());
  display.print(":");
  if (rtc.second() <= 9) {
    display.print("0");
  }
  display.print(rtc.second());
  if (DoLF == true) {
    display.println("");
  }
}

Welcome to the forum

I don't have time to look in detail at the moment, but this sounds like a classic case of writing to memory that you should not be using. This is typically caused by writing past the end of an array

I always hate Adafruit libraries because I have difficulty following the full path; that is however my problem and not yours :wink:

The Adafruit library uses dynamic memory allocation; that is not counted in the memory usage (global variables). 128x64 bits = 8192 bits. So that is 1kB (for monochrome) or 4kB (for 4-bit colour) and you have to add that to the memory usage.

From my view, you're simply running out of memory.

IIRC The display ‘s begin() call is what allocates a dynamic buffer for your display. That memory is not accounted for when you compile as the allocation is dynamic. For a black and white 128x64 display you might need 1kB of memory which is 50% of your UNO’s memory. So if the rest of the code is above 50% then you run out of memory.

Check out what begin() returns

Edit: basically the same answer as @sterretje

Yes quite possible, but none of the code in CheckSetRTC(); , CheckSetSlotButton(); and
CheckClearSlotButton(); is being executed. All those blocks of code only run if I hold one of the three buttons down during powerup or reset. Which I am not doing :frowning:
It look like merely compiling the code into the Arduino causes the issue. Not the running of those additional code bits.

When you run out of memory weird stuff happens.

Check the result of the call to begin. If it’s false then you have an issue

Thanks. Ah so the compile % have been fooling me into thinking I have spare memory. Sound like I need to move to Mega2560. But I only want to use the bare IC to save power. Maybe Atmega1284P

If the screen needs to be constantly on then saving power on the MCU is not so meaningful.

Hi J-M-L. I plan to shutdown the screen etc and wait for the RTC to wake up Arduino with an alarm. I have not written that code yet as the reboot issue stopped me in my tracks.
This thing might be sitting in a cave for two days before it needs to wake up and do some RDF TX.

To get an idea how much memory the Adafruit library uses, you can load and run the below code. It will display the actual free memory before and after the call to display.begin() in serial monitor; baud rate 115200 (just in case). I've just stripped down your original code.

Source for the two additional functions: https://docs.arduino.cc/learn/programming/memory-guide/

#include <Adafruit_SH110X.h>
#define i2c_Address 0x3c  //initialize with the I2C addr 0x3C Typically eBay OLED's
#define SCREEN_WIDTH 128  // OLED display width, in pixels
#define SCREEN_HEIGHT 64  // OLED display height, in pixels
#define OLED_RESET -1     //   QT-PY / XIAO
Adafruit_SH1106G display = Adafruit_SH1106G(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);


void setup()
{
  Serial.begin(115200);
  display_freeram();
  //For the 128x64 OLED display
  display.begin(i2c_Address, true);  // Address 0x3C default
  display_freeram();
  // Clear the buffer.
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(SH110X_WHITE);
  //As a boot screen display the current Date and Time
  display.setCursor(0, 0);
  display.println("RDF TX ON/OFF TIMER");
  display.println("     DJS 2024");
}

void loop() {
  // put your main code here, to run repeatedly:

}



void display_freeram() {
  Serial.print(F("- SRAM left: "));
  Serial.println(freeRam());
}

int freeRam() {
  extern int __heap_start,*__brkval;
  int v;
  return (int)&v - (__brkval == 0  
    ? (int)&__heap_start : (int) __brkval);  
}

Correct.

No, there is an alternative to the Adafruit library which uses less memory: it's called U8G2.

Some re-coding will be required in order to use it, and there is a performance penalty involved, because in order to save memory, the display is updated in sections, and the part of your code that draws to the display needs to be run several times over to update the whole display.

I'm not sure; after all one still needs that memory (static or dynamic). Only difference can be 1-bit (monochrome) vs 4-bit (gray scale). But still, at least 1kB needed.

BTW, there was recently a topic (Neopixel interrupting CanBus : Project Problem) where using the Adafruit library worked and the U8G2lib caused problems.

@sterretje What do you mean by static? Flash memory? I thought the problem here was RAM/dynamic memory. Did I miss something?

SH110X are monochrome...

Not with U8G2, as I explained above. Can be as little as 256 bytes, or 512 bytes for a balance of performance Vs dynamic memory savings.

No, just RAM that is not dynamically allocated.

I did not realise that, thanks.

1 Like

I scanned that topic briefly. Not convinced the problem was with U8G2.

The poster on that topic was using the "_F_" constructor for the display object. The dynamic memory used would be the same as the Adafruit library, except that U8G2 allocates the memory at compile time, Vs at run time.

Ah! Suddenly realised what you meant by static & dynamic in your previous post! Sorry, @sterretje!

With U8G2 you can choose the "_1_" or "_2_" constructors which will use 256 or 512 bytes for the display buffer.

1 Like

You can get or make a board with ATmega1284P and have 16K RAM plus 32 IO pins, 2 UARTs. The chip should cost less than $6.

I do not see where anyone has suggested the use of the F() macro for the calls to print, that reduces the ram usage to about 660 bytes.

Good point about saving RAM. There's also changint type int variables to type byte or uint8_t for small values like pin numbers.

If you changed the OP's code to use F( macro ) then maybe post it too to save the OP work?

Hi All, the OP DJSCaver here. A big thank you to all those that have (and may) responded to my question. It has been interesting to learn about compile time and run time memory use calculations, the existence of other display libraries etc. While I would like to sit here and chat to you all over a coffee..... I need to wander back to the Arduino IDE and implement all the good help you all have provided. Thanks DJSCaver