Not enough flash memory - IRRemote, TM1637, MCP23017 08 and others

Hi,

Im using below libraries with arduino micro (32u4):

  • TimerInterrupt.h with Timer1

  • Rotary -

  • TM1637Display

  • Adafruit_MCP23008.h - without interupts, just i/o

  • Adafruit_MCP23017.h - without interupts , just i/o

  • IRremote.hpp - with added "#define DECODE_NEC" so it should use only decode NEC, withot sending, also for IR codes im using variable "long", maybe I should use different?

about TM1637, can I write code in different way to get more flash memory?

const uint8_t SEG_In1[] = {
 SEG_A | SEG_F | SEG_E | SEG_D,
 SEG_F | SEG_E | SEG_G | SEG_B | SEG_C,
 0x0,
 SEG_B | SEG_C
};
const uint8_t SEG_In2[] = {
 SEG_A | SEG_F | SEG_E | SEG_D,
 SEG_F | SEG_E | SEG_G | SEG_B | SEG_C,
 0x0,
 SEG_A | SEG_B | SEG_G | SEG_E | SEG_D
};
const uint8_t SEG_In3[] = {
 SEG_A | SEG_F | SEG_E | SEG_D,
 SEG_F | SEG_E | SEG_G | SEG_B | SEG_C,
 0x0,
 SEG_A | SEG_B | SEG_C | SEG_G | SEG_D
};
const uint8_t SEG_In4[] = {
 SEG_A | SEG_F | SEG_E | SEG_D,
 SEG_F | SEG_E | SEG_G | SEG_B | SEG_C,
 0x0,
 SEG_F | SEG_G | SEG_B | SEG_C
};
const uint8_t SEG_In5[] = {
 SEG_A | SEG_F | SEG_E | SEG_D,
 SEG_F | SEG_E | SEG_G | SEG_B | SEG_C,
 0x0,
 SEG_A | SEG_F | SEG_G | SEG_C | SEG_D
};
const uint8_t SEG_In6[] = {
 SEG_A | SEG_F | SEG_E | SEG_D,
 SEG_F | SEG_E | SEG_G | SEG_B | SEG_C,
 0x0,
 SEG_A | SEG_F | SEG_C | SEG_D | SEG_E | SEG_G
};
const uint8_t SEG_MUTE[] = {
 SEG_G,
 SEG_G,
 SEG_G,
 SEG_G
};
const uint8_t SEG_Ir[] = {
 SEG_C,
 SEG_E | SEG_G,
 0x0,
 0x0
};
const uint8_t SEG_Iro[] = {
 SEG_C,
 SEG_E | SEG_G,
 SEG_E | SEG_G | SEG_C | SEG_D,
 0x0
};
const uint8_t SEG_05[] = {
 0x0,
 0x0,
 SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F | SEG_DP,
 SEG_A | SEG_F | SEG_G | SEG_C | SEG_D
};

const uint8_t SEG_00[] = {
 0x0,
 0x0,
 SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F | SEG_DP,
 SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F
};


const uint8_t SEG_DONE[] = {
 SEG_B | SEG_C | SEG_D | SEG_E | SEG_G,          // d
 SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F,  // O
 SEG_C | SEG_E | SEG_G,                          // n
 SEG_A | SEG_D | SEG_E | SEG_F | SEG_G           // E
};

uint8_t data[] = { 0x0, 0x0, 0x0, 0x0 };  // all segments clear
//TM1637//

also, I dont know where I can disable bootloader or in normaln mode bootloader is turned off?

Perhaps you can remove some of these libraries to recover some flash space?

For example can you replace Timer1 library by using millis()?

Could you replace the MCP23008 with MCP23017 or vice-versa so that one less library is needed?

Could you remove the MCP libraries and use only Wire library?

To get more specific and better advice, read the forum guide in the sticky post. It will tell you what you should include in your post, such as the full code, a schematic diagram, links to the specs of the important components you are using.

I have already check variables if I can go with byte or different smaller - its done.

MCP23008/17 - Adafruit published newer library one for both, but after updating to the newest I get 5% more uses of flash memory.

Timer1 - its used for Rotary

demo code of rotarty with TImer:

/* Demo-Code that uses the Rotary-library from GitHub-User https://github.com/buxtronix
 * using his library https://github.com/buxtronix/arduino/tree/master/libraries/Rotary  
 * in combination with a timer-interrupt executed 10000 times per second
 * Copyright 2023 StefanL38. Licenced under the GNU GPL Version 3.
 * A T T E N T I O N ! 
 * this demo-code uses Timer1 which is used by other libraries too. 
 * This means using this code can interfere with other libraries
 * causing malfunction of both
 * 
 * This demo-code uses the TimerInterrupt.h-library from here
 * https://github.com/khoih-prog/TimerInterrupt/tree/master
 * 
 * The examples in the GiPo show how to use different timers
 * The demo-code simply prints the value of variable myCounter 
 * each time the value of the variable changes
 */

#define USE_TIMER_1     true

#if ( defined(__AVR_ATmega644__) || defined(__AVR_ATmega644A__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644PA__)  || \
        defined(ARDUINO_AVR_UNO) || defined(ARDUINO_AVR_NANO) || defined(ARDUINO_AVR_MINI) ||    defined(ARDUINO_AVR_ETHERNET) || \
        defined(ARDUINO_AVR_FIO) || defined(ARDUINO_AVR_BT)   || defined(ARDUINO_AVR_LILYPAD) || defined(ARDUINO_AVR_PRO)      || \
        defined(ARDUINO_AVR_NG) || defined(ARDUINO_AVR_UNO_WIFI_DEV_ED) || defined(ARDUINO_AVR_DUEMILANOVE) || defined(ARDUINO_AVR_FEATHER328P) || \
        defined(ARDUINO_AVR_METRO) || defined(ARDUINO_AVR_PROTRINKET5) || defined(ARDUINO_AVR_PROTRINKET3) || defined(ARDUINO_AVR_PROTRINKET5FTDI) || \
        defined(ARDUINO_AVR_PROTRINKET3FTDI) )
#endif

// To be included only in main(), .ino with setup() to avoid `Multiple Definitions` Linker Error
#include "TimerInterrupt.h"

#define TIMER1_INTERVAL_MS    1
 
#include <Rotary.h>

// Rotary encoder is wired with the common to ground and the two
// outputs to pins 5 and 6.
const byte channel_A_Pin = SS;
const byte channel_B_Pin = 8;
Rotary rotary = Rotary(channel_A_Pin, channel_B_Pin);

const byte channel_C_Pin = MISO;
const byte channel_D_Pin = SCK;
Rotary rotary1 = Rotary(channel_C_Pin, channel_D_Pin);

unsigned long myISR_TimerFrequency = 10000;
// myCounter that will be incremented or decremented by rotation.
// as this variable is changed in an interrupt-service-routine
// this variable MUST !! be declared volatile to make sure 
// that it works properly !
volatile uint8_t myCounter = 0;
uint8_t last_myCounter = 0;

volatile uint8_t myCounter1 = 0;
uint8_t last_myCounter1 = 0;

void TimerHandler1() {
  unsigned char result = rotary.process();
  unsigned char result1 = rotary1.process();

  // depending on having detected rotation
  if (result == DIR_CW) {
    myCounter++;

  }
  else if (result == DIR_CCW) {
    myCounter--;

  }

    // depending on having detected rotation
  if (result1 == DIR_CW) {
    myCounter1++;

  }
  else if (result1 == DIR_CCW) {
    myCounter1--;

  }
}


void PrintFileNameDateTime() {
  Serial.println( F("Code running comes from file ") );
  Serial.println( F(__FILE__) );
  Serial.print( F("  compiled ") );
  Serial.print( F(__DATE__) );
  Serial.print( F(" ") );
  Serial.println( F(__TIME__) );
}


// easy to use helper-function for non-blocking timing
boolean TimePeriodIsOver (unsigned long &startOfPeriod, unsigned long TimePeriod) {
  unsigned long currentMillis  = millis();
  if ( currentMillis - startOfPeriod >= TimePeriod ) {
    // more time than TimePeriod has elapsed since last time if-condition was true
    startOfPeriod = currentMillis; // a new period starts right here so set new starttime
    return true;
  }
  else return false;            // actual TimePeriod is NOT yet over
}

unsigned long MyTestTimer = 0;  // Timer-variables MUST be of type unsigned long
const byte    OnBoard_LED = 13;


void BlinkHeartBeatLED(int IO_Pin, int BlinkPeriod) {
  static unsigned long MyBlinkTimer;
  pinMode(IO_Pin, OUTPUT);

  if ( TimePeriodIsOver(MyBlinkTimer, BlinkPeriod) ) {
    digitalWrite(IO_Pin, !digitalRead(IO_Pin) );
  }
}


void setup() {
  Serial.begin(115200);
  Serial.println("Setup-Start");
  PrintFileNameDateTime();

  Serial.print(F("\nStarting Argument_None on "));
  Serial.println(BOARD_TYPE);
  Serial.println(TIMER_INTERRUPT_VERSION);
  Serial.print(F("CPU Frequency = ")); 
  Serial.print(F_CPU / 1000000); 
  Serial.println(F(" MHz"));

  // Timer0 is used for micros(), millis(), delay(), etc and can't be used
  // Select Timer 1-2 for UNO, 1-5 for MEGA, 1,3,4 for 16u4/32u4
  // Timer 2 is 8-bit timer, only for higher frequency
  // Timer 4 of 16u4 and 32u4 is 8/10-bit timer, only for higher frequency

  ITimer1.init();

  // Using ATmega328 used in UNO => 16MHz CPU clock ,
  // For 16-bit timer 1, 3, 4 and 5, set frequency from 0.2385 to some KHz
  // For 8-bit timer 2 (prescaler up to 1024, set frequency from 61.5Hz to some KHz

  if (ITimer1.attachInterruptInterval(TIMER1_INTERVAL_MS, TimerHandler1)) {
    Serial.print(F("Starting  ITimer1 OK, millis() = ")); Serial.println(millis());
  }
  else {
    Serial.println(F("Can't set ITimer1. Select another freq. or timer"));
  }
}


void loop() {

  BlinkHeartBeatLED(OnBoard_LED, 250);

  // check if value has changed
  if (last_myCounter != myCounter) {
    // only if value REALLY HAS changed
    byte difference = abs(last_myCounter - myCounter);
    if (difference != 1) {
      Serial.println("difference != 1 counter jumped !!");
    }
    last_myCounter = myCounter; // update last_myCounter
    Serial.print("myCounter=");
    Serial.println(myCounter);
  }

    // check if value has changed
  if (last_myCounter1 != myCounter1) {
    // only if value REALLY HAS changed
    byte difference = abs(last_myCounter1 - myCounter1);
    if (difference != 1) {
      Serial.println("difference != 1 counter jumped !!");
    }
    last_myCounter1 = myCounter1; // update last_myCounter
    Serial.print("myCounter1=");
    Serial.println(myCounter1);
  }
}

That will not reduce flash memory, only RAM (dynamic) memory.

Have you explored other rotary encoder libraries to see if they use less flash?

LOL! Maybe you should report that to Adafruit!

You can remove the bootloader, but then you must upload your code to the Arduino Micro using an ICSP programmer such as USBasp. This will free up 2~3K of flash memory, but you may lose the ability to use Serial Monitor. I would consider this only as a last resort.

How do that? I dont need serial monitor and also there is no problem with programming directly via icsp connector

I said I would recommend this only as a last resort. You have not even attempted a "first resort" yet!

If you must do it, I recommend to get a USBasp programmer, connect it to the ICSP pins of the Micro and click "upload using programmer".

Export compiled binary - this is not same as upload using programmer? if yes, then arduino cant compile, beacause of 103% usage of flash memory

No.

Please show an EXACT compiler message

Szkic używa 29640 bajtów (103%) pamięci programu. Maksimum to 28672 bajtów.
Zmienne globalne używają 929 bajtów (36%) pamięci dynamicznej, pozostawiając 1631 bajtów dla zmiennych lokalnych. Maksimum to 2560 bajtów.
Szkic za duży, zobacz porady na https://support.arduino.cc/hc/en-us/articles/360013825179 w celu zmiejszenia go.
text section exceeds available space in board

Compilation error: text section exceeds available space in board

I have changed language to English, but some of text are in Polish

Arduino micro (32u4)has 32768 bytes without bootloader, and your code size

is less than the board capacity, so it seems that removing the bootloader can help in your case.

Yeah, it should working.

After clicking upload using programmer, arduino starts compiling and again I have error that Im out of flash memory.

Im using IDE 2.1.1

You have to change the board settings first in IDE. You need select something like "Arduino micro (no bootloader" or edit the boards.txt file manually.

For other arduino version I saw this option. For micro not. So I need to do it manually.

Also I found this topic, bootloader for 32u4 need 4kb a lot of memory
https://arduino.stackexchange.com/questions/69079/flash-size-in-boards-txt-atmega-328p-32u4

Ok I have changed in boards.txt hfuse to d9 (disable bootloader) and flash memory to 32768

As long as you keep your complete code a secret a lot of options how flash-use can be reduced must be found by yourself.

For me problem is solved.

If its possible please close this topic.

Closed as requested