Small SMS messaging device - Solved

Dec 30th, 2013: Editing original post to reflect progress.
Dec 31st, 2013: My problems seem to be SRAM related. See below (reply).
My thanks to Paul Stoffregen (funny, another Paul S) for helping me to debug earlier tonight at Dorkbot.
January 2nd, 2014: I reduced the memory footprint and successfully transmitted an SMS from the device alone.

My goal is to make an SMS messaging device that can operate without a computer. I'm using a SIM900 GPRS modem shield from Linksprite with a Nokia5110 display from Adafruit and a GKOS (6 button chorded) keyboard I soldered together on some perfboard. Links with details on all three hardware parts are below. These interface with an Uno compatible.

I have written ~50 line sketches that allows two of the three hardware components to work together with each sketch: keyboard outputs to LCD, keyboard outputs to GPRS modem, GPRS modem outputs to LCD. In each case I can use a serial monitor (my computer) to input/output to the SIM900/LCD as well.

My problem is I cannot interface all three devices to each other in a single sketch. When I do (specifically, when I initialize the pins for the LCD) my serial monitor outputs a bunch of 8888888888 characters and then a ton of newlines, and the LCD doesn't display any output. I'll post each of my three sketches, and then how I tried to combine them resulting in the issue. Links to the libraries should also be in my post below.

/* SIM900 outputs to LCD */
 
#include <Adafruit_GFX.h>
#include <Adafruit_PCD8544.h>
#include <SoftwareSerial.h>

Adafruit_PCD8544 LCD(6,5,4,3,2);
extern uint8_t SmallFont[];
 
#define rxPin 7
#define txPin 8

SoftwareSerial SIM900(rxPin, txPin);
 
void setup()
{
  LCD.begin();
  LCD.setTextSize(1);
  LCD.clearDisplay();
  LCD.println("LCD link up!");
  LCD.display();
 
  SIM900.begin(19200);  // SIM900 baud rate   
  Serial.begin(19200);  // Serial port baud rate
//  SIM900.println("AT+IPR=19200");  // Do not autobaud
  Serial.println("Serial link up!");
}
 
void loop()
{   
  int i = 0; 
  char someChar[32] = {0};
  if(Serial.available())
  {
    do{
       someChar[i++] = Serial.read();
      }while (Serial.available());
      SIM900.print(someChar);
 }  
  else if(SIM900.available())
  {
    do{
       someChar[i++] = SIM900.read();
      }while (Serial.available());
      Serial.print(someChar);
      LCD.print(someChar); // SIM900 to LCD
      LCD.display();
 }
}
/* GKOS keyboard outputs to SIM900 */
 
#include <SoftwareSerial.h>
#include <Gkos.h>
 
#define rxPin 7
#define txPin 8

SoftwareSerial SIM900(rxPin, txPin);

char* gEntry =""; 
Gkos gkos(10,11,14,12,15,16);

void setup()
{
  SIM900.begin(19200);  // SIM900 baud rate   
  Serial.begin(19200);  // Serial port baud rate
  SIM900.println("AT+IPR=19200");  // do not autobaud
  Serial.println("Serial link up!");
}

void loop()
{
  gEntry = gkos.entry();  // non-blocking
  if (gEntry != 0){gPrint();}  

  // Serial patch to SIM900
  if (SIM900.available())
      Serial.write(SIM900.read());
  if (Serial.available())
      SIM900.write(Serial.read());
}

void gPrint()
{
  if (strcmp(gEntry, "_Enter") == 0){
      //Serial.println("");
      Serial.write( byte(10) ); Serial.write( byte(13) ); return;
  }
  if (strcmp(gEntry, "_BS") == 0){
      Serial.write( byte(8) ); return;
  }
  if (strcmp(gEntry, "_Del") == 0){
      Serial.write( byte(127) ); return;
  }
  if (strcmp(gEntry, "_Tab") == 0){
      Serial.write(byte (9) ); return;
  }

  SIM900.write(gEntry);  // send SIM900 keyboard input
}
/* GKOS keyboard outputs to LCD */

// Include libraries:
#include <Adafruit_GFX.h>
#include <Adafruit_PCD8544.h>
#include <Gkos.h>

Adafruit_PCD8544 LCD(6,5,4,3,2);
extern uint8_t SmallFont[];

char* gEntry = ""; 
Gkos gkos(10,11,14,12,15,16);

void setup()
{
  LCD.begin();
  LCD.setTextSize(1);
  LCD.clearDisplay();
  LCD.println("LCD link up!");
  LCD.display();
  delay(2000);
  LCD.clearDisplay();
}

void loop()
{
  gEntry = gkos.entry();  // non-blocking
  if (gEntry != 0){gPrint();}
}

void gPrint()
{
  if (strcmp(gEntry, "_Enter") == 0){
      //Serial.println("");
      Serial.write( byte(10) ); Serial.write( byte(13) ); return;
  }
  if (strcmp(gEntry, "_BS") == 0){
      Serial.write( byte(8) ); return;
  }
  if (strcmp(gEntry, "_Del") == 0){
      Serial.write( byte(127) ); return;
  }
  if (strcmp(gEntry, "_Tab") == 0){
      Serial.write(byte (9) ); return;
  }
  
  // Put text on the screen 
  LCD.print(gEntry); 
  LCD.display();
}

My attempt to combine all three, resulting in the error:

/* Unlimited Combo! */
 
#include <SoftwareSerial.h>
#include <Gkos.h>
#include <Adafruit_GFX.h>
#include <Adafruit_PCD8544.h>
 
#define rxPin 7
#define txPin 8

SoftwareSerial SIM900(rxPin, txPin);

char* gEntry =""; 
Gkos gkos(10,11,14,12,15,16);

Adafruit_PCD8544 LCD(6,5,4,3,2);
extern uint8_t SmallFont[];

void setup()
{
  SIM900.begin(19200);  // SIM900 baud rate   
  Serial.begin(19200);  // Serial port baud rate
//  SIM900.println("AT+IPR=19200");  // do not autobaud
  Serial.println("Serial link up!");

  LCD.begin();
  LCD.setTextSize(1);
  LCD.clearDisplay();
  LCD.println("LCD link up!");
  LCD.display();
}

void loop()
{
  gEntry = gkos.entry();  // non-blocking
  if (gEntry != 0){gPrint();
  }  
  // Serial patch to SIM900
  int i = 0;
  char someChar[32] = {0};
  if(Serial.available())
  {
  	do
  	{ someChar[i++] = Serial.read();
  	} while (Serial.available());
  	SIM900.print(someChar);
  }
  else if(SIM900.available())
  {
  	do
  	{ someChar[i++] = SIM900.read();
	} while (Serial.available());
	Serial.print(someChar);
	LCD.print(someChar); // SIM900 to LCD
	LCD.display();
  }
}

void gPrint()
{
  if (strcmp(gEntry, "_Enter") == 0){
      //Serial.println("");
      Serial.write( byte(10) ); Serial.write( byte(13) ); return;
  }
  if (strcmp(gEntry, "_BS") == 0){
      Serial.write( byte(8) ); return;
  }
  if (strcmp(gEntry, "_Del") == 0){
      Serial.write( byte(127) ); return;
  }
  if (strcmp(gEntry, "_Tab") == 0){
      Serial.write(byte (9) ); return;
  }

  SIM900.write(gEntry);  // send SIM900 keyboard input
}

Any help combining the sketches is appreciated.

// initialize libraries with numbers of the interface pins
// pin 7 on Arduino is pin 3 on LCD
// pin 6 on Arduino is pin 4 on LCD 
// pin 5 on Arduino is pin 5 on LCD
// pin 4 is N.C. to CS on LCD
// pin 3 on Arduino is pin 7 on LCD
Adafruit_PCD8544 display = Adafruit_PCD8544(6, 5, 4, 3, 2);

The comments and the call do not match,

Gkos gkos(10, 11, 14, 12, 15, 16);

A link to this library would be useful.

A picture of your set up, and a schematic, would be useful, too. Typically, GSM shields use either pins 10 and 11 or pins 2 and 3 for the SoftwareSerial instance. 7 and 8 are a bit unusual.

Hi Paul, good points, thanks! I've edited the comments to match pin assignments now in my original post. More documentation on what hardware I'm using would certainly help huh? I'll post links here.

The GKOS keyboard I'm using is soldered together on some perfboard with each momentary push button connected to a separate pin, and all of them grounding through a 1k resistor. Arduino Playground - GkosMain is the Arduino project page. http://gkos.com/gkos/arduino/library/Gkos_library_2010-04-14.zip contains the library which needs a couple of lines edited to work with Arduino 1.0+ as I edited the project page to reflect, and here is a diagram.

The LCD is the standard Nokia 5510 (5100?) you can buy at Sparkfun or Adafruit. Here is Adafruit's specific library on Github: GitHub - adafruit/Adafruit-PCD8544-Nokia-5110-LCD-library: Arduino driver for PC8544, most commonly found in small Nokia 5110's and it also recommends downloading the more general Adafruit Graphics Library: GitHub - adafruit/Adafruit-GFX-Library: Adafruit GFX graphics core Arduino library, this is the 'core' class that all our other graphics libraries derive from.

The SIM900 shield I'm using is from Linksprite. http://linksprite.com/wiki/index.php5?title=SIM900_GPRS/GSM_Shield, which does specifically indicate D7 and D8 as being connected for software serial, however unconventional that may be. D9 is connected to the power button of the SIM900 and so I skip that pin on the keyboard/LCD wiring, and D13 seems to be pulled high by the shield so I also skip that pin too, otherwise I get a letter on the keyboard constantly registered as depressed. John at Tronixstuff has some nice tutorials I ran through with this shield. http://tronixstuff.com/2013/09/18/tutorial-arduino-sim900-gsm-modules/

I'm still stuck at the point where I mention in my OP. I can print input on the GKOS keyboard to the LCD in one sketch, and I can also send AT commands to control the SIM900 with my GKOS keyboard with a different sketch, but I cannot seem to combine the two as the #include of <SoftwareSerial.h> seems to bork the rest of the SIM900 sketch. Adafruit recommends running the LCD at 9600 bps and the SIM900 is 19200 bps, so I am guessing this is a potential problem and also understand that using two software serial ports simultaneously is problematic. If I can print both the GKOS keyboard input and the SIM900 output to the screen, I'll at least have a standalone device that doesn't need my computer to send/receives SMS messages, which is my goal. Thanks again for any help!

nyukin:
Dec 31st, 2013: My problems seem to be SRAM related. See below (reply).
My thanks to Paul Stoffregen (funny, another Paul S) for helping me to debug earlier tonight at Dorkbot.

Because any two permutations of hardware work together, but all three do not, running out of RAM intuitively makes sense.
To confirm this is the issue, I pasted this little function at the end of each sketch and called it in the setup:

// free RAM check for debugging. SRAM for ATmega328p = 2K
int availableMemory() 
{
    int size = 2048;
    byte *buf;
    while ((buf = (byte *) malloc(--size)) == NULL);
        free(buf);
    return size;
}

From this I've been able to isolate each library to determine how much free RAM I have left when instantiating/#including.

// Free RAM (in bytes) with one component removed:
// GKOS not included/instantiated: 798
// LCD not included/instantiated: 301
// SIM900 not included/instantiated: 13

The biggest offender is the GKOS library. I can include it without issues, but as soon as I call gkos.entry, poof, 800+ bytes of RAM eaten.

I can think of a few ways to proceed:

  • Reduce the gkos.cpp library file's RAM footprint. I'm not skilled enough to to do this on my own yet.
  • Try to exclude hardware serial. Looking at the Adafruit LCD graphics libraries and drivers, I don't see an #include for SoftwareSerial, and my SIM900 shield has jumpers to change the pins easily. I'm considering using a 128 x 64 monochrome display instead of the current 84 x 48, which I imagine would use twice the RAM.
  • Get an AVR with more RAM. Since I plan to make my own tiny board and want it to be small, a TQFP package that has as few leads as possible is preferred.

I'd like to start with the first option. If you can take a look at gkos.cpp from the main Arduino page linked to above, that'd help a lot! Thanks.

The biggest offender is the GKOS library. I can include it without issues, but as soon as I call gkos.entry, poof, 8K+ of RAM eaten.

It is impossible for the GKOS::entry method to use 8K+ of the 2K of SRAM available on the UNO (compatible).

I looked at the GKOS::entry() method and was appalled at the fact that in contains static arrays. One of them, _gChord2_gRef, contains 64 values. None of the values is greater than 64, but the array type is int. It should be uint8_t, so it takes up only 1/2 as much space.

There is huge duplication in other arrays, too. Frankly, that function needs some serious attention to memory usage.

PaulS:

The biggest offender is the GKOS library. I can include it without issues, but as soon as I call gkos.entry, poof, 8K+ of RAM eaten.

It is impossible for the GKOS::entry method to use 8K+ of the 2K of SRAM available on the UNO (compatible).

I looked at the GKOS::entry() method and was appalled at the fact that in contains static arrays. One of them, _gChord2_gRef, contains 64 values. None of the values is greater than 64, but the array type is int. It should be uint8_t, so it takes up only 1/2 as much space.

There is huge duplication in other arrays, too. Frankly, that function needs some serious attention to memory usage.

Thank you, that at least corroborates it and gives me a direction to go in for learning how to make it better.
I just woke up this morning and instantly realized I typed 8K of RAM when I meant 800 bytes! I guess I was sleepier last night than I thought!

Good news!

I accomplished a proof-of-concept that I outlined as my goal in this thread, so the problem was solved.
Since this thread didn't get a lot of replies, I won't detail it all here. At the suggestion of others and after a little trial and error, I reduced the size of the included libraries so that I have enough RAM to run the sketch intended. Notably, I reduced the number of large static char arrays in the GKOS library to only those that I needed.

Hi Nyukin,
I'm having the exact same problem trying to use a LCD display (using the wire library) with a SIM900 library. Independently they work, but together in the same sketch they dont. Could you please explain how you solved your problem?
Kind regards,
Pieter

Greetings Pieter, I was making my first post to the Arduino forums not too long ago myself, so I hope I can help you.

I'm having the exact same problem trying to use a LCD display (using the wire library) ... Could you please explain how you solved your problem?

It sounds like our hardware setups might be different, so what worked for me might not work for you. Specifically, I commented out many lines of code from the GKOS keyboard library I mentioned above because they represented large static character arrays. These character arrays were stored in SRAM, which the Arduino uC I was using only has 2KB of. My problem was when I combined a screen, a keyboard, and the SIM900 functionality in a single sketch, I was running out of RAM and the whole thing started behaving unexpectedly (i.e. not working). I don't know if I properly articulated that in the OP, but that's what I did.

Independently they work, but together in the same sketch they dont.

This is the problem I had, but again I suspect it could be for different reasons. I would encourage you to create a new thread for your project and post up both sketches you are using that work independently, the sketch you tried to use to combine their functionality, and a more through explanation of how you have everything wired together and what hardware you're using. One quick thing that just came to mind for me is that certain pins didn't work well for my project. For instance, my keyboard used 6 pins as input but when I stacked my SIM900 shield from Linksprite on top and then connected my keyboard, pin 13 kept interfering with the keyboard and causing it to randomly type characters. Maybe you're connecting your LCD to pins on the SIM900 shield that are already in use? I'm making a lot of assumptions with that guess, like for all I know you've boughten a breakout board for the modem and are wiring it all individually. Or maybe you're not even using an UNO but instead a Mega or some other compatible. Yep, a new thread seems like a good idea.

Even though the problems might be for different reasons, I'll be happy to assist you as much as I can. I've spent a lot of time getting all my parts to work together how I wanted so I would be pleased if that investment can help somebody else too.