Running out of Memory (maybe)?

Hello,
I'm picking up electronics after 10+ years and need some help with code that seems to be running out of memory.

It will one day be a homemade Shot Timer. A competition device that measures the time between a start signal (sound) and the time a player makes the final shot in a competitive match.

Made on Arduino Uno, with a OLED 1.3 screen (for testing, will upgrade to a bigger screen later on), using a push button to start and stop, and a KY-038 to listen to shots.

The code should store the last 50 and display the results on a screen. And here is where I think I'm having my problems.

I have set a float lapShots[50] to record the time of each shot. But when I upload the code it stops at line 42 o 43 (when the first control sound is made). It never finishes the step function.

If it set a float lapShots[45] instead, I all runs smoothly.

I'm leavin the code here so you can see.

// C++ code
//
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SH110X.h>

#define ALTOLCD 64 //OLED Hight
#define ANCHOLCD 128 //OLED Width
#define OLED_RESET 4 //Oled Reset

Adafruit_SH1106G lcd = Adafruit_SH1106G(ANCHOLCD, ALTOLCD, &Wire, OLED_RESET);

#define buzzerpin 5 //Pin connected to buzzer
#define startpin 3 //Pin connected to start, strop Button
#define shotpin 2 //Pin connecte to KY-038
#define debouncedelay 50 //deboncedelay


 float lapShots[45]  = { 0 }; //Var to store results (shots fired in this lap)
unsigned long lapStarted = 0; //Var to keep track of when the lap started
int shots = 0; //Var to keep track of how many shots where fired in this lap
bool shotDetected = false; //Var to set as true when a shot is detected and start the "shot detected" function
bool startStop = false; //Var to set as true when the start/stop button is presed and start the "start/stop" function
char modeRuning = 'w'; //Var to keep track of what mode the device is in
bool startBtnLast = true; //Var used to for debouncing
bool startBtnState = true; //Var used to for debouncing
unsigned long lastDebounceTime = 0; //Var used for debouncing


void setup() {
  pinMode(buzzerpin, OUTPUT); //Set pin 5 to buzzer
  pinMode(startpin, INPUT_PULLUP);  //Set Pin 3 to read pull up
  pinMode(shotpin, INPUT_PULLUP);   //Set Pin 2 to read pull up
  pinMode(LED_BUILTIN, OUTPUT); //Will be used in the future for a status led
  attachInterrupt(digitalPinToInterrupt(shotpin), shotChange, CHANGE); //Interrupt to avoid missing a shot
  
  //Reset Vars - had issued if I didn't
  startStop = false;
  shotDetected = false;

  //Tone to debug the start of LCD config
  tone(buzzerpin, 4186, 50);
  //Start LCD & Display Brand
  Wire.begin();
  lcd.begin(0x3C, true);
  lcd.clearDisplay();
  lcd.setTextColor(SH110X_WHITE);
  lcd.setCursor(51, 16);
  lcd.setTextSize(2);
  lcd.println("SE");
  lcd.setCursor(3, 32);
  lcd.println("SHOT TIMER");
  lcd.display();
  //Tone to signal config is finished
  delay(100);
  tone(buzzerpin, 4186, 50);
}

void loop() {

  //Check if StartStop was presed
  bool startBtnRead = digitalRead(startpin);
  if (startBtnRead != startBtnLast)
    lastDebounceTime = millis();

  if ((millis() - lastDebounceTime) > debouncedelay) {
    if (startBtnRead != startBtnState) {
      if (startBtnState == true)
        startStop = true; //Set var so as to activate the start/stop functions
      startBtnState = startBtnRead;
    }
  }
  startBtnLast = startBtnRead;

  //If Start Btn is preseed call function
  if (startStop == true && modeRuning != 'l') { 
    startLap(); 
    Serial.println("Start lap");
    startStop = false;
  } else if (startStop == true && modeRuning == 'l') {
    stopLap();
    startStop = false;
    Serial.println("Stop lap");
  }

  //If Shot is sensed call function
  if (shotDetected && modeRuning == 'l') {
    shot();
    shotDetected = false;
  }
}

void shotChange() {
  if (modeRuning == 'l') {
    shotDetected = true;
    Serial.println("Shot!");
  }
}

void lapChange() {
  startStop = true;
  Serial.println("Btn Press");
}

//Shot detected function
void shot() {
  lapShots[shots] = ((float)millis() - (float)lapStarted) / (float)1000;  //Convert to Sec

  //Missing LCD Code

  shots++;
  if (shots == 50)
    shots = 1;
  delay(10);
}


//New lap starts
void startLap() {
  //Set lapRuning to true
  modeRuning = 'l';

  //Missing LCD Code

  //Capture lap Start Millis
  lapStarted = millis();
  //Reset Number of Shots and clear lap array
  shots = 0;
  memset(lapShots, 0, sizeof(lapShots));
  //Sound Start Tone
  tone(buzzerpin, 4186, 500);
}


void stopLap() {
  //Set mode to result
  modeRuning = 'r';
  //Sound Stop Tone
  tone(buzzerpin, 4186, 150);

  //Missing LCD Code
}
type or paste code here

Probably indicative but doesn't the IDE then give you some advice to that effect?

Does that float really need to be a float?

Since you appear to be using only text on the display, you should be a lot better off using the Adafruit ascii libraries.

Hi, thanks for the idea on changing libraries. I will try that.

IDE says 40% maybe close to 50% on used memory.

I've changed the float for a long and used code to print the result with decimals on tje screen. It had no effect.

Finally, I've added more code (just printed some other text on the screen), and has to make that array even smaller. Down to lapShots[20] now.

I'm not familiar with that particular display, but in general a 128 x 64 OLED display will need a 1024 byte buffer when using the Adafruit library. That buffer is not shown in the ram memory usage displayed by the Arduino IDE, because it is allocated at run-time.

Have a look at the u8g2 library, it has options to use the full buffer (same size as Adafruit's library), a page buffer (considerably smaller), or no buffer if you can accept fixed-size text-only display (see the u8x8 example in the u8g2 library).

Could be memory. As @david_2018 says, 1024 bytes might be dynamically allocated for the display. The compiler doesn't see it. That's 50% of an UNO's RAM right there. Add the 40-50% that the compiler does know about and you're getting close.

So, why not just switch to a platform with more resources now? If the problem goes away, it likely was memory usage. If not, then you have some more debugging to do.

So it would seem I have to try some other library.

I'd rather not change the Uno unless it's 100% necessary.

If I make this a mass production product I don't want to make costs go up.

Thanks

If you move to a Teensy LC or Teensy 3.2, you'll have more resources and a more powerful processor. Both boards are also considerably smaller than an Uno. Oh and they both cost less than an Uno. They're also better suited for use in a product where you won't be depending on breadboard-type interconnects.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.