Wierd problem in a simple sketch.

This sketch is simply to play with parameters for an LCD colour screen (Nokia 6100) while I get used to Arduino C++ on the mega328.
The sketch will, on command from Serial input, write up to 8 lines of text to the screen as well as change colours and contrast.
loop() writes a buffer to the screen, waits for a delay time (typically 1 second), then checks for Serial input and repeats.
The code is:

/*
   Colour_LCD_Display_Test_1
 Created: Oct 15, 2011
 Last modified: Oct 19, 2011
 PeteC
 
 *** Initial purpose:
 Display text on the display.
 
 *** Hardware:
 LCD Colour 132 x 132 Shield with Epson controller.
 Pins D8, D9, D11 and D13 are used for the display.
 Pins D3, D4, D5 are utilized for onboard switch input. If the switches are not available
 to the user, these pins may be used for other signals.
 
 *** Software:
 To adjust parameters on the fly, the program accepts commands from
 the serial input using a leading 1-character key to identify the
 parameter.
 'd' - Set the overall display colour as a 3 digit hex number.
 'b' - Set the character background colour as a 3 digit hex number.
 'f' - Set the character foreground colour as a 3 digit hex number.
 'c' - Set the contrast as a decimal number between 0 and 63.
 'x' - Set the horizontal starting position of the first line as a decimal number between 0 and 127.
 'y' - Set the vertical starting position of the first line as a decimal number between 0 and 127.
 's' - Set the line spacing as a decimal number between 0 and 63.
 '0' to '7' - Set a string to go into line n (n = 0 to 7).
 
 Note that all lines must end with a carriage return - select from the popup in the momitor window.
 */

//	Included files
//	External Component Libs 
#include "LCD_driver.h"
#include <MemoryFree.h>


#define maxLineLength 17
#define maxNumberLines 8

int contrast = 40;      // Initial value for contrast.
/*
  'x' & 'y' will be used in the traditional sense but
 note that they are reversed in this implementation.
 Ie., in LCDPutStr(&string, X, Y, ... 'X' defines the vertical
 position of the line and 'Y' defines the starting point in
 the horizontal direction.
 
 */
int x = 0;
int y = 0;
int s = 15;            // Initial value for line spacing.
/*
  The foreground colour is the colour of the characters.
 The background colour is the colour of the space within the characters.
 The clear colour is the colour of the screen before the text appears; it
 will also be the colour left around text that does not fully fill the screen.
 In general, it is probably best to have clearColour = bColour but could be
 useful to have contrasting clear and backgound colours to draw attention to
 a special message.
 */
int fColour = 0xFFF;  // Initial value for foreground colour.
int bColour = 0;      // Initial value for background colour.
int clearColour = 0;  // Initial value for clear screen colour.
// This is set to initialize items that have to be in loop() because of scope.
boolean starting = true;
int startCount = 4;
int maxNumberChars = maxNumberLines * maxLineLength;
boolean debug = true;
byte mistakeValue;
long timeOfMistake;
unsigned char testMistake = 'x';

void setup() {
  ioinit();    // Initialize LCD I/O.
  LCDInit();    // Initialize the LCD.
  Serial.begin(9600);
  Serial.println("Starting ...");
  Serial.println(maxNumberChars, DEC);
    Serial.print("Available RAM1 = ");
    Serial.println(freeMemory());
}

void loop() {
unsigned char text[maxNumberLines * maxLineLength];  // Create storage for text.
  int i;          // Use i and j for loop counting.
  int j;
  Serial.println(millis()/1000, DEC);  // Print the time since starting.
  delay(300);
  if (starting) {  // Prefill the text on initial entry.
    for (i=0; i<maxNumberChars; i++) text[i] = 'x';
    for (i=0; i<maxNumberLines; i++) text[maxLineLength * i + maxLineLength - 1] = 0;
    starting = false;
  }
  if (startCount-- > 0) {
    Serial.print("Available RAM2 = ");
    Serial.println(freeMemory());
  }
  
  LCDContrast(contrast);  // Set the contrast.
  LCDClear(clearColour);  // Set the screen colour.
  int yLine = y;          // yLine is the vertical position of the next line.
  for (i=0; i<maxNumberLines; i++) {  // Put text to screen.
    LCDPutStr(&text[i * maxLineLength], yLine, x, fColour, bColour);
    //LCDPutStr("1234567890123456", yLine, x, fColour, bColour);
    yLine += s;
  }
  if (text[134] != testMistake) {
    if (debug) {
      debug = false;
      timeOfMistake = millis()/1000;
      mistakeValue = text[134];
    }
    Serial.print("Mistake is: ");
    Serial.print(mistakeValue, HEX);
    Serial.print(" at: ");
    Serial.println(timeOfMistake, DEC);
     Serial.print("Available RAM3 = ");
    Serial.println(freeMemory());
 }
  delay(10);    // Delay for 1 second.
 /*  The rest of this sketch is used only to read commands sent from the monitor.
   The first character of input is the 'key', identifying the command as
   listed in the table above.
   There are three types of input expected, depending on the command: decimal
   numbers for four commands, hex numbers for three commands and text for one
   command. 'conversionType' is set according to the 'key' value and is used
   in a switch statement to process incoming characters. When the end of input
   (carriage return) is received, 'conversionType' is incremented by 3 to use
   the switch statement to store the data into the appropriate parameter.
   In the case of text input, the line is collected in a small array and
   transfered into the display 'text' array when the end of line is reached.
   */
  byte key = 0;  // 'key' is used 
  boolean validInput = true;
  boolean processIncoming;
  int conversionType;
  int newNumber = 0;
  int textIndex = 0;
  int textLineNumber;
  unsigned char textLine[maxLineLength];
  for (i=0; i<maxLineLength; i++) textLine[i] = 0;
  while (Serial.available() > 0) {
    processIncoming = true;
    unsigned char incoming = Serial.read();  // Read the next character.
    if (key == 0) {
      processIncoming = false;
      //      Serial.println("Setting key");
      key = incoming;
      if ((key == 'd') || (key == 'b') || (key == 'f')) {
        conversionType = 0;
      } 
      else if ((key == 'c') || (key == 'x') || (key == 'y') || (key == 's')) {
        conversionType = 1;
      } 
      else if ((key >= '0') && (key <= '7')) {
        conversionType = 2;
        textLineNumber = key - '0';
        for (j=0; j<maxLineLength; j++) textLine[j] = 0;
      } 
      else validInput = false;
    } 
    else if (incoming == 13) conversionType += 3;
    if (validInput && processIncoming) {
      switch (conversionType) {
      case 0:  // Hex colour input.
        if (incoming >= 'a') incoming -= 'a' - 'A';
        if (incoming > '9') incoming -= 'A' - '9' - 1;
        if ((incoming < '0') || (incoming > '9' + 6)) validInput = false;
        newNumber = newNumber * 16 + incoming - '0';
        break;
      case 1:
        if ((incoming < '0') || (incoming > '9')) validInput = false;
        newNumber = newNumber * 10 + incoming - '0';
        break;
      case 2:
        if (incoming == '`') incoming = 127;
        if (incoming == '~') incoming = 128;
        if (incoming == '|') incoming = 129;
        if (textIndex < 16) textLine[textIndex++] = incoming;
        break;
      case 3:
        if (key == 'd') clearColour = newNumber & 0xFFF;
        else if (key == 'b') bColour = newNumber & 0x0FFF;
        else fColour = newNumber & 0x0FFF;
        break;
      case 4:
        if (key == 'c') contrast = newNumber & 0x3F;
        else if (key == 'x') x = newNumber & 0xFFF;
        else if (key == 'y') y = newNumber & 0xFFF;
        else s = newNumber & 0x3F;
        break;
      case 5:
        for(i=0; i<maxLineLength; i++)
          text[textLineNumber * maxLineLength + i] = textLine[i];
        if (textLineNumber == 7) testMistake = textLine[15];
        break;
      default:
        break;
      }
    }
  }
}

The problem is that after looping for a time, the last few characters of the buffer get mashed. For any given version of the sketch, the time until this happens is constant but changing anything in the program will change the time from start to mash.

When I say ‘mashed’ I mean that anywhere from 3 to about a dozen characters get overwritten.

For instance, as shown, the delay is 0.01 seconds - time to mash is 704 seconds. if delay is 0.001, time to mash is 57 seconds; at 1 second time to mash is 688 seconds.
It doesn’t matter if I change parameters or text.

Now, if I move the declaration of “text” from loop() to global scope (before setup()), the sketch works forever, at least more than a day, with no problem.

I have been playing with this for a few days so there are things in there that don’t need to be, some of the comments no longer make sense and the whole thing is a bit awkward.

I have moved on to write more useful software and this sketch will go on the shelf as soon as I solve this problem which bugs me because I don’t understand it.

Can anyone suggest a reason for this strange behaviour?

Now, if I move the declaration of "text" from loop() to global scope (before setup()), the sketch works forever, at least more than a day, with no problem.

You get a new copy of text on every iteration of loop, when the scope is local to loop. You have cope that properly initializes that array on the first iteration of loop, but not on subsequent iterations. Why not?

Declaring the array at global scope initializes it (to all NULLS). Declaring it at local scope does not.

I don't need to initialize it after the beginning - the text remains constant at 128 'x's unless I enter new text via Serial. It shouldn't initialize it at all while going around the loop.

I agree that giving it global scope is better programming but as I said, I have been playing with a number of things in this sketch.

What bothers me is the apparent randomness. It loops, repainting the screen from 'text', hundreds (and in some situations many thousands) of times before the last few characters get mashed. I have never seen it mash more than those few at the end. I don't see that anything is changing anywhere other than the time as it loops mindlessly.

I don't need to initialize it after the beginning - the text remains constant at 128 'x's unless I enter new text via Serial.

Suit yourself.

text is currently a local variable that goes out of scope at the end of loop, and get created again when loop gets called again.

Local variables are not initialized, so they contain whatever crap was in the memory space they now occupy. Any number of things could have crapped on that memory since it was last used by your variable.

If you don't want to initialize, I'm OK with that.

Thanks Paul.

I am still trying to understand this environment. I didn't see it as going out of scope at the end of loop() and then reentering, perhaps after doing something else.

I haven't been able to find any manual on the IDE. Is there one?

and