While loop do not work or maybe ram overflow?

Hello everybody :slight_smile:

I’ve got a strange issue.

I need to use a big while loop inside a fonction.

If the loop is complete the Arduino do not enter the loop, it seems to stuck just before it.
But if I reduce the lenght of the loop by commenting some lines it’s working good.

Is there any limitation ?

Here is the code:

The 4th debug line is commented, like this the Arduino is stopping just before entering the while loop or just before the first line in the loop.
If I remove the commente on this line the loop is working good but of course don’t do barely anything XD

The code is too huge to fit in the post, but it’s mainly the same thing everywhere, it’s just a menu fonction with some of switch/case…

void menu()
 {
 exitMenu = 1;
 buttonValue = analogRead(buttonPin); //lecture de la valeur des boutons
 Serial.println(buttonValue); //debug
 
 if(buttonValue <1000){
   
   display.clearDisplay();
   display.setTextSize(1);
   display.setCursor(0,0);
   display.setTextColor(WHITE,BLACK);
   display.print(">Seuil bas: ");
   display.println(rpmlow);
   display.print(" Seuil haut: ");
   display.println(rpmhigh);
   display.print(" facteur: ");
   display.println(rpmfactor);
   display.display();
   btPresse=1;
   menuValue = MENU1_1;
   Serial.println("Init menu OK"); //debug
   
   while(exitMenu == 1){   
     Serial.println("while loop entry"); //debug
     //exitMenu = 0; //debug
     noInterrupts();
     buttonValue = analogRead(buttonPin); //lecture de la valeur des boutons
   int tmpButtonState = 0;             // the current reading from the input pin
   
   if(buttonValue>=BUTTON1LOW && buttonValue<BUTTON1HIGH){
     //Read switch 1
     tmpButtonState = BUTTON1;
   }else if(buttonValue>BUTTON2LOW && buttonValue<BUTTON2HIGH){
     //Read switch 2
     tmpButtonState = BUTTON2;
   }else if(buttonValue>BUTTON3LOW && buttonValue<BUTTON3HIGH){
     //Read switch 3
     tmpButtonState = BUTTON3;
   }else if(buttonValue>BUTTON4LOW && buttonValue<BUTTON4HIGH){
     //Read switch 4
     tmpButtonState = BUTTON4;
   }else if(buttonValue>BUTTON5LOW && buttonValue<BUTTON5HIGH){
     //Read switch 5
     tmpButtonState = BUTTON5;
   }else if(buttonValue>1000){
     btPresse = 0;
     buttonState=7;
   }
   // check to see if you just pressed the button 
   // (i.e. the input went from LOW to a buttonState),  and you've waited 
   // long enough since the last press to ignore any noise:  

   // If the switch changed, due to noise or pressing:
   if (tmpButtonState != lastButtonState) {
     // reset the debouncing timer
     lastDebounceTime = millis();
   } 

   if ((millis() - lastDebounceTime) > debounceDelay) {
     // whatever the reading is at, it's been there for longer
     // than the debounce delay, so take it as the actual current state:
     buttonState = tmpButtonState;
   }

   // save the reading.  Next time through the loop,
   // it'll be the lastButtonState:
   lastButtonState = tmpButtonState;
    
    Serial.print("buttonsState: ");
    Serial.println(buttonState);
   
   switch(buttonState){
     case BUTTON1: //gauche
     switch(menuValue){
    case MENU1_1:
    if (btPresse == 0){
      exitMenu = 0;
      btPresse = 1;
    }    
    break; 
    case MENU1_2:
    if (btPresse == 0){
      display.clearDisplay();
      display.setTextSize(1);
      display.setCursor(0,0);
      display.setTextColor(WHITE,BLACK);
      display.print(">Seuil bas: ");
      display.println(rpmlow);
      display.print(" Seuil haut: ");
      display.println(rpmhigh);
      display.print(" facteur: ");
      display.println(rpmfactor);
      display.display();
      menuValue=MENU1_1;
      btPresse = 1;
    }    
    break;
    case MENU2_1:
    if  (btPresse ==0){
      exitMenu = 0;
      btPresse = 1;
    }    
    break;
    case MENU2_2:
    if (btPresse == 0){
      display.clearDisplay();
      display.setTextSize(1);
      display.setCursor(0,0);
      display.setTextColor(WHITE,BLACK);
      display.print(" Seuil bas: ");
      display.println(rpmlow);
      display.print(">Seuil haut: ");
      display.println(rpmhigh);
      display.print(" facteur: ");
      display.println(rpmfactor);
      display.display();
      menuValue=MENU2_1;
      btPresse = 1;
    }    
    break;
    case MENU3_1:
    if (btPresse ==0){
      exitMenu = 0;
      btPresse = 1;
    }    
    break;
    case MENU3_2:
    if (btPresse ==0){
      display.clearDisplay();
      display.setTextSize(1);
      display.setCursor(0,0);
      display.setTextColor(WHITE,BLACK);
      display.print(" Seuil bas: ");
      display.println(rpmlow);
      display.print(" Seuil haut: ");
      display.println(rpmhigh);
      display.print(">facteur: ");
      display.println(rpmfactor);
      display.display();
      menuValue =MENU3_1;
      btPresse = 1;
    }    
    break;
     }
     break;
   
   EEPROM_writeAnything(0, rpmlow);
   EEPROM_writeAnything(2, rpmhigh);
   EEPROM_writeAnything(4, rpmfactor);
   interrupts();
   } //fin while
 } //fin if
   
 }

Your code is incomplete. I'm guessing you're running out of RAM. Start putting string constants inside F() macros.

Please read the sticky threads about posting.

I can't post complete code, it's too huge (longer than 9500 caracters). But there is nothing special in the rest of the code, it's the same structure.

Is there any way to check the free ram ?

I'll try to make it less ram consuming.

Thank you for your help.

I can't post complete code, it's too huge (longer than 9500 caracters).

You can attach it. Read the sticky at the top on how to use the forum.

You should break up your code in separate functions. That way there are less local variables active at the same time and it makes your app readable -> understandable -> maintainable.

Ok :slight_smile:

So here is the complete code of the function.

But it’s strange, now the Arduino seems to stuck earlier.

On my first tries with full code I’ve got

‚ÄúInit menu OK‚ÄĚ on the serial terminal, that‚Äôs with I was thinking the problem is located in the while loop

later after some differents try

‚ÄúInit menu‚ÄĚ

And now with using the F(), less code and data:

‚ÄúInit me‚ÄĚ

Is there any chance I’ve made some serious mistake and damage the Arduino ?

menu_fonction.txt (17.5 KB)

So here is the complete code of the function.

Where is the complete code of the program ?

Attached to the previous post ! :astonished:

That appears to be only the code for the menu() function. Even the filename indicates that ! :astonished:

Yes, this is the function which is causing the issue.

I guess it's not optimized ... or I know it's not optimized XD

I need to try something differents to manage the menu and the display.

I need to try something differents to manage the menu and the display.

Yeas, maybe a Mega. You don't seem to comprehend how little memory an Arduino has.

M4vrick: Yes, this is the function which is causing the issue.

It may be the function where the error occurs or the function that does not work or the function where making changes gets it working, but you don't know that it is the function that causes the issue. Hence the request for you to post your whole program.

PaulS:
Yeas, maybe a Mega. You don’t seem to comprehend how little memory an Arduino has.

I hope to make it working on a Uno R3, my final goal is to use a Pro Mini 5V. There is only a 3 items menu on a Monochrome 128x32 display !

UKHeliBob:
It may be the function where the error occurs or the function that does not work or the function where making changes gets it working, but you don’t know that it is the function that causes the issue. Hence the request for you to post your whole program.

Ok, here is the complete code, last version with constants optimization. I’ve change all int to byte when it’s possible.
Everything was working fine since I’m adding the menu() function, if the problem is a ram overflow I guess it’s causing by the multiple switch/case I’m using.

The Arduino is freezing when entering the while loop in the menu() function, does it load all the while loop in memory before running it?
In this case I can try with subfunction to simplify the code and helping using less memory ?

Shift_Light_05.ino (24.3 KB)

As was already suggested, break the menu function down into smaller functions. You'd have a single function for each different menu, or you could event take the contents from an array with a single function that is parametrized with current selection. Either way, you have duplicated practically the same piece of code multiple times, separately for each button press too, and you are still missing the F macro from most of the strings.

This sequence of commands

            display.clearDisplay();
            display.setTextSize(1);
            display.setCursor(0,0);
            display.setTextColor(WHITE,BLACK);

appears several times in your code. It may not make any difference to the code size but personally I would make those lines into a function and call it when the display needs to be cleared. If nothing else it should make the code easier to read.

I was in the process of reducing the code with sub functions, following your advice. And using the F macro for every print.

Here is the new code, with a button less (4 buttons instead of 5 before). But still the same issue.

Before taking too much time to debug it, do you think I could make it working with an Uno ?
I don’t want to waste my time and your time if there is definitly not enough memory to handle it.

My menu is 3 lines, 4 buttons (UP, DOWN, ESC, OK) and 126x32 Display.

Shift_Light_05.ino (14.6 KB)

Try the function here http://playground.arduino.cc/Code/AvailableMemory to see how much RAM you actually have left. You still have a couple of serial prints that lack the F macro too.

I'd also be inclined to run it without the interrupt input being hooked up - ground it and see whether problems persist.

Also, don't do this:

  display.print(F(">Seuil bas: "));

Print the ">" separately. That way there will only be one copy of the "Seuil bas: " string created by the compiler. That applies elsewhere too.

Assuming that this error isn't popping, get rid of this too, or at least shorten the string:

#if (SSD1306_LCDHEIGHT != 32)
#error("Height incorrect, please fix Adafruit_SSD1306.h!");
#endif

So I'd better do:

print(F(">")); print(F("Seuil bas: "));

instead of:

print(F(">Seuil bas: "));

even if there is more code line? I can also seperate the space used in place of '>' or moving cursor to keep only the minimal string lenght. So more line code but less memory usage with less differents strings. Did I understand well ?

That's it. The trick is that if you use the same string in multiple places, the compiler will make a single copy. If there is any difference at all, there will be one for each version. So yes, you'll need to separate out the version with a trailing space in the same way.