Comment gagner/optimiser la mémoire

Bonjour à tous!!

Je fais face a un problème de mémoire.
J'ai un Leonoardo et sur le terminal, il est écrit

Sketch uses 23,454 bytes (81%) of program storage space. Maximum is 28,672 bytes.
Global variables use 1,891 bytes (73%) of dynamic memory, leaving 669 bytes for local variables. Maximum is 2,560 bytes.
Low memory available, stability problems may occur.

Je veux encore utiliser une carte SD, sauf si je peux faire autrement (quand je GSM n'est pas disponible, les données doivent etre écrites dans une carte SD). Si j'ajoute la librairie SD, ma mémoire monte à 95%. Grrrr.

Donc je dois obtimiser mon code.

Pour le moment j'ai beaucoup de Serial.println()

#ifdef DEBUG
Serial.prinlln(F("Affichage\n"));
#endif

Es-ce que le \n a une influence sur la mémoire?

Si je commente

//#define DEBUG

je gagne 16% de place. Ce qui est énorme.

Premiere question, comment puis-je obtimiser mes débug, car j'en ai besoin.

Si je fais une fonction de se genre

void sprintln(char * message)
{
  Serial.println(message);
}

Es-ce que je vais vraiment y gagner?
Et comment puis-je utiliser le F de (F(""));?
Qu'es-ce qu'il prend le plus de place, la fonction Serial.println(), ou le texte à imprimer?

Deuxième question
J'ai beaucoup de

if(val) // val est un bool
{
  retun true;
}
else
{
return false
}

En terme de mémoire, Ne serait-il pas mieux de faire

if(val) return true;
    return flase;
Troisième question

Que me suggeriez-vous pour obtimiser ce code.
Avant cette fonction, il y a la fonction sms_read(). Quand le sms est le lu, il envoi le contenu du message à
send_command(). le paramètre command, est le message du SMS.
La fonction sendCommande() va donc lire le message.
S'il lit, 'sms,r' , 'sms,s' , 'dir,w,+213334443333' , 'dir,r', 'dir,d,2' etc, il va appeler une fonction.
Si non il efface le SMS dont le texte n'est pas confirme à une command.

int SIM908::sendCommand(char * command)
{
  //int is=0;
  //char inSerial[25]; // expl: dir,w,+41567771122
  bool sent = false;
    
    if(!strncmp(command,"call",3))
    {
      splitString(command,splitedString);
       if(!strncmp(splitedString[1],"me",1))
       {
        
         // sms_send(2,"Boubaa will not call you but it just auto reply to your SMS!");
          sms_send(_owner,"Boubaa will not call you but it just auto reply to your SMS!");
          sent = 3; // not delete but change mode to read
       } 
    }
    else if(!strncmp(command,"dir",3))
    {
       splitString(command,splitedString);
       if(!strncmp(splitedString[1],"w",1))
       { 
         
         int lenPhone = strlen(splitedString[2]);
         //Serial.println(lenPhone);
         
         if(lenPhone < 12)
         {
           #ifdef DEBUG
             Serial.println(F("\n> Min, 12 digits with de +\n"));
             Serial.println(splitedString[2]);
           #endif
         }
         else
         {
           if(dir_write(splitedString[2]))
           {
              #ifdef DEBUG
                Serial.println(F("  Phone saved"));
              #endif
              sent = 1;
           }
           else
           {
              #ifdef DEBUG
                Serial.println(F("  Phone not saved"));
              #endif
              sent = 2;
           }
         }
         
       }
       else if(!strncmp(splitedString[1],"r",1))
       {
         for(int di=1; di<=_max_phone_in_dir; di++)
         {
           dir_read(di);
         }
         sent = 1;
         #ifdef DEBUG
           Serial.println(F(""));
         #endif
       }
       else if(!strncmp(splitedString[1],"d",1))
       {
           if(dir_delete(atoi(splitedString[2])))
           {
              #ifdef DEBUG
                Serial.println(F("  Phone deleted"));
              #endif
              sent = 1;
           }
           else
           {
              #ifdef DEBUG
                Serial.println(F("  Phone not deleted"));
              #endif
              sent = 2;
           }
       }
     }

    else if(!strncmp(command,"gps",3))
    {
      splitString(command,splitedString);
         
      if(!strncmp(splitedString[1],"1",1))
      {
        if(gps_read(1)) sent = 1;
          sent = 2; 
      }
      else if(!strncmp(splitedString[1],"0",1))
      {
        if(gps_read(0))
        {
          sent = 1;
        }
        else
        {
          sent = 2;
        }
      }
      else if(!strncmp(splitedString[1],"c",1))
      {
        if(gps_cellid())
        {
          sent = 1;
        }
        else
        {
          sent = 2;
        }
      }
      else
      {
        if(gps_read(0))
        {
          sent = 1;
        }
        else
        {
          sent = 2;
        }
      }
    }
     
     /* Enable GSM */
     else if(!strncmp(command,"egsm",4))
     {
       gsm_enable();
       sent = 1;
     }

     /* Enable GPS */
     else if(!strncmp(command,"egps",4))
     {
       gps_enable();
       sent = 1;
     }
      /* SEND SMS*/
     /* sms,r is not read if the command is received from a SMS. 
        sent can return true, becaus the terminal display the message...
     */
      else if(!strncmp(command,"sms",3))
      {
        splitString(command,splitedString);
        if(!strncmp(splitedString[1],"r",1))
        {
            sms_read(2); // List REC RAED
            sent = 1;
        }
        else if(!strncmp(splitedString[1],"u",1))
        {
            sms_read(1); // List REC UNREAD
            sent = 1;
        }
        else if(!strncmp(splitedString[1],"a",1))
        {
            sms_read(3);  // List REC ALL
            sent = 1;
        }
        else if(!strncmp(splitedString[1],"s",1))
        {
         if(sms_send(_owner,"Boubaa sent you a test SMS"))
         {
            #ifdef DEBUG
              Serial.println(F("  SMS sent\n"));
            #endif
            sent = 1;
          }
          else
          {
            #ifdef DEBUG
              Serial.println(F("  SMS Not sent\n"));
            #endif
            sent = 2;
          }
        }
        else if(!strncmp(splitedString[1],"d",1))
        {
          if(sms_delete(atoi(splitedString[2])))
          {
            #ifdef DEBUG
              Serial.println(F("> SMS Deleted\n"));
            #endif
            sent = 1;
          }
          else
          {
            #ifdef DEBUG_SMS
              Serial.println(F("> SMS Not deleted\n"));
            #endif
            sent = 2;
          }
        }
        else
        {
          #ifdef DEBUG
            Serial.println(F("  The command is unknow. SMS will be deleted."));
          #endif
          sent = 0;
        }
      }

    return sent;
 // }
}

Derniere question
J'avais lu que strcpy() et sprintf() utilisait beaucoup de mémoire, es-ce vrai? Comment pourrais-je alors faire autrement?

  1. les chaînes de debug sont utiles mais en principe on met au point une fonction à la fois donc ce n'est pas nécessaire de truffer toutes les fonctions de ton programme de printf. Une fois qu'une fonction est réputée bonne on commente les printf et on y touche plus.

  2. la manière la plus simple de l'écrire c'est

 return(val);

Maintenant, le compilateur gère ce genre de chose donc cela ne devrait pas avoir d'influence sur le code généré. Par contre à la lecture de ton code c'est moins lourd.

  1. code mammouth difficile d'avoir un avis.

De manière générale.
Il y a un moyen de gagner de la place. Etre moins verbeux, exemples

Serial.println(F("  The command is unknow. SMS will be deleted."));

peut devenir

Serial.println(F("  Unknown command. SMS deleted."));

La chaîne est moitié moins longue.
Mais là c'est de la mémoire programme que l'on gagne.
Ton problème si tu ajoutes la librairie SD ce sera la RAM disponible. La librairie SD à besoin d'un buffer de 512 octets. Et il n'y aura plus assez de mémoire pour créer les variables dynamiques.

En fait, je doute que l'on puisse faire tourner un soft avec les librairies GSM, GPS et SD sans être habitué à coder sur des cibles à faible taille mémoire.
Pour économiser la RAM, il faut limiter autant que possible les variables globales. Les librairies s'allouent souvent des zones mémoire pour leur besoin (comme la librairie SD par exemple) et sans reprendre ces librairies il est difficile de rogner sur cette partie. Ce qui impose au développeur d'être très économe en ressources mémoire.
C'est à prendre en compte dès le début car cela à une incidence sur l'architecture de l'application. A posteriori c'est souvent une gymnastique difficile et risquée qui oblige à refaire une validation du code.

le \n ne sert a rien, vu que tu fais un println.
le F vient de la librairie Flash, mais comme dit fdufnews, ca ne t'aidera pas beaucoup.
au mieux tu peut reduire les tampon d'emission/reception de serial, mais meme en gerant a l'octet pres, peu de chances que tu arrive comme ca a rajouter la SD sans vraiment manipuler (et savoir) avec quelle memoire/code tu joue.

Merci, je vais lire vos réponses.

Mais es-ce que chnager ceci:

if(val) // val est un bool
{
  Serial.println(F("OK"));
}
else
{
  Serial.println(F("KO"));
}

en

if(val)  Serial.println(F("OK"));
   Serial.println(F("KO"));

es-ce que {}else{} est considérable, si j'en ai tout plein?

Je ne sais pas si ça va te faire gagner beaucoup, mais ce que tu viens d'écrire peut être transformer en :

Serial.println(val?F("OK"):F("KO"));

c'est une autre forme d'écriture du if qui permet de l'intégrer dans des fonctions :

condition ? retour_vrai : retour_faux;

pierrot10:

if(val)  Serial.println(F("OK"));

Serial.println(F("KO"));




es-ce que {}else{} est considérable, si j'en ai tout plein?

Cette écriture va se traduire par:
si val est faux tu afficheras:
KO
si val est vrai tu afficheras
OK
KO

Un else consomme juste quelques instructions pour exécuter le test et temporairement un octet de RAM (et encore c'est même pas sûr) pour stocker la variable donc le gain est négligeable.

fdufnews:
Un else consomme juste quelques instructions pour exécuter le test et temporairement un octet de RAM (et encore c'est même pas sûr) pour stocker la variable donc le gain est négligeable.

Registre de statut SREG, bit "zero flag" pour un if (val), pas besoin de RAM :wink:
Sinon pour un if(val < <= == >= > val) ça demande un registre en plus vu qu'il y a deux opérandes.

Plus généralement : tu manques de RAM, pas de flash.
Regarde si tu n'as pas des constantes sans "const", des types de données inadéquats (style un int pour stocker une valeur entre 0 et 255 qui pourrait trés bien passer dans un byte) ou des booléen sauce bourrin avec un int ou byte par 0/1 (solution -> bitwise).