Any way to reduce my sketch size?

I wrote some code that has a couple of led functions that will be put in a speaker. Since the audio portion is all analog I didn’t need much memory to run the leds and was fighting for space, so I have a adafruit trinket with roughly 5,300 bytes of memory and my code is taking up 103% right now.

Any ideas to trim this down a bit are appreciated!

  • all of the variables called bass or vol take a line in from the amp and average it and then send audio reactivity to the leds

  • the parts where it says logic were to artificially slow down how fast the hue changes because 1 is added to s1val every loop. I’m sure there has to be a better way to do this I just can’t think of one

#include "OneButton.h"
#include "FastLED.h"
#define NUM_LEDS 8

#define DATA_PIN 4
CRGB leds[NUM_LEDS];

/////////////// Switch 1

int Fader =  0;
int Dimmer = 4;
int S1Val =  0;
int S2Val =  0;
int buttonState;
int Logic =  1;
int linenew;
int line;
int lineavg;
int linecounter;
int bassvol;


OneButton button(3, true);

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

void setup() {

  button.attachDoubleClick(doubleclick);

  pinMode(2, INPUT);
  //line
  pinMode(3, INPUT);
  pinMode(4, OUTPUT);

  FastLED.addLeds<WS2811, DATA_PIN, GRB>(leds, NUM_LEDS);

  START();
  delay(800);

}

void loop() {

  EVERY_N_MILLISECONDS(10) {
    button.tick();
  }

  EVERY_N_SECONDS(1) {
    line = line + analogRead(2);
    linecounter++;
  }

  SWITCH1();

  buttonState = digitalRead(3);

  if (Fader == 0) {
    S1Val = S1Val;
  }
  if (Fader == 1 && Logic == 0) {
    S1Val++;
  }

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

  if (Fader == 2) {


    if (linecounter > 9) {
      lineavg = line / 10;
      line = 0;
      linecounter = 0;
    }

    bassvol = analogRead(2);

    if (bassvol > lineavg + 50) {
      linenew = 240;
    }
    if (line < lineavg) {
      linenew = linenew - 10;
    }
    if (linenew < 0) {
      linenew = 0;
    }

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

    S2Val = linenew;
    EVERY_N_MILLISECONDS(10) {
      S1Val++;

      CHSV color = CHSV(S1Val, 255, linenew);
      fill_solid(leds, NUM_LEDS, color);
      FastLED.show();
    }
  }

  EVERY_N_MILLISECONDS(3) {
    Logic = 1;
  }

  EVERY_N_MILLISECONDS(20) {
    Logic = 0;
  }

  ///////////////////////// HSV hue switcher


  CHSV color = CHSV(S1Val, 255, S2Val);
  fill_solid(leds, NUM_LEDS, color);
  FastLED.show();


  ////////////////////////// resets hue value

  SWITCH1RESET();
}

/////////////////////////// Startup Void

void START()
{
  fill_solid(leds, NUM_LEDS, CRGB(0, 100, 0));
  FastLED.show();
  delay(100);
  fill_solid(leds, NUM_LEDS, CRGB(0, 0, 0));
  FastLED.show();
  delay(100);
  fill_solid(leds, NUM_LEDS, CRGB(0, 100, 0));
  FastLED.show();
  delay(100);
  fill_solid(leds, NUM_LEDS, CRGB(0, 0, 0));
  FastLED.show();
}

//////////////////////////// VOIDS

void SWITCH1RESET()
{ if (S1Val > 255) {
    S1Val = 0;
  }
}

void SWITCH1()
{
  if (buttonState == 1 && Logic == 0) {
    S1Val++;
  }
}

void doubleclick()
{
  S1Val = S1Val - 20;
  Dimmer++;

  if (Dimmer == 0) {
    S2Val = 0;
  }
  if (Dimmer == 1) {
    S2Val = 90;
  }
  if (Dimmer == 2) {
    S2Val = 240;
  }
  if (Dimmer == 3) {
    Fader = 1;
  }
  if (Dimmer == 4) {
    Fader = 2;
  }
  if (Dimmer == 5) {
    S1Val = 0;
    S2Val = 0;
    Fader = 0;
    Dimmer = 0;
  }
}

how about uploading without the bootloader ? as in this thread

Maybe get rid of OneButton.h

Add this to save 24 bytes of program memory:

// Defining an empty serialEventRun() in the sketch overrides the version in the core and saves some bytes of program memory and makes the loop() run a bit faster.
// The only drawback is the loss of the serialEvent() feature: https://www.arduino.cc/en/Reference/SerialEvent
void serialEventRun() {}

Since you’re not using serialEvent(), it does no harm.

Change all your global variables except line and bassvol to byte to save 220 bytes of program memory and 9 bytes of dynamic memory. This means you can get rid of some pointless code:

  if (linenew < 0) {
      linenew = 0;
    }
void SWITCH1RESET()
{ if (S1Val > 255) {
    S1Val = 0;
  }
}

I didn’t look super carefully at the code so you should verify there will be no problems from changing these types. This will need to be fixed:

      if (line < lineavg) {
        linenew = linenew - 10;
      }

Use switch/case in doubleclick to save 2 bytes of program memory:

switch (Dimmer) {
    case 0:
      S2Val = 0;
      break;
    case 1:
      S2Val = 90;
      break;
    case 2:
      S2Val = 240;
      break;
    case 3:
      Fader = 1;
    case 4:
      Fader = 2;
      break;
    case 5:
      S1Val = 0;
      S2Val = 0;
      Fader = 0;
      Dimmer = 0;
      break;
  }

doesn’t the adafruit trinket have an ATtiny85 on-board, so 8K of flash ?

J-M-L: doesn't the adafruit trinket have an ATtiny85 on-board, so 8K of flash ?

yes but the bootloader takes up the impressive 2.7K

#define NUM_LEDS 8

:o

Thank you for the suggestions. I got it down to a size that will work! Shannon would you mind explaining what the serialEventRun does exactly? I can't find much info on it.

Thanks!

Shannon Is not someone’s pseudo in this list - it’s a “title” granted by the forum based on number of posts or something. For example you are a “Newbie” and your pseudo is C_Laughrey

I assume your question was for Pert

C_Laughrey: Shannon would you mind explaining what the serialEventRun does exactly? I can't find much info on it.

It's a wrapper for this... https://www.arduino.cc/en/Reference/SerialEvent

Do not use the "EVERY_N_MILLISECONDS" macro, maybe even get rid of FastLED altogether.

I rather like being called "Shannon". Unfortunately I won't have that pleasure much longer, and I've never seen anyone mistakenly called "Brattain" here. However, it could be confusing if there were two Shannon members in the thread so pert is probably better.

Coding Badly recently pointed out in another thread an alternative to my serialEventRun trick by wrapping all the code in your loop function in this:

while (true) {
  // your loop code here
}

After that, you can remove the serialEventRun code I told you to add. I haven't checked it with your code, but in my tests it saved an extra 2 bytes of program memory compared to the serialEventRun trick.

I'm glad to hear that you got the size down small enough! It might still be useful to get it down even smaller in case you later want to add some features. Some other forum members may still have suggestions for how you can do this. In order to facilitate that, you should post your updated code in a reply here.

Your variable Logic only has 2 values, this should be a bool rather than an int.

I believe buttonState can also be set to a bool. Someone correct me if I'm wrong, but if you write a non-zero int to a bool, it will return true. Since digitalRead returns either 1 or 0, this will lead to the boolean value being true when digitalRead returns a 1, and false when it returns a 0.

It’s not good practice to assume you can do boolean operations with HIGH and LOW (though this is done often enough). There’s no guarantee of it working. For a real-life example of this being a bad idea, see: https://github.com/arduino/ArduinoCore-API/issues/25
I don’t think that will save any memory anyway.

I would second the suggestion of ditching the 2.7k bootloader of the trinket and just using an attiny85 without the VUSB bootloader and programming it with an ISP programmer instead - then you get the full 8k, My ATTinyCore (https://github.com/SpenceKonde/ATTinyCore )also has a serial bootloader (use with external USB-serial adapter) that takes up IIRC 640 bytes of flash, if you for some reason don't like ISP programming (maybe you have other things on the ISP pins that would interfere, or something)

Boolean variables still take up the full byte - you don't save anything by using boolean instead of byte (though you do save something by not using ints for things with boolean values)

Here’s a list of your biggest functions:

000013d2 0000004a T delay
00001386 0000004c T micros
000000ec 0000005c T doubleclick()
0000015e 0000005c W CEveryNMillis::ready()
00000b6e 0000005c T OneButton::OneButton(int, int, bool)
00000b6e 0000005c T OneButton::OneButton(int, int, bool)
00001036 0000006e T CFastLED::setMaxRefreshRate(unsigned int, bool)
000010a4 00000072 T CFastLED::addLeds(CLEDController*, CRGB*, int, int)
00001568 00000076 T digitalRead
000009ba 0000007e W PixelController<(EOrder)66, 1, 4294967295ul>::init_binary_dithering()
00000acc 00000092 W CPixelLEDController<(EOrder)66, 1, 4294967295ul>::showColor(CRGB const&, int, CRGB)
00000a38 00000094 W CPixelLEDController<(EOrder)66, 1, 4294967295ul>::show(CRGB const*, int, CRGB)
000012da 00000094 T __vector_5
00000e78 00000098 T CFastLED::countFPS(int)
000014ca 0000009e T pinMode
000001c0 000000ac T START()
00000dac 000000ae W CLEDController::computeAdjustment(unsigned char, CRGB const&, CRGB const&)
0000026c 000000cc T setup
000008b8 000000fa W ClocklessController<(unsigned char)4, 3, 4, 3, (EOrder)66, 0, false, 10>::showPixels(PixelController<(EOrder)66, 1, 4294967295ul>&)
00000f10 00000126 T CFastLED::show(unsigned char)
00001148 00000168 T hsv2rgb_rainbow(CHSV const&, CRGB&)
00000bd2 000001ae T OneButton::tick(bool)
00000354 00000286 T loop
000005da 000002de W ClocklessController<(unsigned char)4, 3, 4, 3, (EOrder)66, 0, false, 10>::showRGBInternal(PixelController<(EOrder)66, 1, 4294967295ul>&)

The fastLED stuff looks huge, perhaps because it is designed for speed, rather than size. Although, I’m not sure why it’s inculduing hvs2rgb_rainbow() - you don’t seem to use that. And two different “ClocklessController” functions?

Perhaps you should try a different neopixel library? You said you don’t need “fast”, particularly…