DS3231 misreading with current draw

When you get it working, post a picture.

Thanks ZX. I believe I removed the jumper to put it in 3A mode but I'll double check

Unfortunately, changing the duplicate assignment of the I2C pins didn't solve the problem.

Here are the custom classes I wrote for TimeWords and RainbowWords, in case there might be something in here:

RainbowWords:

#include "RainbowWords.h"

RainbowWords::RainbowWords() {
  return;
}

void RainbowWords::initialize() {
  strip = Adafruit_NeoPixel(PIXEL_COUNT, PIXEL_PIN, NEO_GRB + NEO_KHZ800);

  // Serial.println(F("Initializing all LEDs to 'off'"));
  // Initialize all pixels to 'off'
  strip.setBrightness(255);
  strip.begin();
  strip.show();

// Ensure it's an empty string
  for (int i=0; i < MAX_WORDS; i++) {
    RainbowWords::wordsToLight[i][0] = '\0';
    RainbowWords::previousWordsToLight[i][0] = '\0';
  }
// Ensure pixelOnOffStates are zeroed
  for (int i=0; i < PIXEL_COUNT; i++) {
    RainbowWords::pixelOnOffStates[i] = 0;
  }
  // "light" them by turning off.
  RainbowWords::lightPixels(100);
}

void RainbowWords::assignBirthday(char name[MAX_WORD_LENGTH] = "") {
    strncpy(RainbowWords::wordsToLight[0], "HAPPY", MAX_WORD_LENGTH);
    strncpy(RainbowWords::wordsToLight[1], "BIRTH", MAX_WORD_LENGTH);
    strncpy(RainbowWords::wordsToLight[2], "DAY", MAX_WORD_LENGTH);

    if (strlen(name) > 0) { // Use strlen for char arrays
      strncpy(RainbowWords::wordsToLight[3], name, MAX_WORD_LENGTH); 
    } else {
      RainbowWords::wordsToLight[3][0] = '\0';
    }
}

void RainbowWords::lightPixels(uint32_t wait) {

  // Serial.println(F("lighting pixels"));
  // normally go to 256 to cycle colours
  for(int j=0; j<1; j=j+20) {
    // // Serial.print("j = "));
    // // Serial.println(j);
    for (int i=0; i<strip.numPixels(); i++) {
      RainbowWords::strip.setPixelColor(i, Wheel((i+j) & 255)*pixelOnOffStates[i]);
      if (pixelOnOffStates[i] == 1)
      {
        // Serial.println(i);
        RainbowWords::strip.show();
        delay(wait);
      }
    }
    
  }
  // Serial.println(F("Finished lighting pixels."));
  return;
}

void RainbowWords::updateAllRainbowWords(DateTime now) {
  getWordsToLight(now);
  // Serial.println(F("Words to light are:"));
  // for (int i=0; i < MAX_WORDS; i++) {
    // Serial.print(RainbowWords::wordsToLight[i]);
    // Serial.print(", ");
  // }
  // Serial.println();
  if (!charArraysAreIdentical(RainbowWords::wordsToLight, RainbowWords::previousWordsToLight)) {
    // Serial.println(F("charArrays are NOT identical, updating words..."));
    // Ensure pixelOnOffStates are zeroed
    for (int i=0; i < PIXEL_COUNT; i++) {
      RainbowWords::pixelOnOffStates[i] = 0;
    }
    for (int i=0; i < MAX_WORDS; i++) {
      // Serial.print("Flagging LEDs for word: ");
      // Serial.println(RainbowWords::wordsToLight[i]);
      flagLedsForWord(RainbowWords::wordsToLight[i]);
      // Serial.println(i);
    }
    RainbowWords::lightPixels(1000);
    for (int i=0; i < MAX_WORDS; i++) {
      strncpy(RainbowWords::previousWordsToLight[i], RainbowWords::wordsToLight[i], MAX_WORD_LENGTH);
    }
  }
  // Serial.println(F("Finished updating Rainbow words."));
  return;
}

void RainbowWords::getWordsToLight(DateTime now) {
  // Serial.print("Minute: ");
  // Serial.println(now.minute());

  bool day_assigned = false;
  if (now.month() == 2) {
    if (now.day() == 8) {
      // Serial.println(F("Feb. 8, pauline's birthday"));
      assignBirthday("PAULINE");
      day_assigned = true;
    }
// truncated for privacy
  } else if (now.month() == 10){
    } if (now.day() == 31) {
      // Serial.println(F("Oct. 31, Happy halloween."));
      strncpy(RainbowWords::wordsToLight[0], "HAPPY", MAX_WORD_LENGTH);
      strncpy(RainbowWords::wordsToLight[1], "halloween", MAX_WORD_LENGTH);
      RainbowWords::wordsToLight[2][0] = '\0'; // Set to empty string
      RainbowWords::wordsToLight[3][0] = '\0'; // Set to empty string
      day_assigned = true;
    }
  } else if (now.month() == 11){
    if (now.day() == 8) {
      // Serial.println(F("Nov 8, jacky's birthday"));
      assignBirthday("JACKY");
      day_assigned = true;
    }
 } else if (now.month() == 11){
    } if (now.day() == 25) {
      // Serial.println(F("Dec. 25, Merry Christmas."));
      strncpy(RainbowWords::wordsToLight[0], "MERRY", MAX_WORD_LENGTH);
      strncpy(RainbowWords::wordsToLight[1], "XMAS", MAX_WORD_LENGTH);
      RainbowWords::wordsToLight[2][0] = '\0'; // Set to empty string
      RainbowWords::wordsToLight[3][0] = '\0'; // Set to empty string
      day_assigned = true;
    }
  } else {
      // nonsense month!
      for (int i=0; i < MAX_WORDS; i++) {
          RainbowWords::wordsToLight[i][0] = '\0';
      }
      day_assigned = true;
    }
    if (now.minute() <= 5 && !day_assigned) {
      strncpy(RainbowWords::wordsToLight[0], "HAPPY", MAX_WORD_LENGTH);
      strncpy(RainbowWords::wordsToLight[1], "DAY", MAX_WORD_LENGTH);
      RainbowWords::wordsToLight[2][0] = '\0'; // Set to empty string
      RainbowWords::wordsToLight[3][0] = '\0'; // Set to empty string
    } else if (!day_assigned) {
        // Serial.println(F("No special day today"));
        for (int i=0; i < MAX_WORDS; i++) {
          RainbowWords::wordsToLight[i][0] = '\0';
        }
    }
}

// Function to check if two arrays of strings (char arrays) are identical
bool RainbowWords::charArraysAreIdentical(char arr1[MAX_WORDS][MAX_WORD_LENGTH], char arr2[MAX_WORDS][MAX_WORD_LENGTH]) {
    for (int i = 0; i < MAX_WORDS; i++) {
      if (strcmp(arr1[i], arr2[i]) != 0) { // Use strcmp for char array comparison
        return false; // Found a mismatch
      }
    }
    return true; // All elements match
}

void RainbowWords::flagLedsForWord(char word[MAX_WORD_LENGTH]) {
    // Serial.print("Word to flag LEDs: ");
    // Serial.println(word);
    static const int merry = 7;
    static const int halloween = 14;
    static const int bob = 3;
    static const int xmas = 6;
    static const int andre = 8;
    static const int jacky = 8;
    static const int frank = 7;
    static const int pauline = 10;
    static const int bill = 6;
    static const int day = 3;
    static const int birth = 8;
    static const int happy = 8; 

    if (strcmp(word, "MERRY") == 0) {
      for (int i = 0; i < merry; i++) {
        pixelOnOffStates[i] = 1;
      }
    } else if (strcmp(word, "halloween") == 0) {
      for (int i = merry; i < merry + halloween; i++) {
        pixelOnOffStates[i] = 1;
      }
    } else if (strcmp(word, "JOE") == 0) {
      for (int i = merry; i < merry + bob; i++) {
        pixelOnOffStates[i] = 1;
      }
    } else if (strcmp(word, "XMAS") == 0) {
      for (int i = merry + halloween; i < merry + halloween + xmas; i++) {
        pixelOnOffStates[i] = 1;
      }
    } else if (strcmp(word, "ANDRE") == 0) {
      for (int i = merry + halloween + xmas + 1 ; i < merry + halloween + xmas + andre - 1; i++) {
        pixelOnOffStates[i] = 1;
      }
    } else if (strcmp(word, "JACKY") == 0) {
      for (int i = merry + halloween + xmas + andre; i < merry + halloween + xmas + andre + jacky - 1; i++) {
        pixelOnOffStates[i] = 1;
      }
    } else if (strcmp(word, "FRANK") == 0) {
      for (int i = merry + halloween + xmas + andre + jacky; i < merry + halloween + xmas + andre + jacky + frank; i++) {
        pixelOnOffStates[i] = 1;
      }
    } else if (strcmp(word, "PAULINE") == 0) {
      for (int i = merry + halloween + xmas + andre + jacky + frank; i < merry + halloween + xmas + andre + jacky + frank + pauline; i++) {
        pixelOnOffStates[i] = 1;
      }
    } else if (strcmp(word, "BILL") == 0) {
      for (int i = merry + halloween + xmas + andre + jacky + frank + pauline; i < merry + halloween + xmas + andre + jacky + frank + pauline + bill; i++) {
        pixelOnOffStates[i] = 1;
      }
    } else if (strcmp(word, "DAY") == 0) {
      for (int i = merry + halloween + xmas + andre + jacky + frank + pauline + bill; i < merry + halloween + xmas + andre + jacky + frank + pauline + bill + day; i++) {
        pixelOnOffStates[i] = 1;
      }
    } else if (strcmp(word, "BIRTH") == 0) {
      // special case: andre
      for (int i = merry + halloween + xmas + andre + jacky + frank + pauline + bill + day; i < merry + halloween + xmas + andre + jacky + frank + pauline + bill + day + birth; i++) {
        pixelOnOffStates[i] = 1;
      }
    } else if (strcmp(word, "HAPPY") == 0) {
      for (int i = merry + halloween + xmas + andre + jacky + frank + pauline + bill + day + birth; i < merry + halloween + xmas + andre + jacky + frank + pauline + bill + day + birth + happy; i++) {
        pixelOnOffStates[i] = 1;
      }
    }
  }


// Input a value 0 to 255 to get a color value.
// The colours are a transition r - g - b - back to r.
uint32_t RainbowWords::Wheel(byte WheelPos) {
  WheelPos = 255 - WheelPos;
  if(WheelPos < 85) {
    return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
  }
  if(WheelPos < 170) {
    WheelPos -= 85;
    return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
  }
  WheelPos -= 170;
  return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
}

TimeWords:

// TimeWords.cpp
#include "TimeWords.h"

TimeWords::TimeWords(int clockPin, int latchPin, int dataPin) {
  CLOCK_PIN = clockPin;
  LATCH_PIN = latchPin;
  DATA_PIN = dataPin;
  return;
}

void TimeWords::updateAllTimeWords(DateTime time) {
  TimeWords::currentHour = time.hour();
  TimeWords::currentMinute = time.minute(); 
  
  // re-initialize to empty except first two words
  for (int i = 2; i < TimeWords::MAX_TIME_WORDS; i++) {
    TimeWords::currentTimeWords[i][0] = '\0'; // Set the first char to null
  }
  // always have IT IS
  strncpy(TimeWords::currentTimeWords[0], "IT", TimeWords::MAX_WORD_LENGTH);
  strncpy(TimeWords::currentTimeWords[1], "IS", TimeWords::MAX_WORD_LENGTH);

  // update all words
  TimeWords::updateHourWords(TimeWords::currentHour, TimeWords::currentMinute);
  TimeWords::updateMinuteWords(TimeWords::currentMinute);

  for (int i = 0; i < TimeWords::MAX_MINUTE_WORDS; i++) {
      strncpy(TimeWords::currentTimeWords[2 + i], TimeWords::currentMinuteWords[i], TimeWords::MAX_WORD_LENGTH);
  }
  for (int i = 0; i < TimeWords::MAX_HOUR_WORDS; i++) {
      strncpy(TimeWords::currentTimeWords[2 + TimeWords::MAX_MINUTE_WORDS + i], TimeWords::currentHourWords[i], TimeWords::MAX_WORD_LENGTH);
  }
  for (int i =0;i<TimeWords::MAX_TIME_WORDS;i++) {
    Serial.print(TimeWords::currentTimeWords[i]);
    Serial.print(F(" "));
  }
  Serial.println();
  TimeWords::updateClockDisplay();
}

void TimeWords::updateHourWords(int hour, int minute) {
  hour = hour%12;
  if (minute>32)
  {
    hour++;
  }
  if (hour==0)
  {
    hour=12;
  }
  if (hour==13)
  {
    hour=1;
  }
  TimeWords::currentHour = hour;
  switch (hour) {
      case 1:
        strncpy(TimeWords::currentHourWords[0], "ONE", MAX_WORD_LENGTH);
        break;
      case 2:
        strncpy(TimeWords::currentHourWords[0], "TWO", MAX_WORD_LENGTH);
        break;
      case 3:
        strncpy(TimeWords::currentHourWords[0], "THREE", MAX_WORD_LENGTH);
        break;
      case 4:
        strncpy(TimeWords::currentHourWords[0], "FOUR", MAX_WORD_LENGTH);
        break;
      case 5:
        strncpy(TimeWords::currentHourWords[0], "FIVE (hours)", MAX_WORD_LENGTH);
        break;
      case 6:
        strncpy(TimeWords::currentHourWords[0], "SIX", MAX_WORD_LENGTH);
        break;
      case 7:
        strncpy(TimeWords::currentHourWords[0], "SEVEN", MAX_WORD_LENGTH);
        break;
      case 8:
        strncpy(TimeWords::currentHourWords[0], "EIGHT", MAX_WORD_LENGTH);
        break;
      case 9:
        strncpy(TimeWords::currentHourWords[0], "NINE", MAX_WORD_LENGTH);
        break;
      case 10:
        strncpy(TimeWords::currentHourWords[0], "TEN (hours)", MAX_WORD_LENGTH);
        break;
      case 11:
        strncpy(TimeWords::currentHourWords[0], "ELEVEN", MAX_WORD_LENGTH);
        break;
      case 12:
        strncpy(TimeWords::currentHourWords[0], "TWELVE", MAX_WORD_LENGTH);
        break;
      default:
        TimeWords::currentHourWords[0][0] = '\0'; // Set to empty string
        break;
    }
    strncpy(TimeWords::currentHourWords[1], "OCLOCK", MAX_WORD_LENGTH);
}

void TimeWords::updateMinuteWords(int minute) {
  // re-initialize all to nothing.
  for (int i =0; i<MAX_MINUTE_WORDS; i++) {
    TimeWords::currentMinuteWords[i][0] = '\0';
  }
  minute = TimeWords::roundToNearest5(minute);
  if (minute==60) {
    minute=0;
  }
  TimeWords::currentMinute = minute;

switch (minute) {
      case 0:
        break;
      case 5:
        strncpy(TimeWords::currentMinuteWords[0], "FIVE (minutes)", MAX_WORD_LENGTH);
        strncpy(TimeWords::currentMinuteWords[1], "MINUTES", MAX_WORD_LENGTH);
        strncpy(TimeWords::currentMinuteWords[2], "PAST", MAX_WORD_LENGTH);
        break;
      case 10:
        strncpy(TimeWords::currentMinuteWords[0], "TEN (minutes)", MAX_WORD_LENGTH);
        strncpy(TimeWords::currentMinuteWords[1], "MINUTES", MAX_WORD_LENGTH);
        strncpy(TimeWords::currentMinuteWords[2], "PAST", MAX_WORD_LENGTH);
        break;
      case 15:
        strncpy(TimeWords::currentMinuteWords[0], "QUARTER", MAX_WORD_LENGTH);
        strncpy(TimeWords::currentMinuteWords[1], "PAST", MAX_WORD_LENGTH);
        break;
      case 20:
        strncpy(TimeWords::currentMinuteWords[0], "TWENTY", MAX_WORD_LENGTH);
        strncpy(TimeWords::currentMinuteWords[1], "MINUTES", MAX_WORD_LENGTH);
        strncpy(TimeWords::currentMinuteWords[2], "PAST", MAX_WORD_LENGTH);
        break;
      case 25:
        strncpy(TimeWords::currentMinuteWords[0], "TWENTY", MAX_WORD_LENGTH);
        strncpy(TimeWords::currentMinuteWords[1], "FIVE (minutes)", MAX_WORD_LENGTH);
        strncpy(TimeWords::currentMinuteWords[2], "MINUTES", MAX_WORD_LENGTH);
        strncpy(TimeWords::currentMinuteWords[3], "PAST", MAX_WORD_LENGTH);
        break;
      case 30:
        strncpy(TimeWords::currentMinuteWords[0], "HALF", MAX_WORD_LENGTH);
        strncpy(TimeWords::currentMinuteWords[1], "PAST", MAX_WORD_LENGTH);
        break;
      case 35:
        strncpy(TimeWords::currentMinuteWords[0], "TWENTY", MAX_WORD_LENGTH);
        strncpy(TimeWords::currentMinuteWords[1], "FIVE (minutes)", MAX_WORD_LENGTH);
        strncpy(TimeWords::currentMinuteWords[2], "MINUTES", MAX_WORD_LENGTH);
        strncpy(TimeWords::currentMinuteWords[3], "TO", MAX_WORD_LENGTH);
        break;
      case 40:
        strncpy(TimeWords::currentMinuteWords[0], "TWENTY", MAX_WORD_LENGTH);
        strncpy(TimeWords::currentMinuteWords[1], "MINUTES", MAX_WORD_LENGTH);
        strncpy(TimeWords::currentMinuteWords[2], "TO", MAX_WORD_LENGTH);
        break;
      case 45:
        strncpy(TimeWords::currentMinuteWords[0], "QUARTER", MAX_WORD_LENGTH);
        strncpy(TimeWords::currentMinuteWords[1], "TO", MAX_WORD_LENGTH);
        break;
      case 50:
        strncpy(TimeWords::currentMinuteWords[0], "TEN (minutes)", MAX_WORD_LENGTH);
        strncpy(TimeWords::currentMinuteWords[1], "MINUTES", MAX_WORD_LENGTH);
        strncpy(TimeWords::currentMinuteWords[2], "TO", MAX_WORD_LENGTH);
        break;
      case 55:
        strncpy(TimeWords::currentMinuteWords[0], "FIVE (minutes)", MAX_WORD_LENGTH);
        strncpy(TimeWords::currentMinuteWords[1], "MINUTES", MAX_WORD_LENGTH);
        strncpy(TimeWords::currentMinuteWords[2], "TO", MAX_WORD_LENGTH);
        break;
      default:
        strncpy(TimeWords::currentMinuteWords[0], "INVALID", MAX_WORD_LENGTH);
        break;
    }
}

int TimeWords::roundToNearest5(int n) {
    return ((n + 2) / 5) * 5;  // Add 2 before dividing by 5 to round to the nearest multiple of 5
}

uint32_t TimeWords::convertAllTimeWordsTo32BitData(char wordsToLight[MAX_TIME_WORDS][MAX_WORD_LENGTH]) {
  uint32_t wordTotal = 0x00000000;

  for (int i =0; i<8; i++) {
    wordTotal += TimeWords::convertTimeWordTo32BitData(wordsToLight[i]);
  }

  return wordTotal;
}

void TimeWords::updateClockDisplay() {
  TimeWords::wordsToIlluminate = TimeWords::convertAllTimeWordsTo32BitData(TimeWords::currentTimeWords);
  TimeWords::shiftOutData(TimeWords::wordsToIlluminate);
}

void TimeWords::lightUpOneWordAtATime() {
  const int TOTAL_WORDS = 23;
  char timeWordsArray[TOTAL_WORDS][MAX_WORD_LENGTH] = {
    "IT", "IS", "TWENTY", "QUARTER", "FIVE (minutes)", "TEN (minutes)", "MINUTES", "HALF", "PAST",
    "TO", "NINE", "FOUR", "THREE", "ONE", "TWO", "SEVEN", "EIGHT", "ELEVEN",
    "TEN (hours)", "FIVE (hours)", "TWELVE", "SIX", "OCLOCK"
  };
  uint32_t data;
  char word[MAX_WORD_LENGTH];
  
  for (int i =0; i<TOTAL_WORDS; i++) {
    strncpy(word,timeWordsArray[i],MAX_WORD_LENGTH);
    data = TimeWords::convertTimeWordTo32BitData(word);
    Serial.print("Word: ");
    Serial.println(word);
    // Serial.print(", 32 bit data: ");
    // Serial.println(data, HEX);
    TimeWords::shiftOutData(data);
    delay(2000);
  }

}

// String TimeWords::reverseString(String str) {
//   String reversedStr = "";
//   for (i = str.length() - 1; i >= 0; i--) {
//     reversedStr += str.charAt(i);
//   }
//   return reversedStr;
// }

// String TimeWords::intToBinaryString(int num) {
//   if (num == 0) {
//     return "00000000";
//   }

//   String binaryString = "";
//   unsigned int unsignedNum = static_cast<unsigned int>(num);
//   while (unsignedNum > 0) {
//     binaryString += (unsignedNum % 2 == 0) ? '0' : '1';
//     unsignedNum /= 2;
//   }
//   String reversedString = "";
//   for (i = binaryString.length() - 1; i >= 0; i--) {
//     reversedString += binaryString.charAt(i);
//   }
//   // Pad with leading zeros
//   while (reversedString.length() < 8) {
//     reversedString = "0" + reversedString;
//   }
//   return reversedString;
// }

// Function to shift out data of any length
void TimeWords::shiftOutData(uint32_t data) {
  // Latch the data (prepare to shift)
  digitalWrite(TimeWords::LATCH_PIN, LOW);  
  // Shift out each byte of the 32-bit data
  for (int i = 3; i >= 0; i--) {
    // Serial.print("Sending data for shift register #");
    // Serial.print(i);
    // Serial.print(" : decimal val: ");
    byte currentByte = (data >> (i * 8)) & 0xFF;  // Extract each byte from the 32-bit data
    // Serial.print(currentByte);
    // Serial.print(", binary val: ");
    // Serial.println(TimeWords::intToBinaryString(currentByte));
    shiftOut(TimeWords::DATA_PIN, TimeWords::CLOCK_PIN, LSBFIRST, currentByte);  // Send the byte
  }
  // Pulse the latch pin to update the shift registers
  digitalWrite(TimeWords::LATCH_PIN, HIGH);
  digitalWrite(TimeWords::LATCH_PIN, LOW); // Optional: pulse it low again to ensure proper latching
}

uint32_t TimeWords::convertTimeWordTo32BitData(char word[MAX_WORD_LENGTH]) {
  uint32_t data = 0;
   if (strcmp(word, "IT") == 0) {
            data = 0x40;
            data = data << (0 * 8);
        } else if (strcmp(word, "IS") == 0) {
            data = 0x20;
        } else if (strcmp(word, "TWENTY") == 0) {
            data = 0x10;
        } else if (strcmp(word, "QUARTER") == 0) {
            data = 0x08;
        } else if (strcmp(word, "FIVE (minutes)") == 0) {
            data = 0x04;
        } else if (strcmp(word, "TEN (minutes)") == 0) {
            data = 0x02;
        } else if (strcmp(word, "MINUTES") == 0) {
            data = 0x01;
        } else if (strcmp(word, "HALF") == 0) {
            data = 0x40;
            data = data << (1 * 8);
        } else if (strcmp(word, "PAST") == 0) {
            data = 0x20;
            data = data << (1 * 8);
        } else if (strcmp(word, "TO") == 0) {
            data = 0x10;
            data = data << (1 * 8);
        } else if (strcmp(word, "NINE") == 0) {
            data = 0x08;
            data = data << (1 * 8);
        } else if (strcmp(word, "FOUR") == 0) {
            data = 0x04;
            data = data << (1 * 8);
        } else if (strcmp(word, "THREE") == 0) {
            data = 0x02;
            data = data << (1 * 8);
        } else if (strcmp(word, "ONE") == 0) {
            data = 0x01;
            data = data << (1 * 8);
        } else if (strcmp(word, "TWO") == 0) {
            data = 0x40;
            data = data << (2 * 8);
        } else if (strcmp(word, "SEVEN") == 0) {
            data = 0x20;
            data = data << (2 * 8);
        } else if (strcmp(word, "EIGHT") == 0) {
            data = 0x10;
            data = data << (2 * 8);
        } else if (strcmp(word, "ELEVEN") == 0) {
            data = 0x08;
            data = data << (2 * 8);
        } else if (strcmp(word, "TEN (hours)") == 0) {
            data = 0x04;
            data = data << (2 * 8);
        } else if (strcmp(word, "FIVE (hours)") == 0) {
            data = 0x02;
            data = data << (2 * 8);
        } else if (strcmp(word, "TWELVE") == 0) {
            data = 0x01;
            data = data << (2 * 8);
        } else if (strcmp(word, "SIX") == 0) {
            data = 0x40;
            data = data << (3 * 8);
        } else if (strcmp(word, "OCLOCK") == 0) {
            data = 0x20;
            data = data << (3 * 8);
        }

        return data;
    }

Beyond my level of software debugging.

Thanks Jim, I still think it's hardware/noise related, since the software components were behaving as expected when running independently, and even when operating with a small number of RGB LEDs illuminated.

Well now that you fixed the I2C pins, why don't you try the extra pull-up again?

How much free memory ?

I'll post the exact numbers in a bit, but roughly 75% of the memory is used, leaving 700ish bytes for dynamic storage I think.

Exact numbers are here:

Sketch uses 11156 bytes (34%) of program storage space. Maximum is 32256 bytes.
Global variables use 1264 bytes (61%) of dynamic memory, leaving 784 bytes for local variables. Maximum is 2048 bytes.

I tried shielding and more aggressive pullup resistors on the SDA/SCL lines, then even more aggressive shielding, and the results were the same.

I measured the current out of my power supply and it's nowhere near the limit (at 0.5A).

I then unplugged everything but the RTC and the white LEDs (so no rainbow LEDs were plugged in), reran things, and saw the same problem. That pointed me toward a code issue.

After some testing to isolate which section of code was causing the month, day, hour, minute and second to get assigned to zero, I isolated it to this line:

RainbowWords::strip.setPixelColor(i, Wheel((i+j) & 255)*pixelOnOffStates[i]);

where

RainbowWords::strip = Adafruit_NeoPixel(PIXEL_COUNT, PIXEL_PIN, NEO_GRB + NEO_KHZ800);

and i is looping through the 84 rainbow LEDs, and j is looping through 255 colors.

After some additional refactoring and testing, I believe what's happening is that the memory chunk allocated to the neopixel strip, something like 3 bytes per LED, is overlapping with other variables, and so when I assign a pixel color of 0 (off) to a high-index-number LED in the array, I start losing my month, day, hour, minute and second variables (the memory block seems to gradually "eat" them, which explains why they iteratively become zero over a few loop iterations.

Some research suggests that the FastLED.h library is more memory-efficient than the Adafruit library, so I'll give that a shot to see if I can keep the same array on a smaller block of memory less likely to hammer an existing variable. Another alternative is for me to break the LED strip into a few sections and use separate pins for each of them. The theory is that allocating smaller blocks of memory are less likely to result in overlap, I guess? This is new territory for me.

I'm going to test some of these possibilities tomorrow, but have to call it a night now.

Thank you everyone who weighed in and helped me when I was incredibly stuck -- it really helped me to keep pushing through.

Well I think you have proven that it is NOT an EMI issue or power supply issue.

I confirmed the issue was related to the memory allocation for the Adafruit Neopixel 84-LED variable which occupies ~250 bytes. Setting the LEDs at high indices to zero was setting hour, minute, to get set to zero.

The solution was to switch to the FastLED library which is much more memory efficient and didn't produce the same issue.

Thank you everyone who weighed in and helped isolate and debug the issue when I was very discouraged. It was very helpful and motivating. It's my first time using a community forum like this and I'm grateful.

Here is a photo of the finished product!

2 Likes

WOW cool!

1 Like

Yes, indeed! Really cool.

1 Like

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