128x64 (Adafruit SSD1306) doesnt work with SIM800L

Hello everyone. Hope someone experienced could help me to resolve this.
I'm building a simple device using SIM800L (D2,D3) > Arduino Nano and and an OLED display 128x64 via IIC.
All works fine when I'm testing the SIM800> Arduino or Display> Arduino. But when I try using them all together then Arduino restarts itself constantly.

I'm using SoftwareSerial.h to interface with the SIM800L and it works fine.
For the OLED i'm using Adafruit_GFX.h and Adafruit_SSD1306.h libraries.
In Setup I do display.begin first and then SIM800.begin(9600)
If I try to use an AT command to SIM800 like SIM800.println("ATE0"); the display stop working. Actually the whole sketch stops working.
Banging my head in the wall for 2 days with no result.
Couldn't find any similar problem in google or here in the forum (maybe didn't search hard enough).

Look at your Build report. Adafruit_SSD1306 allocates 1024 bytes for its scrren buffer at runtime.

Reduce your SRAM usage. e.g. messages in PROGMEM, correct size of arrays, ...

David.

david_prentice:
Look at your Build report. Adafruit_SSD1306 allocates 1024 bytes for its scrren buffer at runtime.

Reduce your SRAM usage. e.g. messages in PROGMEM, correct size of arrays, ...

David.

Thank you for the reply!! This is a bit too advanced for me :slight_smile:
Will appreciate any guidance. E.g. how to reduce the SRAM usage?

First off. Click the "build icon".
Then look at the build report. e.g. (this is just a random sketch for a Uno)

Sketch uses 28448 bytes (88%) of program storage space. Maximum is 32256 bytes.
Global variables use 1073 bytes (52%) of dynamic memory, leaving 975 bytes for local variables. Maximum is 2048 bytes.

Note that it says 975 bytes of SRAM are available. i.e. it looks good.
Adafruit_SSD1306 would attempt to allocate 1024 bytes at runtime. And it would FAIL.

If Global was 975 and local was 1073, the build still looks good.
Adafruit_SSD1306 would attempt to allocate 1024 bytes at runtime. And it would SUCCEED.
However you would only have 49 bytes left. Your program might run for a few seconds. But it will almost certainly crash.

If you want help with your sketch, paste or attach it to your message.
It is easier to show by example than to offer general advice.

David.

Thanks. It makes more sense.
Here is the Build and the code (attached). Just wanted it to get SMS and print on the OLED. Didnt realise that it's such a hassle :slight_smile:

Sketch uses 19276 bytes (62%) of program storage space. Maximum is 30720 bytes.
Global variables use 966 bytes (47%) of dynamic memory, leaving 1082 bytes for local variables. Maximum is 2048 bytes.

#include <SoftwareSerial.h>
#include <Adafruit_GFX.h> // OLED display
#include <Adafruit_SSD1306.h> // OLED display
#include <DS3231.h> // Clock

SoftwareSerial SIM800(2, 3);  // 3 - RX Arduino (TX SIM800L), 2 - TX Arduino (RX SIM800L)
DS3231 clock;
RTCDateTime dt;
Adafruit_SSD1306 display(-1); //-1 if sharing Arduino reset pin with OLED reset

String intDateTime;
String Operator;
String GSMquality;
String IMEI;
boolean ATresult;
String PhoneNumber;
String CallerID;
String SMSbody;
String GSMeventDateTime;

//***************************************************************************
//***************************************************************************
void setup() {
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);  
  delay(100);
  Serial.begin(9600);
  Serial.println("Start Setup");
  
  clock.begin();
  Serial.println("Modules Begin Complete");
  delay(1000);
  
  // Set sketch compiling time taken from the Computer during compiling
  //clock.setDateTime(__DATE__, __TIME__);
  
  display.display(); // Display splash screen
  delay(3000);
  Serial.println("Display Splash");
  display.clearDisplay(); // Clear the display buffer.
  
  Serial.println("Display splash screen done");
  
// Display Device Info
  display.setTextSize(2);
  display.setTextColor(WHITE);
  display.setCursor(12,16);
  display.println("GSM Controller");
  display.setCursor(22,32);
  display.println("Module");
  display.setCursor(29,48);
  display.println("V 1.0");
  display.display();
  delay(3000);
  display.clearDisplay();
  display.display();
  
  // SIM800L Initialise
  SIM800.begin(9600);
  delay(100);
  SIM800.println("AT");
  delay(50);
  SIM800.println("ATE0"); // Echo OFF
  delay(50);
  SIM800.println("AT+CMGF=1"); // Switch to SMS text format
  delay(50);

  Serial.println("End Setup");
}//        SETUP END
//***************************************************************************
//***************************************************************************
void loop() {
  String SIMtext;
  String prevSIMtext;
  if (SIM800.available()>0){           
    SIMtext=SIM800.readString();
    Serial.println(SIMtext);    
  }
  if (Serial.available()>0){           
    SIM800.write(Serial.read());    
  }

 if(SIMtext!=prevSIMtext){
  ATmanager(SIMtext);
  prevSIMtext=SIMtext;
 }

} //      LOOP END
//***************************************************************************
//***************************************************************************
//        FUNCTIONS
void ATmanager(String incText){
  String ATmessage;
  String ATcode;
  int GSMq;
  int x;
  int y;
  ATcode=incText.substring(2,8);
  ATcode.trim();
  Serial.print("AT code is:");Serial.println(ATcode);
  if(ATcode=="+CSQ:"){ //                          Signal Quality
    x=incText.indexOf(":");y=incText.indexOf(",");
    GSMquality=incText.substring(x+1,y);
    GSMquality.trim();
    GSMq=GSMquality.toInt();
    //Serial.println(GSMq);
    if(GSMq >= 0 && GSMq <= 9){
      GSMquality="WEAK"; goto Z20;
      }
    if(GSMq >= 10 && GSMq <= 14 ){
      GSMquality="FAIR"; goto Z20;
      }
    if(GSMq >= 15 && GSMq <= 19){
      GSMquality="GOOD"; goto Z20;
      }
    if(GSMq >= 20 && GSMq <= 30){
      GSMquality="BEST"; goto Z20;
      }
    if(GSMq = 99){
      GSMquality="NONE";
      }
Z20: Serial.print("GSM Quality: ");Serial.println(GSMquality);
    }// END OF CSQ

    if(ATcode=="+COPS:"){ //                        SIM Operator
      x=incText.indexOf((char)34);
      y=incText.indexOf((char)34,x+1);
      Operator = incText.substring(x+1,y);
      Serial.print("SIM Operator: ");Serial.println(Operator);
    }// END OF Operator

    if(incText.substring(2,3)!="+"){ // IMEI
      x=incText.indexOf("OK");
      IMEI=incText.substring(2,x);
      IMEI.trim();
      Serial.print("IMEI: ");Serial.println(IMEI);
    }// END OF IMEI

    if(ATcode=="+CMT:"){ // SMS READING
      x=incText.indexOf((char)34);
      y=incText.indexOf((char)34,x+1);
      PhoneNumber = incText.substring(x+1,y);
      x=incText.indexOf((char)34,y+1);
      y=incText.indexOf((char)34,x+1);
      CallerID = incText.substring(x+1,y);
      x=incText.indexOf((char)34,y+1);
      y=incText.indexOf((char)34,x+1);
      GSMeventDateTime = incText.substring(x+1,y);
      SMSbody=incText.substring(y+2,y+128);
      SMSbody.trim();
      Serial.print("Number: ");Serial.println(PhoneNumber);
      Serial.print("CallerID: ");Serial.println(CallerID);
      Serial.print("DateTime: ");Serial.println(GSMeventDateTime);
      Serial.print("Message: ");Serial.println(SMSbody);
      
//      //OLED display
      display.clearDisplay();
      display.setTextSize(1);
      display.print("Number: ");display.println(PhoneNumber);
      display.print("CallerID: ");display.println(CallerID);
      display.print("DateTime: ");display.println(GSMeventDateTime);
      display.print("Message: ");display.println(SMSbody);
      display.display();

 
    } // END OF SMS READING

}// END OF ATmanager
//*********************************************************************
String getDateTimeValue() //getDateTimeValue();
{
  dt = clock.getDateTime();

  String YY,MO,DD,HH,MM,SS;
  YY=String(dt.year);
  MO=String(dt.month);
  if (dt.month<10){MO="0"+MO;}
  DD=String(dt.day);
  if (dt.day<10){DD="0"+DD;}
  HH=String(dt.hour);
  if (dt.hour<10){HH="0"+HH;}
  MM=String(dt.minute);
  if (dt.minute<10){MM="0"+MM;}
  SS=String(dt.second);
  if (dt.second<10){SS="0"+SS;}

  String intDT= YY+"-"+MO+"-"+DD+" "+HH+":"+MM+":"+SS;
 
  return intDT;
}

SIM800L_Beginning_4_Afrt_OLED.ino (6.14 KB)

1 Like

I just did ctrl-T to format the code.
Then search for print(" and change it to print(F("
Then search for println(" and change it to println(F("
Then search for ") and change it to "))
Then search for "); and change it to "));

Untested. Please just try it.

#include <SoftwareSerial.h>
#include <Adafruit_GFX.h> // OLED display
#include <Adafruit_SSD1306.h> // OLED display
#include <DS3231.h> // Clock

SoftwareSerial SIM800(2, 3);  // 3 - RX Arduino (TX SIM800L), 2 - TX Arduino (RX SIM800L)
DS3231 clock;
RTCDateTime dt;
Adafruit_SSD1306 display(-1); //-1 if sharing Arduino reset pin with OLED reset

String intDateTime;
String Operator;
String GSMquality;
String IMEI;
boolean ATresult;
String PhoneNumber;
String CallerID;
String SMSbody;
String GSMeventDateTime;

//***************************************************************************
//***************************************************************************
void setup() {
    display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
    delay(100);
    Serial.begin(9600);
    Serial.println(F("Start Setup"));

    clock.begin();
    Serial.println(F("Modules Begin Complete"));
    delay(1000);

    // Set sketch compiling time taken from the Computer during compiling
    //clock.setDateTime(__DATE__, __TIME__);

    display.display(); // Display splash screen
    delay(3000);
    Serial.println(F("Display Splash"));
    display.clearDisplay(); // Clear the display buffer.

    Serial.println(F("Display splash screen done"));

    // Display Device Info
    display.setTextSize(2);
    display.setTextColor(WHITE);
    display.setCursor(12, 16);
    display.println(F("GSM Controller"));
    display.setCursor(22, 32);
    display.println(F("Module"));
    display.setCursor(29, 48);
    display.println(F("V 1.0"));
    display.display();
    delay(3000);
    display.clearDisplay();
    display.display();

    // SIM800L Initialise
    SIM800.begin(9600);
    delay(100);
    SIM800.println(F("AT"));
    delay(50);
    SIM800.println(F("ATE0")); // Echo OFF
    delay(50);
    SIM800.println(F("AT+CMGF=1")); // Switch to SMS text format
    delay(50);

    Serial.println(F("End Setup"));
}//        SETUP END
//***************************************************************************
//***************************************************************************
void loop() {
    String SIMtext;
    String prevSIMtext;
    if (SIM800.available() > 0) {
        SIMtext = SIM800.readString();
        Serial.println(SIMtext);
    }
    if (Serial.available() > 0) {
        SIM800.write(Serial.read());
    }

    if (SIMtext != prevSIMtext) {
        ATmanager(SIMtext);
        prevSIMtext = SIMtext;
    }

} //      LOOP END
//***************************************************************************
//***************************************************************************
//        FUNCTIONS
void ATmanager(String incText) {
    String ATmessage;
    String ATcode;
    int GSMq;
    int x;
    int y;
    ATcode = incText.substring(2, 8);
    ATcode.trim();
    Serial.print(F("AT code is:")); Serial.println(ATcode);
    if (ATcode == "+CSQ:") { //                          Signal Quality
        x = incText.indexOf(":"); y = incText.indexOf(",");
        GSMquality = incText.substring(x + 1, y);
        GSMquality.trim();
        GSMq = GSMquality.toInt();
        //Serial.println(GSMq);
        if (GSMq >= 0 && GSMq <= 9) {
        GSMquality = "WEAK"; goto Z20;
    }
    if (GSMq >= 10 && GSMq <= 14 ) {
        GSMquality = "FAIR"; goto Z20;
    }
    if (GSMq >= 15 && GSMq <= 19) {
        GSMquality = "GOOD"; goto Z20;
    }
    if (GSMq >= 20 && GSMq <= 30) {
        GSMquality = "BEST"; goto Z20;
    }
    if (GSMq = 99) {
        GSMquality = "NONE";
    }
Z20: Serial.print(F("GSM Quality: ")); Serial.println(GSMquality);
}// END OF CSQ

if (ATcode == "+COPS:") { //                        SIM Operator
        x = incText.indexOf((char)34);
        y = incText.indexOf((char)34, x + 1);
        Operator = incText.substring(x + 1, y);
        Serial.print(F("SIM Operator: ")); Serial.println(Operator);
    }// END OF Operator

    if (incText.substring(2, 3) != "+") { // IMEI
        x = incText.indexOf("OK");
        IMEI = incText.substring(2, x);
        IMEI.trim();
        Serial.print(F("IMEI: ")); Serial.println(IMEI);
    }// END OF IMEI

    if (ATcode == "+CMT:") { // SMS READING
        x = incText.indexOf((char)34);
        y = incText.indexOf((char)34, x + 1);
        PhoneNumber = incText.substring(x + 1, y);
        x = incText.indexOf((char)34, y + 1);
        y = incText.indexOf((char)34, x + 1);
        CallerID = incText.substring(x + 1, y);
        x = incText.indexOf((char)34, y + 1);
        y = incText.indexOf((char)34, x + 1);
        GSMeventDateTime = incText.substring(x + 1, y);
        SMSbody = incText.substring(y + 2, y + 128);
        SMSbody.trim();
        Serial.print(F("Number: ")); Serial.println(PhoneNumber);
        Serial.print(F("CallerID: ")); Serial.println(CallerID);
        Serial.print(F("DateTime: ")); Serial.println(GSMeventDateTime);
        Serial.print(F("Message: ")); Serial.println(SMSbody);

        //      //OLED display
        display.clearDisplay();
        display.setTextSize(1);
        display.print(F("Number: ")); display.println(PhoneNumber);
        display.print(F("CallerID: ")); display.println(CallerID);
        display.print(F("DateTime: ")); display.println(GSMeventDateTime);
        display.print(F("Message: ")); display.println(SMSbody);
        display.display();


    } // END OF SMS READING

}// END OF ATmanager
//*********************************************************************
String getDateTimeValue() //getDateTimeValue();
{
    dt = clock.getDateTime();

    String YY, MO, DD, HH, MM, SS;
    YY = String(dt.year);
    MO = String(dt.month);
    if (dt.month < 10) {
        MO = "0" + MO;
    }
    DD = String(dt.day);
    if (dt.day < 10) {
        DD = "0" + DD;
    }
    HH = String(dt.hour);
    if (dt.hour < 10) {
        HH = "0" + HH;
    }
    MM = String(dt.minute);
    if (dt.minute < 10) {
        MM = "0" + MM;
    }
    SS = String(dt.second);
    if (dt.second < 10) {
        SS = "0" + SS;
    }

    String intDT = YY + "-" + MO + "-" + DD + " " + HH + ":" + MM + ":" + SS;

    return intDT;
}

Please report back with your Memory Usage lines.

David.

Edit. Used a better search for the ") in a print statement. But I then had to manually search for ")); to check for any non-print changes. e.g. incText.indexOf(":");

Hi David.
Thank you. I tried it. Now it shows

Sketch uses 19412 bytes (63%) of program storage space. Maximum is 30720 bytes.
Global variables use 744 bytes (36%) of dynamic memory, leaving 1304 bytes for local variables. Maximum is 2048 bytes.

and goes through setup step ok. However in the main part it doesn't properly work. I have a same set of code but without anything related to the display and it works well and I can see it in the serial monitor.
Thinking of using a different OLED library than Adafruit where it doesn't use so much of SRAM. Maybe you have any idea which one would be the best in this case?

1304 bytes is a lot healthier. 1304 - 1024 = 280 bytes. I would stick with Adafruit.

My "editing" was very cursory. As a general rule, print("message") can safely be put into Flash memory e.g. print(F("message"))

Only you know how your program should behave. So look at the problem area. e.g. what was the last good message. then trace execution from there.

David.

david_prentice:
1304 bytes is a lot healthier. 1304 - 1024 = 280 bytes. I would stick with Adafruit.

My "editing" was very cursory. As a general rule, print("message") can safely be put into Flash memory e.g. print(F("message"))

Only you know how your program should behave. So look at the problem area. e.g. what was the last good message. then trace execution from there.

David.

Yes I forgot to mention, I noticed you haven't changed all of the print( to print(F, When I changed all of the print( and println( to (F the code couldn't compile and returned:
exit status 1
Error compiling for board Arduino Nano.
...C:\Program Files\WindowsApps\ArduinoLLC.ArduinoIDE_1.8.29.0_x86__mdqgnx93n4wtt\hardware\arduino\avr\cores\arduino/WString.h:38:74: error: array must be initialized with a brace-enclosed initializer

#define F(string_literal) (reinterpret_cast<const __FlashStringHelper *>(PSTR(string_literal)))
C:\Users\asadi1\OneDrive - BP\Documents\Arduino\SIM800L_Beginning_4_Afrt_OLED_Updated_by_David\SIM800L_Beginning_4_Afrt_OLED_Updated_by_David.ino:101:52: note: in expansion of macro 'F'

Serial.print(F("AT code is:")); Serial.println(F(ATcode));

What does it mean?

I have edited #5. Please try the new code in #5.

Untested. Because I don't have the same "DS3231.h" library as you.

Thank you David. I tested it and it is the same thing. Will keep trying to make it work.

In the code you've updated there is:
Serial.print(F("SIM Operator: ")); Serial.println(Operator);

Could you please help why there is (F in one and not in the other? I have never used Flash with print function before.

Serial.print("SIM Operator: "); just sends a literal text string.
Serial.println(Operator); sends the value of the variable called Operator.

It is a feature of GCC that it puts "anonymous strings" into SRAM. And prints from SRAM.
Since the strings are anonymous, you can't access them from another part of the program. You certainly can't modify them.

It is sensible to store these "anonymous strings" in PROGMEM. Which is what the F() macro does.

Other compilers are wiser. They recognise that this data is anonymous. And store in Flash automatically.

It is a bit painful to wrap "messages" with F() but it does stop wasteful use of SRAM.
In your case, it should mean that everything works 100%.

I am impressed by your use of the String class methods. They make my head hurt. And you should be careful that you don't concatenate into monster strings.

Google for "anonymous string". I bet there is a good Wikipedia article.

David.

p.s. I would expect the new sketch pasted into #5 will build and run.
If you have errors or Warnings, paste offending lines. Or attach the whole build report.

Hi @david_prentice,
Sorry for not replying for so long. I was busy testing and trying all other OLED libraries available in the manager to find the one that is not as heavy as Adafruits. I found ssOLED library working great for me in this design. It is very simple and doesn't create any buffer (unless you need). It took some time to understand how it works, but it paid back.
Thank you very much for your time, I learned a lot.