How to reduce the size of a sketch if it’s too big for Arduino UNO

Hi all, i'm try to upload the code to Arduino UNO but got warning mean the sketch is too big. I don't know how to reduce the sketch. Please help me to solve this problem

Waring message
"text section exceeds available space in boardSketch uses 17072 bytes (52%) of program storage space. Maximum is 32256 bytes.
Global variables use 2446 bytes (119%) of dynamic memory, leaving -398 bytes for local variables. Maximum is 2048 bytes.
Sketch too big; see https://support.arduino.cc/hc/en-us/articles/360013825179 22 for tips on reducing it."

#define Drum_map 0


// ADD2 MAP
byte Note[2][21] = {{
    36, 38, 37, 42, 54, 49, 48, 71, 69, 67, 65,
    60, 62, 61, 77, 79, 81, 89, 91, 93
  }
};


//sensitivity, threshold, scan time, mask time, note map
uint8_t KICK[5] = {100, 10, 10, 30, Note[Drum_map][0]};
uint8_t SNARE[9] = {100, 10, 30, 10, 10, 3, Note[Drum_map][1], Note[Drum_map][2], Note[Drum_map][3]};
uint8_t HIHAT[6] = {100, 10, 10, 30, Note[Drum_map][4], Note[Drum_map][5]};
uint8_t HIHAT_PEDAL[5] = {90, 30, 70, 90, Note[Drum_map][6]};
uint8_t TOM1[5] = {100, 55, 25, 30, Note[Drum_map][7]};
uint8_t TOM2[5] = {100, 55, 25, 30, Note[Drum_map][8]};
uint8_t TOM3[5] = {100, 55, 25, 30, Note[Drum_map][9]};
uint8_t TOM4[5] = {100, 55, 25, 30, Note[Drum_map][10]};
uint8_t RIDE[9] = {100, 10, 10, 30, 4, 9, Note[Drum_map][11], Note[Drum_map][12], Note[Drum_map][13]};
uint8_t CRASH[9] = {100, 10, 10, 30, 4, 9, Note[Drum_map][14], Note[Drum_map][15], Note[Drum_map][16]};
uint8_t CYM1[5] = {100, 10, 10, 30, Note[Drum_map][17]};
uint8_t CYM2[5] = {100, 10, 10, 30, Note[Drum_map][18]};
uint8_t CHINA[5] = {100, 10, 10, 30, Note[Drum_map][19]};


/////////////////////////////////////////////////////////////////////////////////////

#include <hellodrum.h>
#include <LiquidCrystal_I2C.h>
#include <MIDI.h>
MIDI_CREATE_DEFAULT_INSTANCE();

LiquidCrystal_I2C lcd(0x27, 16, 2);

HelloDrumMUX_4067 mux(2, 3, 4, 5, 0);

//name pad and define MUX pin
HelloDrum kick(0);
HelloDrum snare(1, 2);
HelloDrum hihat(4);
HelloDrum hihatPedal(3);
HelloDrum tom1(5);
HelloDrum tom2(6);
HelloDrum tom3(7);
HelloDrum tom4(12);
HelloDrum ride(8, 9);
HelloDrum crash(10, 11);
HelloDrum cym1(13);
HelloDrum cym2(14);
HelloDrum china(15);


HelloDrumButton button(8, 9, 10, 11, 12); 
void setup()
{
  lcd.init(); // initialize the lcd
  lcd.backlight();  //open the backlight

  MIDI.begin();
  Serial.begin(38400);


  kick.settingName("KICK");
  snare.settingName("SNARE");
  hihat.settingName("HIHAT");
  hihatPedal.settingName("HIHAT PEDAL");
  tom1.settingName("TOM 1");
  tom2.settingName("TOM 2");
  tom3.settingName("TOM 3");
  tom4.settingName("TOM 4");
  ride.settingName("RIDE");
  crash.settingName("CRASH");
  cym1.settingName("CYMBAL 1");
  cym2.settingName("CYMBAL 2");
  china.settingName("CHINA");
  //splash.settingName("SPLASH");


  kick.loadMemory();
  snare.loadMemory();
  hihat.loadMemory();
  hihatPedal.loadMemory();
  tom1.loadMemory();
  tom2.loadMemory();
  tom3.loadMemory();
  tom4.loadMemory();
  ride.loadMemory();
  crash.loadMemory();
  cym1.loadMemory();
  cym2.loadMemory();
  china.loadMemory();


  lcd.clear();
  lcd.setCursor(1, 0);
  lcd.print("Hello world!");
  lcd.setCursor(0, 1);
  lcd.print("Hello drum!");
}

void loop()
{
  /////////// LCD & SETTING MODE /////////////


  bool buttonPush = button.GetPushState();
  bool editStart = button.GetEditState();
  bool editDone = button.GetEditdoneState();
  bool display = button.GetDisplayState();

  const char *padName = button.GetPadName();
  const char *item = button.GetSettingItem();
  int settingValue = button.GetSettingValue();
  int velocity = button.GetVelocity();
  const char *hitPad = button.GetHitPad();

  button.readButtonState();

  kick.settingEnable();
  snare.settingEnable();
  hihat.settingEnable();
  hihatPedal.settingEnable();
  tom1.settingEnable();
  tom2.settingEnable();
  tom3.settingEnable();
  tom4.settingEnable();
  ride.settingEnable();
  crash.settingEnable();
  cym1.settingEnable();
  cym2.settingEnable();
  china.settingEnable();


  if (buttonPush == true)
  {
    lcd.clear();
    lcd.print(padName);
    lcd.setCursor(0, 1);
    lcd.print(item);
    lcd.setCursor(13, 1);
    lcd.print(settingValue);
  }

  if (editStart == true)
  {
    lcd.clear();              // clear display
    lcd.print("EDIT START");  // print message at (0, 0)
    delay(500);               // display the above for 0.5 seconds
    lcd.clear();              // clear display
    lcd.print(padName);       // print message at (0, 0)
    lcd.setCursor(0, 1);      // move cursor to   (0, 1)
    lcd.print(item);          // print message at (0, 01)
    lcd.setCursor(13, 1);     // move cursor to   (13, 1)
    lcd.print(settingValue);  // print message at (13, 1)
  }

  if (editDone == true)
  {
    lcd.clear();
    lcd.print("EDIT DONE");
    delay(500);
    lcd.clear();
    lcd.print(padName);
    lcd.setCursor(0, 1);
    lcd.print(item);
    lcd.setCursor(13, 1);
    lcd.print(settingValue);
  }


  mux.scan();
  kick.singlePiezoMUX();
  snare.dualPiezoMUX();
  hihat.HHMUX();
  hihatPedal.TCRT5000MUX();
  tom1.singlePiezoMUX();
  tom2.singlePiezoMUX();
  tom3.singlePiezoMUX();
  tom4.singlePiezoMUX();
  ride.cymbal3zoneMUX();
  crash.cymbal2zoneMUX();
  cym1.singlePiezoMUX();
  cym2.singlePiezoMUX();
  china.singlePiezoMUX();


  //Kick
  if (kick.hit == true)
  {
    MIDI.sendNoteOn(KICK[4], kick.velocity, 10); //(note, velocity, channel)
    MIDI.sendNoteOff(KICK[4], 0, 10);
  }

  //SNARE HEAD
  if (snare.hit == true)
  {
    MIDI.sendNoteOn(SNARE[6], snare.velocity, 10); //(note, velocity, channel)
    MIDI.sendNoteOff(SNARE[6], 0, 10);
  }
  //SNARE RIMSHOT
  else if (snare.hitRim == true)
  {
    if (snare.velocity > 60)
    {
      MIDI.sendNoteOn(SNARE[7], snare.velocity, 10); //(note, velocity, channel)
      MIDI.sendNoteOff(SNARE[7], 0, 10);
    }
    else
    {
      MIDI.sendNoteOn(SNARE[8], snare.velocity * 2, 10); //(note, velocity, channel)
      MIDI.sendNoteOff(SNARE[8], 0, 10);
    }
  }

  //HiHat
  if (hihat.hit == true)
  {
    //check open or close
    //1.open
    if (hihatPedal.openHH == true)
    {
      MIDI.sendNoteOn(HIHAT[4], hihat.velocity, 10); //(note, velocity, channel)
      MIDI.sendNoteOff(HIHAT[4], 0, 10);
    }
    //2.close
    else if (hihatPedal.closeHH == true)
    {
      MIDI.sendNoteOn(HIHAT[5], hihat.velocity, 10); //(note, velocity, channel)
      MIDI.sendNoteOff(HIHAT[5], 0, 10);
    }
  }

  //when pedal is closed, TCRT5000
  if (hihatPedal.hit == true)
  {
    MIDI.sendNoteOn(HIHAT_PEDAL[4], hihatPedal.velocity, 10); //(note, velocity, channel)
    MIDI.sendNoteOff(HIHAT_PEDAL[4], 0, 10);
  }

  //sending state of pedal with controll change
  if (hihatPedal.moving == true)
  {
    MIDI.sendControlChange(4, hihatPedal.pedalCC, 10);
  }

  //Tom 1
  if (tom1.hit == true)
  {
    MIDI.sendNoteOn(TOM1[4], tom1.velocity, 10); //(note, velocity, channel)
    MIDI.sendNoteOff(TOM1[4], 0, 10);
  }

  //Tom 2
  if (tom2.hit == true)
  {
    MIDI.sendNoteOn(TOM2[4], tom2.velocity, 10); //(note, velocity, channel)
    MIDI.sendNoteOff(TOM2[4], 0, 10);
  }

  //Tom 3
  if (tom3.hit == true)
  {
    MIDI.sendNoteOn(TOM3[4], tom3.velocity, 10); //(note, velocity, channel)
    MIDI.sendNoteOff(TOM3[4], 0, 10);
  }

  //Tom 4
  if (tom4.hit == true)
  {
    MIDI.sendNoteOn(TOM4[4], tom4.velocity, 10); //(note, velocity, channel)
    MIDI.sendNoteOff(TOM4[4], 0, 10);
  }

  //Ride Bow
  if (ride.hit == true)
  {
    MIDI.sendNoteOn(RIDE[6], ride.velocity, 10); //(note, velocity, channel)
    MIDI.sendNoteOff(RIDE[6], 0, 10);
  }

  //Ride Edge
  else if (ride.hitRim == true)
  {
    MIDI.sendNoteOn(RIDE[7], ride.velocity, 10); //(note, velocity, channel)
    MIDI.sendNoteOff(RIDE[7], 0, 10);
  }

  //Ride Cup
  else if (ride.hitCup == true)
  {
    MIDI.sendNoteOn(RIDE[8], ride.velocity, 10); //(note, velocity, channel)
    MIDI.sendNoteOff(RIDE[8], 0, 10);
  }

  //Ride Choke
  if (ride.choke == true)
  {
    MIDI.sendPolyPressure(RIDE[6], 127, 10);
    MIDI.sendPolyPressure(RIDE[7], 127, 10);
    MIDI.sendPolyPressure(RIDE[8], 127, 10);
    MIDI.sendPolyPressure(RIDE[6], 0, 10);
    MIDI.sendPolyPressure(RIDE[7], 0, 10);
    MIDI.sendPolyPressure(RIDE[8], 0, 10);
  }

  //Crash Bow
  if (crash.hit == true)
  {
    MIDI.sendNoteOn(CRASH[6], crash.velocity, 10); //(note, velocity, channel)
    MIDI.sendNoteOff(CRASH[6], 0, 10);
  }

  //Crash Edge
  else if (crash.hitRim == true)
  {
    MIDI.sendNoteOn(CRASH[7], crash.velocity, 10); //(note, velocity, channel)
    MIDI.sendNoteOff(CRASH[7], 0, 10);
  }

  //Crash Cup
  else if (crash.hitCup == true)
  {
    MIDI.sendNoteOn(CRASH[8], crash.velocity, 10); //(note, velocity, channel)
    MIDI.sendNoteOff(CRASH[8], 0, 10);
  }

  //Crash Choke
  if (crash.choke == true)
  {
    MIDI.sendPolyPressure(CRASH[6], 127, 10);
    MIDI.sendPolyPressure(CRASH[7], 127, 10);
    MIDI.sendPolyPressure(CRASH[8], 127, 10);
    MIDI.sendPolyPressure(CRASH[6], 0, 10);
    MIDI.sendPolyPressure(CRASH[7], 0, 10);
    MIDI.sendPolyPressure(CRASH[8], 0, 10);
  }

  //Cymbal
  if (cym1.hit == true)
  {
    MIDI.sendNoteOn(CYM1[4], cym1.velocity, 10); //(note, velocity, channel)
    MIDI.sendNoteOff(CYM1[4], 0, 10);
  }

  if (cym2.hit == true)
  {
    MIDI.sendNoteOn(CYM2[4], cym2.velocity, 10); //(note, velocity, channel)
    MIDI.sendNoteOff(CYM2[4], 0, 10);
  }

  if (china.hit == true)
  {
    MIDI.sendNoteOn(CHINA[4], china.velocity, 10); //(note, velocity, channel)
    MIDI.sendNoteOff(CHINA[4], 0, 10);
  }
}

Get rid of stuff or get a bigger box.

One of the main reasons I use ESP32's. They are a bigger box. If I need more I use BeagleBone Blacks.

So to get a stable, reliable program, you would need to reduce memory use by some 45%. Tough call.

Are some of your global variables constant? Could you put them into PROGMEM instead?

If I analyse correct

You need 7 IO-pins 2 IO-pins for I2C-LCD and 5 for DrumMux
you could take a Seeeduino XIAO for this project
|Flash Memory|256KB|

|SRAM|32KB|
|Digital I/O Pins|11|
|Analog I/O Pins|11|
|I2C interface|1|

32 kB RAM on XIAO compared to 2 KB on Uno

best regards Stefan

1 Like

Do you mean add Seeeduino XIAO to Arduino UNO, or Seeeduino XIAO instead of arduino?
But it has other pin for 5 buttons and other port.

Chop main code and major functions into sections. Remove sections. Find where the biggest gain in memory occurs.

Sorry I'm poor in programming, how to chop main code and major functions into sections?

Agreed, the SAMD21 varient is an excellant microcontrollers for the Arduino IDE.

Very small, low cost, plenty of memory, RTC, and 5uA deep sleep current if you remove the rather pointless (IMHO) green power LED.

Well there is a point, it can be done, but if you dont know how, its a problem and time consuming.

If you were trapped on Mars, all alone, and the only way of communicating back to Earth was to cut the memory of the needed program so it fitted on the only micro you had, a UNO, it might be worth the effort.

But with such a significant memory reduction required, unless there is a glaringly obvious issue, most all experienced Arduinoists, would I assume, take the quick option and use an Arduino suited to the task.

Start with your global variables (the DRUM things). They take memory for the life of the sketch. If you can move the global variables into local functions, then the same global/lifelong variables become local variables and are born and die as each function is entered and exited. The variables still use memory, but the memory space is returned to general use when the local function is exited.

For example, the LCD (and more) function can be moved out of void loop() and into its own function. When the LCD function is needed, call the LCD function from inside void loop()

And, just like Jason Borne, if you want to get it done, you can and will, even if you must eat what grows from your own waste. So, don't flush this yet! Programming is no different from any job you have done, and I must say, most of my programmer colleagues are good musicians. The art and science of programming go hand in hand.

Seeeduino XIAO instead of arduino

The code you have posted just uses 7 IO-pins.
Except power and ground, except USB-cable:
How many wires are connected to the Arduino-Unos IO-pins?

Best thing would be to post a picture where it is easy to see how many wires are connected to IO-pins D2,D3.....D13 and A0,A1,A2,...A6

Yes I tried to upload the code without LCD code, it complete and no error warn. But it got warning when add LCD and buttons code.

@willtcs
Yes, that will happen when cutting parts out. You are looking for memory usage. Now, if you can successfully move that LCD code to a function, it should compile without warnings and will show you any memory saving.

Moving (sensitivity, threshold, scan time, mask time, note map) to be inside void setup() and void loop() saved a few (4%) global bytes

Global variables use 2368 bytes (115%) of dynamic memory, leaving -320 bytes for local variables. Maximum is 2048 bytes.

Then... moving HelloDrum xyz(pin); definitions into void setup() and void loop() saved a bit more... now, only compiled uses only 66% dynamic, with 694 bytes for variables.

Global variables use 1354 bytes (66%) of dynamic memory, leaving 694 bytes for local variables. Maximum is 2048 bytes.

I think you can do it.

Why? We can't see the complete sketch, but if we're talking only about required pins, that count totals to 14, right? IMHO as far as I can see, even keeping D0 and D1 reserved for serial debugging, Arduino UNO offers 12 digital pins (D2-D13) plus 6 analog (A0-A5) that can also be defined as digital, so the total is up to 18 digital pins and with this 14 pins requirement he can still use UNO. Right?

From which detail you count up to 14?
... looked up the sketch once again
ah ! here !

HelloDrumButton button(8, 9, 10, 11, 12); 

OK I understand. Then indeed a Seeeduino XIAO has too less IO-pins
So maybe something linke that?
https://www.ebay.de/itm/164643396466
best regards Stefan

Or maybe;

2 IO-pins for I2C-LCD and 5 for DrumMux = 7.

depending what the purpose of theese buttons is

HelloDrumButton button(8, 9, 10, 11, 12); 

It might be possible to use an I2C-IO-expander for these buttons.
Are this really manual pushed buttons or is this some kind of drum-sensor and just called "button" which would be a confusing name

If you switch processors, be sure you don't care that another might use 3.3 volt logic, not 5 votes like the UNO.

It does not present an unsolvable problem, just a PITA challenge if you have a bunch of 5 volt stuff hooked up.

a

I got it down to 66%. Just needs testing.