Low memory available, stability problems may occur.

Hi guys, wondering if anyone can help me optimize this code. I'm using an Arduino UNO R3.

#define LOG_OUT 0 // use the log output function
#define FFT_N 256 // set to 256 point fft
#define LIN_OUT 1

#include <LedControl.h>
#include <FFT.h>

int DIN = 12;
int CS = 11;
int CLK = 10;
//int delayTime = 5;
float factors[8] = {1, 1.1, 1.35, 1.45, 1.55, 1.7, 1.9, 2.1};       //factors to increase the height of each column
unsigned char hs[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};              //height of each column



LedControl lc = LedControl(DIN, CLK, CS, 0);

void setup() {
  lc.shutdown(0, false);      //The MAX72XX is in power-saving mode on startup
  lc.setIntensity(0, 0);     // Set the brightness to maximum value
  lc.clearDisplay(0);         // and clear the display
  TIMSK0 = 0; // turn off timer0 for lower jitter
  ADCSRA = 0xe5; // set the adc to free running mode
  ADMUX = 0x40; // use adc0
  DIDR0 = 0x01; // turn off the digital input for adc0
  Serial.begin(115200); // use the serial port
}

unsigned char borders[9] = {0, 15, 31, 47, 63, 79, 95, 111, 127};   //borders of the frequency areas

void setColumn(int column, unsigned char height) {
  // maps height from 0 to 255 to 0 to 8
  unsigned char h = (unsigned char) map(height, 0, 255, 0, 8);
  // apply multipliers to heights
  h = (unsigned char)(h * factors[column]);
  // if less than 0,
  if (h < hs[column]) {
    // goes from 0 -> 255
    hs[column]--;
  } else if (h > hs[column]) {
    hs[column] = h;
  }
  // light up LEDs
  for (unsigned char y = 0; y < 8; y++) {
    if (hs[column] > y) {
      // addr then col then row
      lc.setLed(0, column, y, true);
    } else {
      lc.setLed(0, column, y, false);
    }

  }
}

void loop() {
  while (1) { // reduces jitter
    cli();  // UDRE interrupt slows this way down on arduino1.0
    for (int i = 0 ; i < 512 ; i += 2) { // save 256 samples
      while (!(ADCSRA & 0x10)); // wait for adc to be ready
      ADCSRA = 0xf5; // restart adc
      byte m = ADCL; // fetch adc data
      byte j = ADCH;
      int k = (j << 8) | m; // form into an int
      k -= 0x0200; // form into a signed int
      k <<= 6; // form into a 16b signed int
      fft_input[i] = k; // put real data into even bins
      fft_input[i + 1] = 0; // set odd bins to 0
    }
    fft_window(); // window the data for better frequency response
    fft_reorder(); // reorder the data before doing the fft
    fft_run(); // process the data in the fft
    fft_mag_lin(); // take the output of the fft
    sei();
    // for each column
    for (int i = 0; i < 8; i++) {
      // find the maximum value within the specified frequency borders
      int maxVal = 0;
      for (int j = borders[i]; j < borders[i + 1]; j++) {
        if ((unsigned char) fft_lin_out[j] > maxVal) {
          maxVal = (unsigned char) fft_lin_out[j];
        }
      }
      // determine height and light up LED
      setColumn(i, maxVal);
      Serial.println(maxVal);
    }
  }
}

Error message is:

Sketch uses 7718 bytes (23%) of program storage space. Maximum is 32256 bytes.
Global variables use 1606 bytes (78%) of dynamic memory, leaving 442 bytes for local variables. Maximum is 2048 bytes.
Low memory available, stability problems may occur.

Post a link to where you got the LedControl and FFT libraries library from. Please use the chain links icon on the toolbar to make it clickable. Or if you installed it using Library Manger (Sketch > Include Library > Manage Libraries) then say so and state the full name of the library.

I don't have any experience with the FFT library (or even know which you're using since you didn't provide that information), but I suspect the value of FFT_N will affect memory usage.

Which version of the Arduino AVR Boards are you using (as shown at Tools > Board > Boards Manager)?

You have declared 3 integers, DIN, CS and CLK.
Would #define DIN 12 etc work? Saves 6 byte....

pert:
Post a link to where you got the LedControl and FFT libraries library from. Please use the chain links icon on the toolbar to make it clickable. Or if you installed it using Library Manger (Sketch > Include Library > Manage Libraries) then say so and state the full name of the library.

The FFT library is from openmusiclabs and can be found here.

The LedControl library is to control an 8x8 MAX7221 LED matrix and can be found here.

pert:
I don't have any experience with the FFT library (or even know which you're using since you didn't provide that information), but I suspect the value of FFT_N will affect memory usage.

It definitely does. Swapping it to 128 reduces the dynamic memory ~30%, but I pay for it in terms of quality and would prefer not to if avoidable.

pert:
Which version of the Arduino AVR Boards are you using (as shown at Tools > Board > Boards Manager)?

I'm using version 1.6.21. Thanks for all your help.

Railroader:
You have declared 3 integers, DIN, CS and CLK.
Would #define DIN 12 etc work? Saves 6 byte....

It did work, but did memory usage was identical.

Edit: Added response to railroader

I was able to 24 bytes of SRAM by changing factors[] to an unsigned char:

unsigned char factors[8] = {100, 110, 135, 145, 155, 170, 190, 210};       //factors to increase the height of each column

...

h = (unsigned char)((h * factors[column])/100);

There are a few places where you use a larger type than necessary for local variables:

void setColumn(int column, unsigned char height)
for (int i = 0; i < 8; i++) {
int maxVal = 0;

The concern with using 78% of dynamic memory for globals is that doesn't leave much margin for your local variables. If it wasn't for that, you could go up to 100% usage for globals without a problem. So even though using the correct type for local variables won't change the global number displayed by the Arduino IDE, it certainly addresses the true problem.

Do you need the Serial output? Getting rid of that saves 177 bytes of SRAM. If you only need it for debugging you could later disable it. If dynamic memory shortage is a problem while you still need it then you could temporarily reduce FFT_N.

Now I know your problem is only with SRAM but if you're interested in reducing flash usage here are a couple things you could do:

Update to Arduino IDE 1.8.6 to save 132 bytes.

Add this line to your sketch to save 38 bytes at the cost of losing the worthless serialEvent() function:

void serialEventRun() {}

erosten:
It did work, but did memory usage was identical.

The only thing changing those to macros does is makes your code harder to troubleshoot. I would add the const keyword but that won't change memory usage, it only provides a helpful compilation error if you have a bug in your code that modifies a variable that was never meant to be modified.