Smart Hoodie with 16x16 Matrix display. Odd memory issue... can't figure it out

Hi everyone. I made a change to my code resulting in what appears to be an unrelated error, so I am assuming I am encountering a memory allocation issue, but I have no idea why. Here's the story....

My 9 year old son conceived of a "smart hoodie" that he could wear, and that had a display screen built into the front. He wanted it to be able to display his school name, twinkle some lights, play rock paper scissors, and answer yes or no to a question. I got all this working. I wrote a function CheerText to display text in "cheer" format, where one letter is displayed at a time like cheerleaders might call them out. That function takes a color, some text, and a speed (for the delay between letters) as input, and then displays the resultant cheer. I also created a Twinkle routine to twinkle 20 LEDs at a time. When I showed it to my son, one of his pieces of feedback is that he wanted more LEDs to twinkle at a time. So I upped the number to 50. The weird thing is that once I did that, the Twinkle() routine DID show 50 LEDs twinkling instead of 20, BUT the CheerText() routine appears to get skipped, and there are some random LEDs that get lit up instead. But I literally changed nothing else. My code is pasted below. I'm using an adafruit Flora with an adafruit 16x16 neopixel matrix, and I have a button wired up for control. The matrix is separately powered by a 9v battery connected through a UBEC DC/DC Step-Down (Buck) Converter (also from adafruit). Whenever I change MAXSTARS to 50, and then use the array initialization for the 50 sized array, the CheerText routine craps out. If I change it back to 20, everything works as intended. This one has me stumped. Here's my code:

#include <gfxfont.h>
#include <Adafruit_NeoPixel.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SPITFT.h>
#include <Adafruit_SPITFT_Macros.h>
#include <Adafruit_NeoMatrix.h>
#include <gamma.h>

// NeoPixel Information
#define MATRIXPIN 6     // pin the NeoPixel Matrix is connected to
#define LEDPIN 7        // pin for the on-board LED on the Flora
#define PIXELPIN 8      // pin for the on-board single NeoPixel on the Flora
#define NUMPIXELS 256
#define GRID_COLS 16
#define GRID_ROWS 16

#define MAXSTARS 20    // set to number of desired stars to appear at once in Twinkle routine below
#define DEFBRIGHTNESS 25  // Default brightness level unless otherwise specified.

Adafruit_NeoPixel thePixel(1, PIXELPIN, NEO_GRB + NEO_KHZ800);
Adafruit_NeoMatrix matrix = Adafruit_NeoMatrix(GRID_COLS, GRID_ROWS, MATRIXPIN,
  NEO_MATRIX_BOTTOM    + NEO_MATRIX_RIGHT +
  NEO_MATRIX_COLUMNS   + NEO_MATRIX_ZIGZAG,
  NEO_GRB           + NEO_KHZ800);

#define OFF matrix.Color(0, 0, 0)
#define BLUE matrix.Color(0, 0, 255)
#define GREEN matrix.Color(0, 255, 0)
#define RED matrix.Color(255, 0, 0)
#define GREY matrix.Color(128, 15, 0)
#define WHITE matrix.Color(255, 255, 255)
#define CYAN matrix.Color(0, 255, 255)
#define PURPLE matrix.Color(255, 0, 255)
#define YELLOW matrix.Color(255, 255, 0)
#define ORANGE matrix.Color(255, 165, 0)

// global constants
int mode = 0;
int buttonPin = 10;         // pin the bushbutton is connected to
const int maxMode = 5;      // set to the max mode number coded below
int buttonState = 0;        // variable for reading the pushbutton status
int offset = 0;             // scrolling offset placeholder

/*****************************************************************************************
This next section was copied from here for the flame animation:
https://github.com/mic159/NeoFire/blob/master/NeoFire.ino
*****************************************************************************************/

//these values are substracetd from the generated values to give a shape to the animation
const unsigned char valueMask[GRID_ROWS][GRID_COLS]={
    {16 , 0  , 0  , 0  , 0  , 0  , 0  , 16 , 16 , 0  , 0  , 0  , 0  , 0  , 0  , 16 },
    {32 , 0  , 0  , 0  , 0  , 0  , 0  , 32 , 32 , 0  , 0  , 0  , 0  , 0  , 0  , 32 },
    {48 , 0  , 0  , 0  , 0  , 0  , 0  , 48 , 48 , 0  , 0  , 0  , 0  , 0  , 0  , 48 },
    {64 , 8  , 0  , 0  , 0  , 0  , 8  , 64 , 64 , 8  , 0  , 0  , 0  , 0  , 8  , 64 },
    {80 , 16 , 0  , 0  , 0  , 0  , 16 , 80 , 80 , 16 , 0  , 0  , 0  , 0  , 16 , 80 },
    {96 , 32 , 8  , 0  , 0  , 8  , 32 , 96 , 96 , 32 , 8  , 0  , 0  , 8  , 32 , 96 },
    {112, 64 , 16 , 0  , 0  , 16 , 64 , 112, 112, 64 , 16 , 0  , 0  , 16 , 64 , 112},
    {128, 80 , 32 , 8  , 8  , 32 , 80 , 128, 128, 80 , 32 , 8  , 8  , 32 , 80 , 128},
    {144, 96 , 48 , 16 , 16 , 48 , 96 , 144, 144, 96 , 48 , 16 , 16 , 48 , 96 , 144},
    {160, 112, 64 , 32 , 32 , 64 , 112, 160, 160, 112, 64 , 32 , 32 , 64 , 112, 160},
    {176, 128, 80 , 48 , 48 , 80 , 128, 176, 176, 128, 80 , 48 , 48 , 80 , 128, 176},
    {192, 144, 96 , 64 , 64 , 96 , 144, 192, 192, 144, 96 , 64 , 64 , 96 , 144, 192},
    {208, 160, 112, 80 , 80 , 112, 160, 208, 208, 160, 112, 80 , 80 , 112, 160, 208},
    {224, 176, 128, 96 , 96 , 128, 176, 224, 224, 176, 128, 96 , 96 , 128, 176, 224},
    {255, 192, 144, 112, 112, 144, 192, 255, 255, 192, 144, 112, 112, 144, 192, 255},
    {255, 208, 160, 128, 128, 160, 208, 255, 255, 192, 160, 128, 128, 160, 208, 255}
};

//these are the hues for the fire, 
//should be between 0 (red) to about 25 (yellow)
const unsigned char hueMask[GRID_ROWS][GRID_COLS]={
    {1 , 11, 19, 25, 25, 22, 11, 1 , 1 , 11, 19, 25, 25, 22, 11, 1 },
    {1 , 11, 19, 25, 25, 22, 11, 1 , 1 , 11, 19, 25, 25, 22, 11, 1 },
    {1 , 8 , 13, 19, 25, 19, 8 , 1 , 1 , 8 , 13, 19, 25, 19, 8 , 1 },
    {1 , 8 , 13, 19, 25, 19, 8 , 1 , 1 , 8 , 13, 19, 25, 19, 8 , 1 },
    {1 , 8 , 13, 16, 19, 16, 8 , 1 , 1 , 8 , 13, 16, 19, 16, 8 , 1 },
    {1 , 8 , 13, 16, 19, 16, 8 , 1 , 1 , 8 , 13, 16, 19, 16, 8 , 1 },
    {1 , 5 , 11, 13, 13, 13, 5 , 1 , 1 , 5 , 11, 13, 13, 13, 5 , 1 },
    {1 , 5 , 11, 13, 13, 13, 5 , 1 , 1 , 5 , 11, 13, 13, 13, 5 , 1 },
    {1 , 5 , 11, 11, 11, 11, 5 , 1 , 1 , 5 , 11, 11, 11, 11, 5 , 1 },
    {1 , 5 , 11, 11, 11, 11, 5 , 1 , 1 , 5 , 11, 11, 11, 11, 5 , 1 },
    {0 , 1 , 5 , 8 , 8 , 5 , 1 , 0 , 0 , 1 , 5 , 8 , 8 , 5 , 1 , 0 },
    {0 , 1 , 5 , 8 , 8 , 5 , 1 , 0 , 0 , 1 , 5 , 8 , 8 , 5 , 1 , 0 },
    {0 , 0 , 1 , 5 , 5 , 1 , 0 , 0 , 0 , 0 , 1 , 5 , 5 , 1 , 0 , 0 },
    {0 , 0 , 1 , 5 , 5 , 1 , 0 , 0 , 0 , 0 , 1 , 5 , 5 , 1 , 0 , 0 },
    {0 , 0 , 0 , 1 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 1 , 1 , 0 , 0 , 0 },
    {0 , 0 , 0 , 1 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 1 , 1 , 0 , 0 , 0 }
};

unsigned char matrixValue[GRID_ROWS][GRID_COLS];
unsigned char line[GRID_COLS];
int pcnt = 0;

//Converts an HSV color to RGB color
uint16_t HSVtoRGB(uint8_t ih, uint8_t is, uint8_t iv) {
  float r, g, b, h, s, v; //this function works with floats between 0 and 1
  float f, p, q, t;
  int i;

  h = (float)(ih / 256.0);
  s = (float)(is / 256.0);
  v = (float)(iv / 256.0);

  //if saturation is 0, the color is a shade of grey
  if(s == 0.0) {
    b = v;
    g = b;
    r = g;
  }
  //if saturation > 0, more complex calculations are needed
  else
  {
    h *= 6.0; //to bring hue to a number between 0 and 6, better for the calculations
    i = (int)(floor(h)); //e.g. 2.7 becomes 2 and 3.01 becomes 3 or 4.9999 becomes 4
    f = h - i;//the fractional part of h

    p = (float)(v * (1.0 - s));
    q = (float)(v * (1.0 - (s * f)));
    t = (float)(v * (1.0 - (s * (1.0 - f))));

    switch(i)
    {
      case 0: r=v; g=t; b=p; break;
      case 1: r=q; g=v; b=p; break;
      case 2: r=p; g=v; b=t; break;
      case 3: r=p; g=q; b=v; break;
      case 4: r=t; g=p; b=v; break;
      case 5: r=v; g=p; b=q; break;
      default: r = g = b = 0; break;
    }
  }
  return matrix.Color(r * 255.0, g * 255.0, b * 255.0);
}

/**
 * Randomly generate the next line (matrix row)
 */
void generateLine(){
  for(uint8_t x=0; x<GRID_COLS; x++) {
    line[x] = random(64, 255);
  }
}

/**
 * shift all values in the matrix up one row - Original version.
 */
void shiftUp() {
  for (uint8_t y=GRID_ROWS-1; y>0; y--) {
    for (uint8_t x=0; x<GRID_COLS; x++) {
      matrixValue[y][x] = matrixValue[y-1][x];
    }
  }
  
  for (uint8_t x=0; x<GRID_COLS; x++) {
    matrixValue[0][x] = line[x];
  }
}

/**
 * draw a frame, interpolating between 2 "key frames"
 * @param pcnt percentage of interpolation
 */
void drawFrame(int pcnt) {
  int nextv;
  
  //each row interpolates with the one before it
  for (unsigned char y=GRID_ROWS-1; y>0; y--) {   // original
//  for (unsigned char y=0; y<GRID_ROWS-1; y++) {     // flipped vertically
    for (unsigned char x=0; x<GRID_COLS; x++) {     // original
//    for (unsigned char x=GRID_COLS-1; x>=0; x--) {       // flipped forizontally
      nextv = 
          (((100.0-pcnt)*matrixValue[y][x] 
        + pcnt*matrixValue[y-1][x])/100.0) 
        - valueMask[y][x];
      uint16_t color = HSVtoRGB(
        hueMask[y][x], // H
        255, // S
        (uint8_t)max(0, nextv) // V
      );

      //matrix.drawPixel(x, y, color);      
      matrix.drawPixel(x, GRID_ROWS-1-y, color);
    }
  }
  
  //first row interpolates with the "next" line
  for(unsigned char x=0; x<GRID_COLS; x++) {
    uint16_t color = HSVtoRGB(
      hueMask[0][x], // H
      255,           // S
      (uint8_t)(((100.0-pcnt)*matrixValue[0][x] + pcnt*line[x])/100.0) // V
    );
//    matrix.drawPixel(x, 0, color);
    matrix.drawPixel(x, GRID_ROWS-1, color);
  }
}

/************************************************************************************
CheerText - This routine will print one letter at a time in the received text using 
the received color.  I plan on adding a third input defining the speed or time to 
delay on each letter, but that hasn't been implemented yet
************************************************************************************/
void CheerText(String myText, unsigned int color, int speed) {
  Serial.println("Starting CheerText.");
  matrix.setTextSize(2);
  int   ArrayLength=myText.length()+1;    //The +1 is for the 0x00h Terminator
  char  CharArray[ArrayLength];
  myText.toCharArray(CharArray,ArrayLength);
  matrix.setTextColor(color);

  for (int i=0; i<ArrayLength-1; i++){
    matrix.fillScreen(0);
    matrix.show();
    matrix.setCursor(3,1);
    matrix.print(CharArray[i]);
    matrix.show();
    delay(speed);
  }
  //matrix.setTextSize(1);
  //Serial.println("Leaving CheerText.");
}

/************************************************************************************
Twinkle - This routine will twinkle random colors on randomly selected NeoPixels in 
the matrix, up to MAXSTARS at a time, where MAXSTARS is defined above.
************************************************************************************/
void Twinkle() {
  Serial.println("Starting Twinkle.");

  // MAXSTARS = 20
  int starArray[MAXSTARS][2] = {{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}};

  // MAXSTARS = 50
  /*
  int starArray[MAXSTARS][2] = {
    {0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
    {0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
    {0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
    {0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
    {0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}
  };
  */

  int arrayIndex=0;
  matrix.fillScreen(0);
  matrix.show();
  
  // read the state of the button:
  // buttonState = digitalRead(buttonPin);   //commented out for testing
  buttonState = digitalRead(buttonPin); // initial button read
      
  // until the button is pressed, add a star and remove a star each iteration, with a short delay.
  while (buttonState == HIGH) {
    matrix.drawPixel(starArray[arrayIndex][0], starArray[arrayIndex][1], 0);   // black out old X,Y pixed
    starArray[arrayIndex][0]=random(1,GRID_COLS+1);     // set new X coordinate
    starArray[arrayIndex][1]=random(1,GRID_ROWS+1);     // set new Y coordinate
    matrix.drawPixel(starArray[arrayIndex][0], starArray[arrayIndex][1], random(1,65535));   // draw new pixel in random color
    matrix.show();
    delay(100);
    // increment to next position in array
    arrayIndex++;
    if (arrayIndex >= MAXSTARS) {
      arrayIndex=0;
    }
    // read the state of the button:
    buttonState = digitalRead(buttonPin); // commented out for testing
  }

  mode = 0;
  matrix.fillScreen(0);   // clear screen when done
  matrix.show();
  delay(500);
  Serial.println("Leaving Twinkle.");

}

/************************************************************************************
YesOrNo - This routine randomly selects yes or no, and outputs an indication of 
the result
************************************************************************************/
void YesOrNo() {
  Serial.println("Starting YesNo.");
 
  int decision = random(0,2);

  matrix.setTextSize(2);
  matrix.fillScreen(0);
  matrix.show();
  matrix.setCursor(3,1);

  switch (decision) {
  case 0:   // Yes
    matrix.setTextColor(GREEN);
    matrix.print(F("!"));
    matrix.show();
    break;
  case 1:   // no
    matrix.setTextColor(RED);
    matrix.print(F("X"));
    matrix.show();
    break;
  default:  // error
    CheerText("?", WHITE, 1000);
    break;
  }

  delay(3000);
  matrix.fillScreen(0);
  matrix.show();

  Serial.println("Leaving YesNo.");
}

/************************************************************************************
FireIce - This routine makes an icy fireplace of BlueFlame- to be written
************************************************************************************/
void FireIce() {
  if (pcnt >= 100) {
    shiftUp();
    generateLine();
    pcnt = 0;
  }
  drawFrame(pcnt);
  matrix.show();
  pcnt+=30;
}

/************************************************************************************
RockPaperScissors - This routine randomly selects either Rock, Paper, or Scissors, 
and displays an image of the selection
************************************************************************************/
void RockPaperScissors() {
  int choice;
  
  // read the state of the button:
  buttonState = digitalRead(buttonPin); // initial button read
      
  // until the button is pressed, add a star and remove a star each iteration, with a short delay.
  while (buttonState == HIGH) {
    choice = random(1,4);
    matrix.fillScreen(0);
    matrix.show();
    Serial.println("RPS selection: " + String(choice));
    matrix.setCursor(3,3);
    matrix.setTextSize(1);
    matrix.print("Go");
    matrix.show();
    delay(500);
    CheerText("123", YELLOW, 600);
    matrix.fillScreen(0);
    matrix.show();
    delay(100);

    switch (choice) {
      case 1:           // Rock
        matrix.drawCircle(7, 7, 7, YELLOW);
        matrix.drawCircle(4,4,2,YELLOW);
        break;
      case 2:           // Paper
        matrix.drawRect(2, 0, 12, 16, YELLOW);
        matrix.drawFastHLine(4,3,8,YELLOW);
        matrix.drawFastHLine(4,6,8,YELLOW);
        matrix.drawFastHLine(4,9,8,YELLOW);
        matrix.drawFastHLine(4,12,8,YELLOW);
        break;
      case 3:           // Scissors
        matrix.drawLine(0,3,15,12,YELLOW);
        matrix.drawLine(0,12,15,3,YELLOW);
        matrix.drawCircle(2,2,2,YELLOW);
        matrix.drawCircle(2,13,2,YELLOW);
        break;
      default:
        break;
    }

    matrix.show();
    delay(2000);
    matrix.fillScreen(0);
    matrix.show();
    buttonState = digitalRead(buttonPin);
  }
}

/***************************************************************************************
Setup - Executed Once
***************************************************************************************/
void setup() {
  Serial.begin(9600);
  pinMode(buttonPin, INPUT_PULLUP);
  randomSeed(analogRead(12));

  thePixel.setBrightness(50);
  thePixel.begin();
  thePixel.setPixelColor(0, 255, 255, 255);   // pixel number, then RGB values
  thePixel.show(); // Initialize the onboard neopixel to off

  matrix.begin();
  matrix.setBrightness(DEFBRIGHTNESS);
  matrix.setTextWrap(false);
  matrix.setTextColor(WHITE);
  matrix.setTextSize(1);
  matrix.fillScreen(0);
  matrix.show();
  matrix.setCursor(2,3);
  matrix.print(F("ON"));
  matrix.show();
  delay(1000);
  matrix.fillScreen(0);
  matrix.show();

  // Some setup stuff for the flame animation
  randomSeed(analogRead(0));
  generateLine();
  memset(matrixValue, 0, sizeof(matrixValue));    //init all pixels to zero

  Serial.println("Setup Complete.");
  delay(100);
}

/***************************************************************************************
Main Loop - Executed repeatedly until system reset or turned off.
***************************************************************************************/
void loop() {
  
  // ***CHECK AND GET INPUT***

  // read the state of the button:
  buttonState = digitalRead(buttonPin);
  Serial.print("Button state: ");
  Serial.println(buttonState);

  // if the pushbutton is pressed (buttonState is LOW, because using a pull-up input), change modes.
  while (buttonState == LOW) {
    // Turn on LED to indicate button push
    digitalWrite(LEDPIN, HIGH);
    mode++;  // increment to next mode
    if (mode > maxMode) mode = 0;   // cycle back to first mode when max mode is reached.
    
    matrix.setTextSize(1);
    matrix.fillScreen(0);
    matrix.show();

    switch (mode) {
      case 0:
        matrix.setCursor(0,4);
        matrix.setTextColor(BLUE);
        matrix.print(F("O"));
        matrix.setCursor(5,4);
        matrix.print(F("f"));
        matrix.setCursor(10,4);
        matrix.print(F("f"));
        matrix.show();
        thePixel.setPixelColor(0, 0, 0, 0); // pixel number, then RGB values
        thePixel.show();
        break;
      case 1:
        matrix.setCursor(5,4);
        matrix.setTextColor(ORANGE);
        matrix.print(F("P"));
        matrix.show();
        thePixel.setPixelColor(0, 0, 0, 255);   // pixel number, then RGB values
        thePixel.show();
        break;
      case 2:
        matrix.setCursor(2,4);
        matrix.setTextColor(GREEN);
        matrix.print(F("YN"));
        matrix.show();
        thePixel.setPixelColor(0, 255, 165, 0); // pixel number, then RGB values
        thePixel.show();
        break;
      case 3:
        matrix.setCursor(5,4);
        matrix.setTextColor(PURPLE);
        matrix.print(F("*"));
        matrix.show();
        thePixel.setPixelColor(0, 255, 0, 255); // pixel number, then RGB values
        thePixel.show(); 
        break;
      case 4:
        matrix.setCursor(2,4);
        matrix.setTextColor(RED);
        matrix.print(F("^^"));
        matrix.show();
        thePixel.setPixelColor(0, 255, 0, 0); // pixel number, then RGB values
        thePixel.show();
        break;
      case 5:
        matrix.drawCircle(2,7,2,YELLOW);
        matrix.drawRect(6, 4, 4, 7, YELLOW);
        matrix.setTextColor(YELLOW);
        matrix.setCursor(11,3);
        matrix.print(F("x"));
        matrix.show();
        thePixel.setPixelColor(0, 255, 255, 0); // pixel number, then RGB values
        thePixel.show();
      default:
        break;
    } 
    delay(1000);
    matrix.fillScreen(0);
    matrix.show();
    buttonState = digitalRead(buttonPin);     // check to see if button still pressed
  }

  digitalWrite(LEDPIN, LOW);      // turn off LED once button is let go

  // ***DO THE THING BASED ON CURRENT MODE***

  Serial.println("Starting mode " + String(mode));

  // do something based on the current mode
  switch (mode) {
    case 0:   // Screen Off
      thePixel.setPixelColor(0, 0, 0, 0); // pixel number, then RGB values
      thePixel.show();
      matrix.fill(0);
      matrix.show();
      delay(500);
      break;
    case 1:   // POTOMAC Cheer mode
      CheerText("POTOMAC",BLUE, 900);
      matrix.setTextSize(1);
      matrix.setBrightness(100);
      for (offset=15; offset > -70; offset--) {
        matrix.fillScreen(0);
        matrix.setCursor(offset, 3);
        matrix.print("GO POTOMAC!");
        matrix.show();
        delay(50);
      }
      matrix.setBrightness(DEFBRIGHTNESS);
  matrix.show();
  delay(500);
      mode=0;
      break;
    case 2:   // yes-no mode
      CheerText("321", PURPLE, 750);
      delay(400);
      YesOrNo();
      mode=0;
      break;
    case 3:   // Twinkle
      Twinkle();
      break;
    case 4:     // Fire and Ice
      FireIce(); 
      break;
    case 5:     // rock-paper-scissors
      RockPaperScissors();
      break;
    default:
      break;
  }

  Serial.println();
}

/***************************END*********************************/

Any help appreciated.

Here’s the hoodie, for reference:

That would need scrolling. A 16x16 will only hold two, tall, characters.

"mode" never changes from "0" - I think your code resets it.

Reduce this until you gain back what you lost.

Post your compile results (memory usage, et c.) here.

You did not set pinMode() of your output pins.

The Adafruit Flora that I found on the web uses a 32U4. Compiling your sketch for a Leonardo (also 32U4) gives me the following results

Sketch uses 21344 bytes (74%) of program storage space. Maximum is 28672 bytes.
Global variables use 1427 bytes (55%) of dynamic memory, leaving 1133 bytes for local variables. Maximum is 2560 bytes.

That excludes the memory needed for the Neopixels (256x3). You might be skating on thin ice; you can add a function to print the free memory and call that in strategic places to observe if you're anywhere running low or out of memory. See https://docs.arduino.cc/learn/programming/memory-guide/#sram-memory-measurement.

Below some general tips to reduce memory usage.

There is no reason to concatenate String (capital S) objects for Serial prints. E.g. the below

    Serial.println("RPS selection: " + String(choice));

can be replaced by

    Serial.print("RPS selection: ");
    Serial.println(choice);

It prevents the incorrect use of concatenation. Using + for concatenation creates a temporary String object wasting memory.

When you call void CheerText(String myText, unsigned int color, int speed), a full copy of the String object is placed on the stack wasting memory again.
If you use a reference, only two bytes are placed on the stack; note the use of the &in below.

void CheerText(String &myText, unsigned int color, int speed)
{
...
...
}

I further don't see a reason in your current sketch (but I might have missed it) to use a String object for the above function.

void CheerText(char *myText, unsigned int color, int speed)

will achieve the same and will save you the conversion to a char array. And your CharArray variable is not needed if you use the c_str() method which will give you a pointer to the actual text in the String object.

To save some more memory, use the F-macro() when printing; you already use it in a few places, just be more consistent. E.g. replace Serial.println("Starting CheerText."); by Serial.println(F("Starting CheerText."));

Lastly, move your valueMask and hueMask variables to progmem.

Note
Compared to the classic c-strings (character arrays terminated with a '\0'), String objects waste 6 bytes per object. But I admnit that String objects can be convenient.

Yeah, I scroll the name in the main loop. So the CheerText does one letter at a time, then I scroll text after that.

I set pinMode in setup() for the button pin. The matrix is defined elsewhere so I didn't think I needed to set that one???

This is incredibly helpful, thanks. I'm still new-ish to arduino, and I've never had to really deal with memory usage before. I'll give these a try and report back how it goes.

The lone LED on pin 7 (or is that a neopixel, too?)

Oh, right. I started using the on-board LED, but then pivoted to relying on the on-board NeoPixel on pin 8 instead, so I overlooked the LED pinMode. Thanks for catching that.

I helped another project with a scrolling cheer panel (32 x 8). Just showing for an alternate idea.

Thanks all for your help. I added F-macro's for all text Serial prints. I used separate lines for serial.print's rather than concatenation, and I moved the masks to PROGMEM (that was new to me). That freed up enough memory so that I can print 50 stars, and my CheerText() calls still work. I didn't mess with the strings being passed to CheerText because the other stuff did the trick, and I figure that at that point, if it ain't broke, don't fix it (any further). Thanks again all. Much appreciated.

I'm curious, are the LEDs covered with a fabric panel?

No. I glued them to a piece of t-shirt, then glued that behind the hoodie. The hoodie is just an $18 hoodie off amazon.

And I cut a little hole to feed the cable into the pocket to connect to the Flora and hold the batteries.

Thanks, I might want to try that.

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