1

I wrote this code to control my christmas tree. It takes up the majority of the memory on my Arduino Uno:

Sketch uses 31822 bytes (98%) of program storage space. Maximum is 32256 bytes.
Global variables use 1882 bytes (91%) of dynamic memory, leaving 166 bytes for local variables. Maximum is 2048 bytes.
Low memory available, stability problems may occur.

Does anyone know how I can reduce the memory usage?

Code:

#include <SPI.h>
#include <SdFat.h>
#include <SdFatUtil.h>
#include <SFEMP3Shield.h>

#define TREEONE 3
#define TREETWO 4
#define TREETHREE 5
#define TREEFOUR 10

SdFat sd;
SFEMP3Shield MP3player;

const uint8_t volume = 10; // MP3 Player volume 0=max, 255=lowest (off)
//10 for basement 50 for testing

const uint16_t monoMode = 1;

int song = 3;
int num = 0;
int count = 0;

//put arrays here
byte arrayTree[] = {17,16,9,8,3,2,5,4,17,16,9,8,3, ...etc };

void setup() {
  initSD();
  initMP3Player();

  pinMode(TREEONE, OUTPUT);
  pinMode(TREETWO, OUTPUT);
  pinMode(TREETHREE, OUTPUT);
  pinMode(TREEFOUR, OUTPUT);

  digitalWrite(TREEONE, HIGH);
  digitalWrite(TREETWO, HIGH);
  digitalWrite(TREETHREE, HIGH);
  digitalWrite(TREEFOUR, HIGH);
}

void loop() {
  if(!MP3player.isPlaying()){
    MP3player.playTrack(song);
    MetallicaChristmas();
  }
}

void initSD() {
  if(!sd.begin(SD_SEL, SPI_HALF_SPEED)) 
    sd.initErrorHalt();
  if(!sd.chdir("/")) 
    sd.errorHalt("sd.chdir");
}

void initMP3Player() {
  uint8_t result = MP3player.begin();
  MP3player.setVolume(volume, volume);
  MP3player.setMonoMode(monoMode);
}

void treeFunc() {
    //delay(arrayTimes[i]);
    num = arrayTree[count];

    //TREEONE
    if(num>15){
      if((num%2)==0){
        digitalWrite(TREEONE,HIGH);
      }else{
        digitalWrite(TREEONE,LOW);
      }
    }
    //TREETWO
    if((num%16)>7){
      if((num%2)==0){
        digitalWrite(TREETWO,HIGH);
      }else{
        digitalWrite(TREETWO,LOW);
      }
    }
    //TREETHREE
    if((num%8)>3){
      if((num%2)==0){
        digitalWrite(TREETHREE,HIGH);
      }else{
        digitalWrite(TREETHREE,LOW);
      }
    }
    //TREEFOUR
    if((num%4)>1){
      if((num%2)==0){
        digitalWrite(TREEFOUR,HIGH);
      }else{
        digitalWrite(TREEFOUR,LOW);
      }
    }
  count = count + 1;
}

void MetallicaChristmas()
{
  //event 1
  delay(670);
  treeFunc();
  delay(248);
  treeFunc();
  //event 2
  delay(116);
  treeFunc();
  delay(248);
  treeFunc();
  //event 3
  delay(100);
  treeFunc();
  delay(248);
  treeFunc();
  //event 4
  delay(132);
  treeFunc();
  delay(248);
  treeFunc();
  //event 5
  delay(125);
  treeFunc();
  delay(248);
  treeFunc();
  //event 6

  ...etc.
5
  • I see some ints that could be replaced with byte, that would save a couple of bytes. Other than that, it seems to be the libraries you are using. If you need more room tho, jump to a '1284P processor. 128K of flash, 16k SRAM. I offer boards in several form factors, your code will port right over with the MightyCore add-in to the Arduino IDE. crossroadsfencing.com/BobuinoRev17
    – CrossRoads
    Dec 28, 2018 at 15:25
  • 2
    Please show the full sketch. How long is the arrayTree array? Is every other number 1 less than the previous number? How long is the MetallicaChristmas function? There is a smaller sdfat library, but I don't know if it is compatible with SFEMP3Shield. Read about PROGMEM and struct.
    – Jot
    Dec 28, 2018 at 15:29
  • I think that if you store the delays in an array, just like arrayTree. And use PROGMEM on both arrays your code will become smaller and use less dynamic memory. And also make it easier to read/maintain.
    – Gerben
    Dec 28, 2018 at 15:43
  • Without a full sketch, we can not compile it ourself to see how far we can get to reduce memory usage.
    – Jot
    Dec 28, 2018 at 18:19
  • 1
    O, there it is: arduino.stackexchange.com/questions/60109/…
    – Jot
    Dec 28, 2018 at 20:43

1 Answer 1

3

As well as PROGMEM (as described in the comments), there are a couple of other efficiencies that you can make:

  • A function call is expensive (takes a lot of code space), and you are performing a LOT of them!

    • The repetitious calls to delay() followed by treeFunc() are wasteful. Your commented-out line

      //delay(arrayTimes[i]);
      

      looks like you were going to do the right thing, so I’d restore that (use count instead of i) and put the delay() numbers in a new int arrayTimes[] array.

      PROGMEM this array too, of course!

    • Once you’ve done this, you can remove all the calls to delay(). You’ll be left with nothing but repeated calls to treefunc(), which you can replace with a single loop:

      for (count=0;count<sizeof(arrayTree);++count) {
         treeFunc();
      } // for
      

      Don’t forget to get rid of the count = count + 1; line from treeFunc() - it’s now in the for loop.

  • Also expensive is calling the same function twice except with different parameters in both sides of the if in treeFunc(). Instead of:

    if (<condition>) {
       Function(1);
    } // if
    else {
       Function(0);
    } // else
    

    you can instead do:

    Function(<condition>);
    

    For this to work, you need to know that HIGH has the value 1 and LOW has the value 0 - and that a true condition has the value 1 and a false condition has the value 0.

    So, you need to change the if () slightly:

    digitalWrite(THREEONE, (num%2)>0);
    
  • Finally, the mod % operator itself is very expensive, since it is effectively a division, and the Arduino chip doesn’t know how to divide - so the code to do so is large. But the code you’ve written is using binary arithmetic, which the Arduino can do instantly - you just have to write it as such.

    • Instead of (num%2)>0 use num & B0001.
    • Instead of (num%4)>1 use num & B0010.
    • Instead of (num%8)>3 use num & B0100.
    • Instead of (num%16)>7 use num & B1000.

You’ve probably copied the guts of this code from somewhere else, and while it works it isn’t very efficient. Writing the code as above will greatly reduce your code size, exchanging repeated calls for much smaller PROGMEM arrays.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.