Interesting program crash....

I recently assembled the Modern Device Bare Bones Board and the LCD Interface, and I have been learning by tweaking and changing and adding to the sample code that Paul provides on his site.

One of the things I tried to do was change the backlighting level mid-program, making it dim to various levels. When I would enable this part of the code, the program would crash at a specific spot -- and then restart from the beginning. If I inserted the backlight code before the crash spot, the backlight code would execute perfectly and it would proceed to the crash spot. If I inserted the backlight code at the end of the program, the program would crash at the same spot (way before it reached the backlight section). If I commented out the backlight section, the code would run just perfectly.

In the code below, the backlight section is at the bottom (commented out) (third post below). The approximate location of the crash is located at the comment // PROGRAM CRASHES HERE!!!!!! (first post, about 2/3 way down)

Any thoughts? If you want to try it, and have the Modern Device Serial LCD Board, connect it to Analog Input point 0 which is being used as Digital Pin 14 for serial out to the LCD board.

#include <SoftwareSerial.h>

/* port of Peter Anderson's  LCD117_1.BS2  (Parallax Basic Stamp 2) to Arduino
 Paul Badger 2007
 original Peter H. Anderson, Baltimore, MD, Oct, '06
 Modifications in progress by William P. Cahill, Fort Worth TX
 
 Configured for 20 x 2 display

 */


char N;
int I;
int ByteVar;

int NN;
int Remainder;
int Num_5;

#define rxPin 4  // rxPin is immaterial - not used - just make this an unused Arduino pin number
#define txPin 14 // pin 14 is analog pin 0, on a BBB just use a servo cable :)
SoftwareSerial mySerial =  SoftwareSerial(rxPin, txPin);


// mySerial is connected to the TX pin so mySerial.print commands are used
// one could just as well use the software mySerial library to communicate on another pin

void setup(){


   pinMode(txPin, OUTPUT);
   mySerial.begin(9600);    // 9600 baud is chip comm speed

   mySerial.print("?G216"); // set display geometry,  2 x 16 characters in this case
   delay(100);                 // pause to allow LCD EEPROM to program

   mySerial.print("?Bbf");  // set backlight to 40 hex
   delay(100);              // pause to allow LCD EEPROM to program

   mySerial.print("?s6");   // set tabs to six spaces
   delay(1000);              // pause to allow LCD EEPROM to program

}

void loop(){

   mySerial.print("?D00000000000000000");       // define special characters
   delay(300);                                  // delay to allow write to EEPROM
   //crashes LCD without delay
   mySerial.print("?D11010101010101010");
   delay(300);

   mySerial.print("?D21818181818181818");
   delay(300);

   mySerial.print("?D31c1c1c1c1c1c1c1c");
   delay(300);

   mySerial.print("?D41e1e1e1e1e1e1e1e");
   delay(300);

   mySerial.print("?D51f1f1f1f1f1f1f1f");
   delay(300);

   mySerial.print("?D60000000000040E1F");
   delay(300);

   mySerial.print("?D70000000103070F1F");
   delay(300);

   mySerial.print("?c0");              // turn cursor off
   delay(300);  

   mySerial.print("?f");                   // clear the LCD

   delay(1000);

   mySerial.print("?f");                   // clear the LCD
   delay(100);
   delay(3000);

   mySerial.print("?x00?y0");              // cursor to first character of line 0
   
   mySerial.print("Sample LCD Stuff");   
   mySerial.print("?x00?y1");              // move cursor to beginning of line 1
   mySerial.print("               b");   
   mySerial.print("?x00?y1");              // move cursor to beginning of line 1     
   delay(100);
   mySerial.print("              by");   
   mySerial.print("?x00?y1");              // move cursor to beginning of line 1     
   delay(100);   
   mySerial.print("             by ");   
   mySerial.print("?x00?y1");              // move cursor to beginning of line 1     
   delay(100);   
   mySerial.print("            by B");   
   mySerial.print("?x00?y1");              // move cursor to beginning of line 1     
   delay(100);
   mySerial.print("           by Bi");   
   mySerial.print("?x00?y1");              // move cursor to beginning of line 1     
   delay(100);   
   mySerial.print("          by Bil");   
   mySerial.print("?x00?y1");              // move cursor to beginning of line 1     
   delay(100);
   mySerial.print("         by Bill");   
   mySerial.print("?x00?y1");              // move cursor to beginning of line 1     
   delay(100);
   mySerial.print("        by Bill ");   
   mySerial.print("?x00?y1");              // move cursor to beginning of line 1     
   delay(100);
   mySerial.print("       by Bill C");   
   mySerial.print("?x00?y1");              // move cursor to beginning of line 1     
   delay(100);
   mySerial.print("      by Bill Ca");   
   mySerial.print("?x00?y1");              // move cursor to beginning of line 1     
   delay(100);
   mySerial.print("     by Bill Cah");   
   mySerial.print("?x00?y1");              // move cursor to beginning of line 1     
   delay(100);
   mySerial.print("    by Bill Cahi");   
   mySerial.print("?x00?y1");              // move cursor to beginning of line 1     
   delay(100);
   mySerial.print("   by Bill Cahil");   
   mySerial.print("?x00?y1");              // move cursor to beginning of line 1     
   delay(100);
   mySerial.print("  by Bill Cahill");   
   mySerial.print("?x00?y1");              // move cursor to beginning of line 1     
   delay(100);
   mySerial.print(" by Bill Cahill ");     
   delay(2000);                          // Pause to admire
   

   mySerial.print("  Custom Chars:");        
   mySerial.print("    ?0?1?2?3?4?5?6?7    ");       // display special characters
   delay(3000);                              

   mySerial.print("?f");                   // clear the LCD

   mySerial.print("ASCII Character ");   
   mySerial.print("?x00?y1");              // move cursor to countdown position
   mySerial.print("   Table in 5.. ");     
   delay(1000);
   mySerial.print("?x12?y1");              
   mySerial.print("4");   
   delay(1000);
   mySerial.print("?x12?y1");              
   mySerial.print("3");  
   delay(1000);
   mySerial.print("?x12?y1");             
   mySerial.print("2");
   delay(1000);
   mySerial.print("?x12?y1");              
   mySerial.print("1");
   delay(1000);
   mySerial.print("?x00?y0");              // locate cursor to beginning of line 0
   
   
   // PROGRAM CRASHES HERE!!!!!!
   
   
   mySerial.print("DEC   HEX  ASCII");     // print labels
   delay(500);
   // simple printing demonstation  
   for (N = 38; N<= 126; N++){             // pick an arbitrary part of ASCII chart - change as you wish     
      mySerial.print("?x00?y1");              // locate cursor to beginning of line 1

      mySerial.print(N, DEC);               // display N in decimal format
      mySerial.print("?t");                 // tab in

      mySerial.print(N, HEX);               // display N in hexidecimal format
      mySerial.print("?t");                 // tab in

      // glitches on ASCII 63 "?" -- single "?" is a command character
      if (N=='?'){  
         mySerial.print("??");               // print double ??'s - see Phanderson 117 docs
      }    
      else{    
         mySerial.print(N, BYTE);            // display N as an ASCII character
      }            

      mySerial.print("   ");              // display N as an ASCII character


      delay(200);
   } 




   delay (1000);
   mySerial.print("?y0?x00");         // cursor to beginning of line 0
   delay(10);
   mySerial.print("?l");                   // clear line
   delay(10);
   mySerial.print(" Bar Graph Demo");
   delay(10);
   mySerial.print("?n");         // cursor to beginning of line 1 + clear line 1
   delay(500);

   // bar graph demo - increasing bar
   for ( N = 0; N <= 80; N++){             // 16 chars * 5 bits each = 80
      mySerial.print("?y1?x00");       // cursor to beginning of line 1
      delay(10);

      Num_5 = N / 5;                   // calculate solid black tiles
      for (I = 1; I <= Num_5; I++){ 
         mySerial.print("?5");          // print custom character 5 - solid block tiles
         delay(4);
      }

      Remainder = N % 5;               // % sign is modulo operator - calculates remainder              
      // now print the remainder
      mySerial.print("?");             // first half of the custom character command
      mySerial.print(Remainder, DEC);  // prints the custom character equal to remainder
      delay(5);
   }  

   delay(50);

   for ( N = 80; N >= 0; N--){           // decreasing bar - 16 chars * 5 bits each
      mySerial.print("?y1?x00");       // cursor to beginning of line 1
      delay(10);

      Num_5 = N / 5;                   // calculate solid black tiles
      for (I = 1; I <= Num_5; I++){ 
         mySerial.print("?5");          // print custom character 5 - solid block tiles
         delay(5);
      }

      Remainder = N % 5;               // % sign is modulo operator - calculates remainder              
      // now print the remainder
      mySerial.print("?");             // first half of the custom character command
      mySerial.print(Remainder, DEC);  // prints the custom character equal to remainder
      delay(5);
   }

(see next post for the rest)

More of code from above post (ran out of room)

   delay(500);
   mySerial.print("?f");    // clears screen
   delay(50);
   mySerial.print("- <=====Spinning");
   mySerial.print("?y1?x00");         // cursor to beginning of line 1   
   mySerial.print("        Pinwheel");   
   delay(60);
   mySerial.print("?y0?x00");         // cursor to beginning of line 0
   delay(250);
   mySerial.print("?0");
   delay(10);

   mySerial.print("?D00010080402010000");       // define special characters
   delay(300);                                  // delay to allow write to EEPROM
   //crashes LCD without delay
   mySerial.print("?y0?x00");         // cursor to beginning of line 0
   mySerial.print("/");
   delay(10);

   mySerial.print("?D10000000000001F1F");
   delay(300);
   mySerial.print("?y0?x00");         // cursor to beginning of line 0
   mySerial.print("|");
   delay(10);

   mySerial.print("?D200000000001F1F1F");
   delay(300);
   mySerial.print("?y0?x00");         // cursor to beginning of line 0
   mySerial.print("?0");
   delay(10);

   mySerial.print("?D3000000001F1F1F1F");
   delay(300);
   mySerial.print("?y0?x00");         // cursor to beginning of line 0
   mySerial.print("-");
   delay(10);

   mySerial.print("?D40000001F1F1F1F1F");
   delay(300);
   mySerial.print("?y0?x00");         // cursor to beginning of line 0
   mySerial.print("/");
   delay(10);

   mySerial.print("?D500001F1F1F1F1F1F");
   delay(300);
   mySerial.print("?y0?x00");         // cursor to beginning of line 0
   mySerial.print("|");
   delay(10);

   mySerial.print("?D6001F1F1F1F1F1F1F");
   delay(300);
   mySerial.print("?y0?x00");         // cursor to beginning of line 0
   mySerial.print("?0");
   delay(10);

   mySerial.print("?D71F1F1F1F1F1F1F1F");
   delay(300);
   mySerial.print("?y0?x00");         // cursor to beginning of line 0
   mySerial.print("-");
   delay(10);
   
   mySerial.print("?D0000000000000001F");
   delay(300);
   mySerial.print("?y0?x00");         // cursor to beginning of line 0
   mySerial.print("/");
   delay(10);

   mySerial.print("?c0");              // turn cursor off
   delay(300
      );  

   mySerial.print("?f");                   // clear the LCD

   delay(1000);

   mySerial.print("?y0?x00");         // cursor to beginning of line 0
   delay(10);
   mySerial.print("?l");                   // clear line
   delay(10);
   mySerial.print("    Vertical Bar");
   delay(10);
   mySerial.print("?y1?x00");         // cursor to beginning of line 1
   mySerial.print("      Graph Demo");
   delay(500);

   // vertical bar graph demo - increasing bar
   for ( N = 0; N <= 15; N++){           
      mySerial.print("?y1?x00");       // cursor to beginning of line 1
      delay(10);

      if (N < 8){
         mySerial.print("?y0?x00 ");       // cursor to beginning of line 1 and writes blank space
         mySerial.print("?y1?x00");
         Remainder = (N % 8);               // % sign is modulo operator - calculates remainder              
         // now print the remainder
         mySerial.print("?");             // first half of the custom character command
         mySerial.print(Remainder, DEC);  // prints the custom character equal to remainder
         delay(10);

      }
      else{
         mySerial.print("?y1?x00?7");       // cursor to beginning of line 1 and writes black character
         mySerial.print("?y0?x00");
         Remainder = (N % 8);              // % sign is modulo operator - calculates remainder              
         // now print the remainder
         mySerial.print("?");             // first half of the custom character command
         mySerial.print(Remainder, DEC);  // prints the custom character equal to remainder
         delay(10);

      }

   } 
   delay(100);

   for ( N = 15; N >= 0; N--){           
      mySerial.print("?y1?x00");       // cursor to beginning of line 1
      delay(10);

      if (N < 8){
         mySerial.print("?y0?x00 ");       // cursor to beginning of line 1 and writes blank space
         mySerial.print("?y1?x00");
         Remainder = (N % 8);               // % sign is modulo operator - calculates remainder              
         // now print the remainder
         mySerial.print("?");             // first half of the custom character command
         mySerial.print(Remainder, DEC);  // prints the custom character equal to remainder
         delay(10);

      }
      else{
         mySerial.print("?y1?x00?7");       // cursor to beginning of line 1 and writes black character
         mySerial.print("?y0?x00");
         Remainder = (N % 8);              // % sign is modulo operator - calculates remainder              
         // now print the remainder
         mySerial.print("?");             // first half of the custom character command
         mySerial.print(Remainder, DEC);  // prints the custom character equal to remainder
         delay(10);

      }

   } 
   delay(50);
   for ( N = 0; N <= 15; N++){           // decreasing bar
      mySerial.print("?y1?x00");       // cursor to beginning of line 1
      delay(10);

      if (N < 8){
         mySerial.print("?y0?x00 ");       // cursor to beginning of line 1 and writes blank space
         mySerial.print("?y1?x00");
         Remainder = (N % 8);               // % sign is modulo operator - calculates remainder              
         // now print the remainder
         mySerial.print("?");             // first half of the custom character command
         mySerial.print(Remainder, DEC);  // prints the custom character equal to remainder
         delay(10);

      }
      else{
         mySerial.print("?y1?x00?7");       // cursor to beginning of line 1 and writes black character
         mySerial.print("?y0?x00");
         Remainder = (N % 8);              // % sign is modulo operator - calculates remainder              
         // now print the remainder
         mySerial.print("?");             // first half of the custom character command
         mySerial.print(Remainder, DEC);  // prints the custom character equal to remainder
         delay(10);

      }

   } 
   delay(100);

   for ( N = 15; N >= 0; N--){           
      mySerial.print("?y1?x00");       // cursor to beginning of line 1
      delay(10);

      if (N < 8){
         mySerial.print("?y0?x00 ");       // cursor to beginning of line 1 and writes blank space
         mySerial.print("?y1?x00");
         Remainder = (N % 8);               // % sign is modulo operator - calculates remainder              
         // now print the remainder
         mySerial.print("?");             // first half of the custom character command
         mySerial.print(Remainder, DEC);  // prints the custom character equal to remainder
         delay(10);

      }
      else{
         mySerial.print("?y1?x00?7");       // cursor to beginning of line 1 and writes black character
         mySerial.print("?y0?x00");
         Remainder = (N % 8);              // % sign is modulo operator - calculates remainder              
         // now print the remainder
         mySerial.print("?");             // first half of the custom character command
         mySerial.print(Remainder, DEC);  // prints the custom character equal to remainder
         delay(10);

      }

   }

(One more below)

This should be it...

   delay(50);   
   for ( N = 0; N <= 15; N++){           
      mySerial.print("?y1?x00");       // cursor to beginning of line 1
      delay(10);

      if (N < 8){
         mySerial.print("?y0?x00 ");       // cursor to beginning of line 1 and writes blank space
         mySerial.print("?y1?x00");
         Remainder = (N % 8);               // % sign is modulo operator - calculates remainder              
         // now print the remainder
         mySerial.print("?");             // first half of the custom character command
         mySerial.print(Remainder, DEC);  // prints the custom character equal to remainder
         delay(10);

      }
      else{
         mySerial.print("?y1?x00?7");       // cursor to beginning of line 1 and writes black character
         mySerial.print("?y0?x00");
         Remainder = (N % 8);              // % sign is modulo operator - calculates remainder              
         // now print the remainder
         mySerial.print("?");             // first half of the custom character command
         mySerial.print(Remainder, DEC);  // prints the custom character equal to remainder
         delay(10);

      }

   } 
   delay(100);

   for ( N = 15; N >= 0; N--){           // 16 chars * 8 bits each = 80
      mySerial.print("?y1?x00");       // cursor to beginning of line 1
      delay(10);

      if (N < 8){
         mySerial.print("?y0?x00 ");       // cursor to beginning of line 1 and writes blank space
         mySerial.print("?y1?x00");
         Remainder = (N % 8);               // % sign is modulo operator - calculates remainder              
         // now print the remainder
         mySerial.print("?");             // first half of the custom character command
         mySerial.print(Remainder, DEC);  // prints the custom character equal to remainder
         delay(10);

      }
      else{
         mySerial.print("?y1?x00?7");       // cursor to beginning of line 1 and writes black character
         mySerial.print("?y0?x00");
         Remainder = (N % 8);              // % sign is modulo operator - calculates remainder              
         // now print the remainder
         mySerial.print("?");             // first half of the custom character command
         mySerial.print(Remainder, DEC);  // prints the custom character equal to remainder
         delay(10);

      }

   } 
   delay(1000);


   mySerial.print("?f");                   // clear the LCD

   /* experimental backlight control
   
   mySerial.print("   Backlight    ");   
   mySerial.print("?x00?y1");              // move cursor to beginning of line 1
   mySerial.print("   Adjustment   ");     
   delay(1000);
   mySerial.print("?B10");  // set backlight to ...
   delay(1000);              // pause to allow LCD EEPROM to program
   mySerial.print("?B30");  // set backlight to ...
   delay(1000);              // pause to allow LCD EEPROM to program
   mySerial.print("?B60");  // set backlight to 40 hex
   delay(1000);              // pause to allow LCD EEPROM to program
   mySerial.print("?B90");  // set backlight to ...
   delay(1000);              // pause to allow LCD EEPROM to program
   mySerial.print("?Bbf");  // set backlight to 40 hex
   delay(1000);
   */
}

Classic out of RAM problem. All those constant strings are chewing up RAM like crazy - I'm truly surprised it works at all.

The solution is using program (FLASH) memory for constant string storage. Check this post and others on the forum and elsewhere.

-j

Thanks Jason. I think I'm beginning to understand... Let me see if I comprehend the basics of this lesson:

  1. In
   mySerial.print("ASCII Character ");  
   mySerial.print("?x00?y1");              // move cursor to countdown position
   mySerial.print("   Table in 5.. ");

each time a line of code says "mySerial.print(SOMETHING)", the SOMETHING is stored in RAM instead of in the flash memory as a separate constant string where it is called instead of being called from the program itself. With all of the strings in the code, it ate up the RAM pretty quick.

  1. In your example
#include <avr/pgmspace.h>

// print prompts and messages from program flash to save SRAM
void print_prompt_P(const char *data)
{
   while (pgm_read_byte(data) != 0x00)
     Serial.print(pgm_read_byte(data++));
}

the subroutine print_prompt_P, along with the command PSTR from the library pgmspace.h allows me to store these strings in the main program memory.

That's kind of cool.

Should I be able to use mySerial.print(pgm_read_byte(data++)); instead of Serial.print(pgm_read_byte(data++)); so that I can use the alternate output pin for the mySerial command?

Thanks again and 73. This information will be good to know -- one of my goals is to make an APRS/packet radio telemetry unit which may involve lots of serial strings out to the TNC (and, of everybody here, I know you know what I'm talking about!)