After running, Sketch Starts Printing Garbage

After running for a while, my sketch starts displaying symptoms of memory corruption. It is a simple sketch, using port manipulation, to control a multiplexed array of LEDs.

It will run correctly for a while, then appear to freeze, with a semi-random LED illuminated. However, the sketch is running, as I have debug code which displays the stts via an array LEDs[]. This LED will remain constant unless the sketch is changed. It is printing this array that shows corruption.

In inserted code to monitor and detect an out of bounds condition of my array indices, but it did not show anything. Can you take a look, and see if you can detetc anything that maight cause memory corruption.

// Column = PORTB = Pins 8-10
// Rows = PORTD = Pins 4-6

#define halt while(-1){}
#define notDone true

#define PatternDataFile "PatternsData.h"
#include PatternDataFile

#define maxColumnDelay 20
#define maxPatternRepeat 10


const String LEDs[8] {
  "---",
  "--X",
  "-X-",
  "-XX",
  "X--",
  "X-X",
  "XX-",
  "XXX"
};
// end global variable definitions

//********************************************************************************
void setup() {

  // initialize console
  Serial.begin(9600);

  // initialize pseudo-random generator
  randomSeed(analogRead(A0));

  // initialize control pins; pattern
  DDRD = DDRD | B01110000;  // sets pins 4 to 6 as output
  PORTD = PORTD & B10001111; // sets pins 4 to 6 to low

  // initialize control pins; columns
  DDRB = DDRB | B00000111; // sets pins 8 to 10 as output
  PORTB = PORTB | 7; // sets pins 8 - 10 to high

}
// end setup()

//********************************************************************************
void loop() {
  int mySequence; // variable containing the sequence currently displaying
  int nextSequence; // variable containing the next requested sequence
  int myPattern;  // temporary variable containing the pattern for a given column
  int myCell = 0; // variable containing the cell index
  // in simulation, local definition failed!!!

  while (notDone) {

    // Choose sequence
    mySequence = random(1, (maxSequence + 1));
    // mySequence = 2;


    for (myCell = 0; myCell < tableSequences[mySequence]; myCell++) {

      for (int repeatPattern = 0; repeatPattern < maxPatternRepeat; repeatPattern++) {

        for (int myColumn = 0; myColumn < 3; myColumn++) {

          PORTB = PORTB | 7; // disable column output
          myPattern = (pattern_x[mySequence][myCell][myColumn]);
          // set pattern
          PORTD = (
                    (PORTD & B10001111)
                    |
                    (myPattern << 4)
                  );
          // illuminate LEDs
          PORTB = (
                    (PORTB & B11111000)
                    |
                    (7 - (1 << myColumn))
                  );
          displayLEDs(myPattern);
          // Debug
          if (mySequence > maxSequence |
              myCell > maxCells |
              myColumn > maxColumn ) {
            Serial.print(mySequence);
            Serial.print("\t");
            Serial.print(myCell);
            Serial.print("\t");
            Serial.print(myColumn);
            Serial.print("\t");
            halt;
          }
          // Debug


        } // end myColumn
      }     // end repeatPattern
      //      delay(maxColumnDelay);
    }   // end myCell
    nextSequence = getSequence();
    if ((nextSequence >= 0) & (nextSequence < maxSequence)) {
      mySequence = nextSequence;
      break;
    }
    if (nextSequence == 99) halt;
  } // end 'while(notDone)' loop
} // end loop()

//********************************************************************************
void displayLEDs(int thePattern) {
  static int counter = 0;

  Serial.print(LEDs[thePattern]);
  Serial.print("\t");
  Serial.println(thePattern);

  if (counter == 2) {
    counter = 0;
    Serial.println();
  } else {
    counter++;
  }
} // end displayLEDs()

//********************************************************************************
int getSequence() {
  static String inputStream = "";
  int returnValue = 0;
  int inputChar = 0;

  while (Serial.available() > 0) { // read serial input
    inputChar = Serial.read();
    if (isDigit(inputChar)) { // add digit to string
      inputStream += (char)inputChar;
    } // end add digit to string

    if (inputChar == '\n') { // on newline, return value of input digits
      returnValue = inputStream.toInt();
      inputStream = ""; // clear the string for new input:
      return returnValue;
    } // end return input stream value

  } // end read serial input
} // end getSequence()
//djl
// PatternsData_v8
const int maxSequence = 6;
const int maxCells = 18;
const int maxColumn = 3;

// table of the lengths of the defined sequences
// each number represents the number of steps/cells in a sequence
int tableSequences[maxSequence] = { 2, 4, 4, 4, 8, 18 };

// table of the port values for each column for each pattern
// "}, {" separates SEQUENCE definitions
// "{a, b, c}" defines a pattern for each CELL
// "a-c" are the individual patterns for each COLUMN within a cell
const int pattern_x[maxSequence][maxCells][maxColumn] = {
  {
// 0 - star
    {2, 7, 2},
    {5, 2, 5}
  }, {
// 1 - horizontal bar
    {1, 1, 1},
    {2, 2, 2},
    {4, 4, 4},
    {2, 2, 2}
  }, {
// 2 - vertical bar    
    {7, 0, 0},
    {0, 7, 0},
    {0, 0, 7},
    {0, 7, 0}
  }, {
// 3 - single    
    {1, 0, 0},
    {0, 1, 0},
    {0, 0, 1}
  }, {
// 4 - round    
    {0, 4, 0},
    {4, 0, 0},
    {2, 0, 0},
    {1, 0, 0},
    {0, 1, 0},
    {0, 0, 1},
    {0, 0, 2},
    {0, 0, 4}
  }, {
// 5 - box
    {0, 0, 0},
    {1, 0, 0},
    {3, 0, 0},
    {7, 0, 0},
    {7, 1, 0},
    {7, 3, 0},
    {7, 7, 0},
    {7, 7, 1},
    {7, 7, 3},
    {7, 7, 7},
    {3, 7, 7},
    {1, 7, 7},
    {0, 7, 7},
    {0, 3, 7},
    {0, 1, 7},
    {0, 0, 7},
    {0, 0, 3},
    {0, 0, 1}
  }
};

LED_Patterns_v8.ino (3.84 KB)

PatternsData.h (1.25 KB)

const String LEDs[8] {
  "---",
  "--X",
  "-X-",
  "-XX",
  "X--",
  "X-X",
  "XX-",
  "XXX"
};

By my rough reckoning, that's 72 bytes of precious RAM wasted to store 24 bits worth of information.
That's not a good ratio, IMO.

Why does your code have halt in it?

That is NOT calling the halt() function. Why would you want to do that?

The problem is probably with your use of Strings. There is NO excuse for using Strings on an Arduino, which has little memory. Obviously, you control what is sent to the Arduino. Limit the number of characters that can be sent, and use a char array of the appropriate size.

There you go:

mySequence = random(1, (maxSequence + 1));

Couple of questions:

Why is everything you do an int? Byte will do just fine.

Is tableSequences going to change? Aka, why isn't that a const?

And you started of so good with const, why use ugly macros (for maxColumnDelay and maxPatternRepeat)?

#define PatternDataFile "PatternsData.h"
#include PatternDataFile

What the?

#define halt while(-1){}
#define notDone true

WHAT THE? Let the damn loop loop.

nextSequence = getSequence();
    if ((nextSequence >= 0) & (nextSequence < maxSequence)) {
      mySequence = nextSequence;
      break;
    }
    if (nextSequence == 99) halt;

So this does a bunch of things to only fill mySeqence with something and the first thing at the top is to fill it with something random again...

You want speed (hence the port manipulation) but only use Serial at 9600 baud?

Why doesn't do displayLEDs() anything with leds?

AWOL:
By my rough reckoning, that's 72 bytes of precious RAM wasted to store 24 bits worth of information.

Info you don't need to store because it's very easy to actually calculate... It's damn binary.

And indeed, all the String crap is extra overhead...

Info you don't need to store because it's very easy to actually calculate... It's damn binary.

I was being uncharacteristicically charitable - the pattern could change.

link=msg=3265711:
Why does your code have halt in it?

In certain circumstances, I want the sketch to stop doing what it is doing. I use the macro halt to throw it into a do-nothing infinite loop. It's just a common programming trick that I use.

septillion:
Why is everything you do an int? Byte will do just fine.

No reason for now. The sketch was small enough that for initial testing, I defined as int. Sometimes when using byte I run into problems with casting.

septillion:
Is tableSequences going to change? Aka, why isn't that a const?

No reason. Could make it a const.

septillion:
And you started of so good with const, why use ugly macros (for maxColumnDelay and maxPatternRepeat)?

There is quite a bit of discussion of whether to use const or #define on the forum. I have yet to decide which method I prefer, so there is often a mix of the two techniques in my sketches.

Re:

septillion:
What the?

I believe I have answered this above.

Re:

septillion:
WHAT THE? Let the damn loop loop.

Ok. Good point. I am not comfortable yet with loop() looping. So I code the same functionality in the function itself. I sometimes do some initialization in loop() and want to skip that, but I should be doing that in setup() or as a global variable instead... Mea culpa.

septillion:
You want speed (hence the port manipulation) but only use Serial at 9600 baud?

The requirement is not necessarily for speed. It is more for learning about port manipulation And serial communications are primarily used for debugging, hence the speed of 9600. It's the default on my laptop, and I am lazy. It could change.

septillion:
Why doesn't do displayLEDs() anything with leds?
Info you don't need to store because it's very easy to actually calculate... It's damn binary.

DisplayLEDs() displays the expected status of the LEDs. Not anything ti do with the actua state of the LEDs. Again, it is used for debugging. ANd No, it cannot be calculated. The array contains information to set specific LEDs for a specific pattern in a specific sequence. The fact that multiple pattern are shown, would reuire separate code for each possible pattern to be in the loop() funtion (or a user defined function). Using the array allows for one set of code to display many functions.

Other than the comment about all the String crap, I don't see any of this affecting memory corruption.

I use strings because I struggle with char arrays. Not a good reason, I understand. I will look into the use of String. In a quick review of the code, I use String in two places. One is for a const array, implying that memory corruption does not occur here, The other is in a function to process serial input. However, if I comment out use of that function, it still hangs.

That gave me an idea. I commented out the display(LEDs) function and got strange results. The sketch hangs almost immediately! I totally don't understand this behavior.

OK! I had some time to absorb all this information. Thank you.

Much of it had to do with programming style and I took most of it to heart. I am using const where appropriate instead of #define. The major change I made was to type most of my variables as byte instead of int.

To this last point, variables set in PatternsData.h would not compile if byte was used. The compiler reported unknown type. Is it possible a naming problem regarding my include file? I.e., should it be a .c file or something else rather than a .h file?

However, there was something I missed in @septillion 's reply...

mySequence = random(1, (maxSequence + 1));

There is a mix of variable types in that statement. I changed it to:

mySequence =  (byte) random(1, ((float) maxSequence + 1));

I am not sure whether the second argument to random() should be float or not. The documentation does not specify. But it works.

Yes, It had been running fine for several minutes plus the time it is taking me to type this reply. Thanks guys. If you want, please reply to two things.

  • Why is "byte" not recognized in the include file
  • What type should the parameters to random() be?

First three, all a bad habit. If you want to do nothing, just let the loop() do nothing. Or at least make a real function.

And we don't have loads of memory otherwise we just would use a uint64_t for everything... Try to get into the habit of using the smallest variable and making const what can be const :slight_smile:

djsfantasi:
There is quite a bit of discussion of whether to use const or #define on the forum. I have yet to decide which method I prefer, so there is often a mix of the two techniques in my sketches.

That from people who or not understand it or are old school C programmers. A const is the safer alternative introduced in C++. See When #define is considered harmful

djsfantasi:
Re:Ok. Good point. I am not comfortable yet with loop() looping. So I code the same functionality in the function itself. I sometimes do some initialization in loop() and want to skip that, but I should be doing that in setup() or as a global variable instead... Mea culpa.

Use the tools that are handed to you. :wink: Or do you go out and look for a stone to hammer in a nail if you're handed a hammer and a nail?

djsfantasi:
DisplayLEDs() displays the expected status of the LEDs. Not anything ti do with the actua state of the LEDs. Again, it is used for debugging.

Then don't call it that :wink: Call it what it does, debugPatern() for example.

djsfantasi:
ANd No, it cannot be calculated. The array contains information to set specific LEDs for a specific pattern in a specific sequence.

I was talking about what you read from you LEDs String array :wink:

And wow, you mist the most important bit of my reply... I even started with it. That will give you a very nice buffer overflow :wink:

[edit]You replied when typing.

  1. byte is an Arduino type. To use that, you have to include Arduino.h. Or use the C++ type uint8_t.

  2. random() only takes integers, long's to be precise. And yeah, it would be a good idea to have that in the reference indeed.

But you change to the line isn't going to fix it. What are the possible numbers mySequence now can have?

OK, one more update. I got carried away responding to your replies and didn't sufficiently research them.

Performing a Google search,, I found an issue that was rsolved bu including "WProgram.h" before the custom include file. But my compiler did not recognize that file. So i searched the Arduino program folder, and found that its libraries did contain references to WProgram, but it appeared in an ifdef statement in the few that I checked. The ifdef also referenced "Arduino.h" as the alternate.

I included Arduino.h, and variables of type byte are now recognized.

To me, this is weird.

It's not that weird. byte isn't a standard C++ type, it's defined by the Arduino IDE in the Arduino.h file. And every file is compiled on it's own, so without knowledge of any other file. So without the Arduino.h the compiler doesn't know the type :slight_smile: Your sketch is an exception because the IDE does some helping magic (like function prototyping, including Arduino.h etc). But that only applies to your sketch. If you make .h, .c or .cpp files they are just compiled as is :slight_smile:

And in prehistoric times that files was indeed called WProgram.h but since Arduino IDE 1.xx it's Arduino.h :slight_smile:

Septillion, great comments.

The first two comments, I totally agree. Starting with this sketch, I will take your advice. Specifically as to using the smallest variable type and using const instead of define where appropriate. Thank you specifically for your advice on const usage.

I have yet to find the buffer overflow. It DID have one, and that was because of (apparently) casting in the use of the random function. I do recognize one condition, but it really shouldn't occur. The parameter to the displaysLEDs() function is coming from the const array and should only be in the range of 0-7. Eight values. LEDs[] is defined as having eight elements. At least in the reading from the LEDs[] array.

However - Wow - completely blew the calculation of the mySequence variable. An edge condition problem. I believe it should be:

mySequence =  (byte) random(0, ((long) maxSequence - 1));

I have defined pattern_x to have one dimension of mySequence entries. They are indexed by a value of 0 to mySequence less one. I was calculating a value that could potentially be too large by two values, maxSequence and maxSequence+1.

Oops, my mistake.

And in your follow up, thanks for the education on the WProgram.h and Arduino.h files.

The new random indeed doesn't overshoot the array anymore. But the last sequence isn't used now :stuck_out_tongue: The second parameter to random is exclusive :wink:

And absolutely no need to cast it :slight_smile: (at least not by you specifying it)

Yup, last sequence is still an error.

With regard to your other point before I cast the output, it was assigning a long to an int... and Bingo, returned garbage. Once I cast it to a byte - it worked.

I am trying to remove the while loop internal to loop(). Not going well. It doesn't seem to be reading the array pattern_x. I am not sure yet. But doing this does break the sketch. Still investigating,

Assigning random() to a int should just work...

If it "works" when you cast it your just lucky and the compiler just compiles different. But I think you just have a memory overflow somewhere near where the random value is stored.

septillion:
Assigning random() to a int should just work...

If it "works" when you cast it your just lucky and the compiler just compiles different. But I think you just have a memory overflow somewhere near where the random value is stored.

But I am assigning it to a "byte"? Not an "int".

So if you are right, how do I track down that memory overflow?

Still, will work just fine.

Can you tidy up the code a bit (removed serial etc) and repost it?

:o

I can, but it breaks it again. Which supports your theory that there is a memory corru ption issue somewhere.

I have uploaded the "working" version "LED_Patterns_v8" and the "cleaned up" version "LED_Patterns_v8a".

"PatternData.h" does not change between the two sketches.

Thanks for the assistance.

LED_Patterns_v8.ino (4.11 KB)

PatternsData.h (1.28 KB)

LED_Patterns_v8a.ino (3.63 KB)

I have tidied up the "cleaned up" version after further clean up. It still does not work. I don't know if it is significant, but one consistent change always caused it to stop working. When I commented out the call to displayLEDs(). Ironically, I expected that to improve the issue as you had commented about problems with the definition of LEDs[].

I have been looking and looking and nothing seems out of place. I even put back the #define statements for the array maximum values (and added the same #define statements to the main .ino file, as you had mentioned that the files are compiled separately). No good change occurred.

LED_Patterns_v8b.ino (2.51 KB)

Can you redefine "does not work" for me. The original question was something about it printing garbage, but there are no prints in the new code there. So what is the current symptom?

Valid point.

The purpose of the sketch is to multiplex a 3x3 array of LEDs, to display a series of patterns defined in the sketch.

In previous discussions, we believe that there is apparent memory corruption.

Septillon requested a copy of the code, with all debug statements removed. This included all the "prints" which originally displayed the problem.

"Does not work" means that the LEDs are blank or very dim; no patterns are displayed. One early version did show the patterns, but as soon as it was modified, the sketch returned to a "does not work" state,