[ Arduino Annexe B ] Gestion de la mémoire

Nous allons maintenant parler mémoire. Vous le savez peut-être, l’ordinateur (ou le téléphone, ou la tablette ou le minitel…) avec lequel vous êtes en train de consulter ce tutoriel dispose de plusieurs types de mémoire. Et bien de la même façon un microcontrôleur lui aussi en embarque plusieurs que nous allons découvrir ensemble.

Une histoire de mémoire

Comme je vous l’expliquais dans l’introduction, il y a de fortes chances que le support avec lequel vous consultez ce tutoriel utilise différents types de mémoire. Par exemple, un ordinateur dispose d’un disque dur pour sauvegarder les données sur le long terme et il possède aussi de la mémoire vive (RAM) pour sauvegarder les données d’un programme qui est en train de fonctionner (les variables qu’il manipule par exemple). De la même façon, un être humain possède une mémoire dite à court-terme, qui vous permet de vous rappeler d’acheter du lait lorsque vous allez faire vos courses et une mémoire à long terme qui vous permet de vous souvenir des informations qui vous ont marqué et/ou vous sont utiles au quotidien. Pour Arduino la situation est très similaire. On retrouve au total trois mémoires distinctes qui ont chacune un rôle précis : RAM, ROM et Flash.

Les Mémoires

La RAM

Tout d’abord la plus simple : la RAM qui est la mémoire vive du composant (comme sur votre ordinateur). Mémoire vive car elle est très rapide et doit gérer beaucoup d’informations très vite. Vous le savez peut être : il existe différent types de RAM, dans notre cas ce sera de la SRAM (pour Static Random Access Memory), qui est plus rapide mais aussi plus consommatrice en énergie que la RAM Dynamique de vos ordinateurs et aussi plus encombrante (mais tout ca est bien sûr à relativiser à l’échelle électronique). Elle servira à stocker les variables du programme. Chaque fois que vous faites une nouvelle déclaration de variables, cette dernière se retrouvera dans cette mémoire. Une caractéristique à ne pas négliger, cette mémoire est entièrement effacée lorsque l’alimentation de l’Arduino cesse (on dit qu’elle est « volatile »).

L’EEPROM

Ensuite, on trouve une mémoire dite morte, l’EEPROM (Electrically Erasable Programmable Read-Only Memory). Alors non, n’allez pas croire à la lettre qu’elle est vraiment morte. En fait, on la nomme ainsi car elle est capable de stocker des informations même lorsqu’elle n’est plus alimentée. Cette dernière est similaire au disque dur de votre ordinateur par son comportement et ses caractéristiques. La vitesse d’accès est moins élevée que la RAM et sa durée de vie (nombre de cycle d’écritures possible) est plus faible aussi.

La FLASH

Enfin, une dernière mémoire de l’Arduino est la Flash. Elle à un rôle un peu particulier, elle sert à stocker le programme que vous téléchargez dans le microcontrôleur. Elle retient donc les informations même lorsque l’alimentation est coupée. Comme dit plus tôt, c’est ici que sont stockées toutes les instructions de votre programme, ainsi que le bootloader, un petit bout de code qui agit comme le BIOS de votre PC. Il détecte au démarrage de l’Arduino si on tente de programmer la carte via la liaison série et le cas échéant copiera les données dans la mémoire FLASH. On n’y stocke pas de données pendant l’exécution du programme. En revanche, on peut y stocker des constantes (comme des chaînes de caractères pour votre écran LCD par exemple) afin de gagner un peu de place dans la RAM. D’une manière générale, essayez de la voir comme une mémoire en lecture seule. Mais nous verrons cela plus tard.

Rappel sur les variables

Vous le savez depuis longtemps maintenant, toutes les données d’un programme informatique peuvent être stockées dans des variables. Ces dernières peuvent représenter différentes choses et donc on trouve différents types de variables qui occupent chacun une taille particulière dans la mémoire. Voici une liste exhaustive des différents types de données utilisables, classées selon la taille occupée en mémoire :

  • 1 octet : char, byte ( = unsigned char), Boolean
  • 2 octets : int, word (= unsigned int), short (= signed int)
  • 4 octets : long, float, double (= float chez Arduino)

Sur la nouvelle Arduino DUE, le word reste sur 2 octets.

Résumé

Caractéristiques

Voici un petit tableau résumant les caractéristiques des différentes mémoires :

Nom Taille (Uno) Vitesse lecture/écriture Ecriture durant exécution Simplicité d’utilisation
SRAM 2 Ko Très rapide OUI +++
EEPROM 1 Ko Lent OUI ++
FLASH 32 Ko Rapide Lecture seulement +

Les cartes Arduino

Les tailles sont toutes exprimées en kilo-octets (et entre parenthèse se trouve la taille occupée par le bootloader).

Carte SRAM EEPROM Flash
Uno 2 1 32 (0.5)
Leonardo 2.5 1 32 (4)
Mega 2560 8 4 256 (8)
DUE 96 0* 512 (0)
Mini 2 1 32 (2)
Micro 2.5 1 32 (4)

*Avec la DUE il est en théorie possible d’écrire dans la mémoire Flash pendant l’exécution du programme, mais aucune bibliothèque dédiée n’existe pour le moment.

Ajouter de la mémoire

Il est normalement possible de rajouter de la mémoire externe via l’utilisation de composant comme un circuit intégré d’EEPROM ou l’utilisation d’une carte FLASH (une cartes SD) que l’on retrouve partout dans les appareils photos et téléphones portables. Cependant, toutes ces solutions reposent sur l’utilisation d’un protocole de communication différent à chaque fois ou d’adaptation électronique ou d’autres contraintes. Nous ne traiterons donc pas ces différentes mémoire dans ce chapitre pour nous concentrer uniquement sur ce qui est disponible au sein de l’Arduino (et qui sera amplement suffisant pour commencer tout vos premiers projets).

La SRAM ou mémoire vive

Commencons les choses tranquillement avec ce qui se fait de plus facile : la SRAM. Pour rappel, cette mémoire est équivalente à la mémoire vive de votre ordinateur. Dans le cas de l’Arduino UNO, nous disposons de 2 Kilo-Octets (2 KB), ce qui représente un total de 2048 octets. En terme de quantité de variables, cela représente au choix :

  • 2048 char
  • 1024 int
  • 512 float

Bien entendu, vous pouvez y stocker tout les types de données que vous souhaitez, du plus simple au plus farfelu. Par exemple, vous pouvez y mettre quelques char pour définir les broches à utiliser en entrées/sorties et une chaîne de caractères que vous utiliserez pour un message pour votre écran LCD. Si l’on part de cette liste, on pourrait obtenir :

  • Trois char pour définir trois entrées/sorties (Led1, Led2, Bouton)
  • Un tableau de caractère « Salut les gens ! » (donc 17 char avec le caractère ‘\0’ de fin de chaîne)

Cela nous fait un total de 20 octets en RAM. Avec Arduino (tout comme avec votre ordinateur), aucune complication pour lire et écrire des variables dans la RAM. C’est le cœur de la machine qui s’en occupe. C’est totalement transparent pour vous. Par contre, contrairement à votre ordinateur, Arduino ne possède pas plusieurs GigaOctets de RAM. C’est pourquoi il est souvent judicieux de réfléchir au type de la variable à déclarer lorsqu’on en crée une.
Par exemple, pour stocker l’état d’un bouton ou un âge, inutile de prendre un int, un simple char suffit et vous économiserez alors 1 octet par variable. Cela peut sembler trivial, mais on y pense pas forcément lorsqu’on arrive d’un milieu où la mémoire est souvent le cadet des soucis.
Cet aspect est d’autant plus important qu’il est assez difficile de déceler une incohérence de comportement du programme à cause de la mémoire manquante.
En effet, sur votre ordinateur le système d’exploitation (OS, Operating System) possède un certain contrôle sur la quantité de mémoire maximale autorisée par programme. Sur Arduino, pas d’OS donc pas de message d’erreur lorsque la mémoire est saturée. Le microcontrôleur essaiera tant que possible de faire tenir les variables en mémoire, mais s’il ne peut pas le comportement peut devenir imprévisible et les problèmes de RAM sont souvent la dernière chose à laquelle on pense. Donc un conseil : méfiez-vous lorsque vous déclarez vos variables ! (surtout si vous déclarez de nombreuses chaînes de caractères qui prennent rapidement de la place).

Et c’est tout ?

Eh oui. La RAM est une mémoire vraiment simple à utiliser puisque c’est complètement transparent ! (tant que vous ne déclarez pas des variables à tort et à travers 😛 )

L’EEPROM une mémoire « morte »

Comme nous le disions plus tôt, cette mémoire est un peu le « disque dur » de votre carte à la différence qu’il n’y a pas de partie mécanique (donc pas de casse possible). En revanche, la durée de vie de cette mémoire possède un nombre de lectures/écritures limité (environ 100 000 lectures/écritures pour chaque octet). Comme pour tout système de mémoire, elle fonctionne à partir d’un mécanisme d’adresse. Un peu comme si vous rangiez des informations dans un livre, avec une information par page. La taille d’une information est ici d’un octet, et le nombre de cases dans lequel on peut stocker ces infos est de 1024 (sur une Arduino Uno). Vous pouvez donc stocker 1024 octets au total. Vous pouvez aussi stocker 512 int par exemple (1024/2) ou fait un mix des deux. Pour pouvoir manipuler l’EEPROM, il vous faudra dans un premier temps inclure une bibliothèque bien nommée : EEPROM.h

Une case mémoire qui n’a jamais été utilisée possède une valeur initiale de 255.

Enregistrer des données

La mémoire EEPROM est donc divisée en 1024 blocs de 8 bits. Pour écrire une donnée, il va falloir décider dans quel bloc on veut l’enregistrer, c’est ce qu’on appelle l’adresse d’écriture. Comme la mémoire est initialement vide quand vous achetez la carte, vous pouvez choisir comme bon vous semble où vous voulez mettre les informations, à qu’elle adresse, entre 0 et 1023. Par contre lorsque vous voudrez les récupérer il faudra vous souvenir où elles sont ! 😛 Pour enregistrer une donnée c’est très simple, il suffit simplement d’utiliser une seule fonction : write(). Comme elle appartient à la librairie EEPROM, et pour qu’elle ne soit pas confondue avec une autre, elle est déclarée dans un ensemble (un namespace) qui s’appelle EEPROM. Pour utiliser la fonction il faudra donc écrire :

Cette fonction prend deux arguments :

  • L’adresse où écrire (un int entre 0 et 1023)
  • L’octet à enregistrer (un unsigned char)

Par exemple pour enregistrer la valeur 42 à l’adresse 600 on fera :

Lire des données

Je suis intiment persuadé que vous n’aurez aucun mal à deviner comment lire des données depuis la mémoire… Vous avez trouvé ? En effet, il suffit d’utiliser une autre fonction avec un nom très explicite : read() ! Comme pour sa cousine l’écriture, il faudra la faire précéder de « EEPROM » pour y accéder. Cette fonction ne prendra qu’un seul argument qui sera l’adresse à laquelle on veut aller chercher notre donnée. Exemple, je vais lire la donnée à l’adresse 600 :

La variable donnee prendra donc la valeur stockée à l’adresse mémoire numéro 600. Soit 42. Et voilà, vous savez tout sur l’écriture et la lecture dans l’EEPROM. 🙂

Hep hep hep, minute papillon. C’est sympa tout ça mais je fais comment si je veux stocker un float par exemple ?

Excellente question, nous allons voir comment nous allons y répondre !

Limite de ces fonctions

Comme vous l’avez vu, les deux fonctions présentées ci-dessus sont fait pour lire/écrire un seul octet à la fois. Ce qui veut dire qu’on ne peut pas les utiliser pour enregistrer un int, float, double… C’est très embêtant… Mais bien entendu, chaque problème à sa solution. Par contre il va falloir mettre les mains dans le cambouis et faire nos propres fonctions d’enregistrement pour pouvoir conserver des types de variable plus grand qu’un simple octet.

Rappel sur l’opérateur de décalage binaires et les masques

Si vous avez lu le chapitre annexe permettant d’ajouter des sorties numériques à la carte Arduino, vous avez pu lire ce passage sur l’utilisation des registres à décalage et fait ainsi la découverte de l’opérateur de décalage binaire. Si ce n’est pas le cas, alors je vous invite à y jeter un œil pour comprendre comment cela fonctionne, car je ne reviendrais pas vraiment dessus. Simplement pour rappel, ces opérateurs permettent de décaler tous les bits d’une variable vers la droite ou vers la gauche. Ils s’écrivent avec des chevrons : << pour décaler à gauche et >> pour décaler à droite. L’écriture se fait de la manière suivante :

Par exemple, pour décaler de 3 bits vers la gauche :

Les masques, qui vont être utile pour la suite, sont réalisés grâce à deux opérateurs logiques bits-à-bits, le OU ( | ) et le ET ( & ). Un OU permettra d’imposer un bit à 1 tandis que le ET permettra d’imposer un bit à 0. Par exemple, pour mettre les 4 derniers bits d’un octet à 1 on fera :

De même pour mettre les quatre derniers à 0 on fera :

Encore une fois, pour plus de détails sur les opérateurs de décalage ou de masquage, référez à cette partie. Maintenant que les rappels sont faits, nous allons voir comment faire pour lire et écrire dans l’EEPROM des variables qui font plus d’un octet. Pour cela nous allons réaliser deux fonctions qui prendront pour exemple l’écriture/lecture d’un int (mais vous allez comprendre le principe et serez donc capable de faire sans problème la même chose pour tous les types de données 😉 )

Écrire un int dans l’EEPROM

Un int qui représentera la variable à mettre en mémoire. Afin de garder les choses simples, on enregistrera les valeurs à la suite, dans des cases mémoires consécutives. Pour pouvoir mettre notre int dans les deux cases, il va falloir le découper en deux pour obtenir deux octets. On va d'abord commencer par isoler les 8 bits les plus à droite (bits de poids faible) grâce à un simple masque. Ensuite, on va faire évoluer le masque en le décalant 8 fois vers la gauche et ainsi isoler les bits de poids fort.L’enregistrement se fera alors de la manière la plus simple du monde, en faisant deux enregistrements successifs à l’adresse n et n+1.

Je vous invite à essayez par vous-même avant de regarder le code suivant, cela vous fera un bon exercice.

Lire un int depuis l’EEPROM

Je ne sais pas si vous avez trouvé le code précédent simple, mais si c’est le cas alors pas d’inquiétude car on reste sur le même concept. De même que précédemment, je vous invite à lire ce que l'on va faire, essayer, puis regarder la solution après. Le principe est le suivant. Nous allons tout d’abord récupérer l’octet de poids fort puis celui de poids faible qui composait la variable de type int reconstituée !

La Flash, mémoire de programme, morte et vive à la fois !

Maintenant que vous avez tout compris aux différents types de mémoires et que l'on a vu ensemble comment manipuler les plus simples, nous allons pouvoir passer à la dernière, la plus compliquée, la mémoire Flash dite "de programme". Cette mémoire, appelée plus communément "mémoire de programme" (ou encore "Progmem") sert d’ordinaire à stocker le code que vous avez créé puis compilé, le programme en somme. En effet, lorsque vous "téléversez" votre programme (beurk cette traduction) vers le microcontrôleur, c’est ici qu’il sera envoyé. Comme toutes les mémoires flash, sa durée de vie (exprimée en nombres de lectures/écritures) n’est pas infinie. L’utilisation de cette flash est un peu particulière. En effet, on ne peut enregistrer des données dedans qu’au moment du téléchargement du programme. Une fois le programme chargé, elle agit en lecture seule, si bien que vous ne pourrez que récupérer des données injectées plus tôt mais pas en rajouter de nouvelles au moment du fonctionnement normal (par exemple pour y stocker des valeurs de variables).

Alors, ça ne sert à rien une mémoire en lecture seule !?

Détrompez-vous, c’est en fait très utile pour mettre des données qui ne varient pas et qui risqueraient d’encombrer votre RAM par exemple. Le premier des usages est souvent le stockage de chaîne de caractères, que l’on va plus tard envoyer sur un écran LCD. Par exemple je veux afficher à chaque démarrage du programme le message "Salut les gens !" sur mon écran. La première méthode serait donc de faire un truc du genre :

Cette ligne de code va être interprété de façon à enregistrer la chaîne dans la mémoire RAM. Ce message qui fait 16 caractères prendra donc 16 octets dans votre RAM (en fait 17 avec le caractères de fin de chaîne '\0'). Ça peut paraître insignifiant mais si votre programme contient plusieurs chaînes pour afficher du texte de manière dynamique ça peut vite devenir serré. Comme ce message n’a pas besoin d’être modifié pour être ensuite ré-enregistré, la meilleure des solutions reste de le stocker dans la mémoire de programme qui est beaucoup plus grande que la mémoire RAM. Il ne prend ainsi pas de place en RAM et on pourra toujours le récupérer à chaque fois que l’on en aura besoin 🙂 .

Sauvegarder/charger des variables

Maintenant que le concept est posé, passons un peu à la pratique 🙂 . Nous allons commencer par enregistrer et recharger des variables "simples" (un int par exemple) puis ensuite nous chercherons à stocker des variables plus compliquées comme un tableau de caractères.
L'utilisation de la mémoire de programme repose sur un mot-clé qui nous sert d'attribut modificateur de variables. En simple, c'est ce mot-clé qui dira au compilateur "Cette variable il faut la mettre en mémoire flash de programme". Ce mot-clé est PROGMEM (tout en majuscules). Pour pouvoir l'utiliser, il vous faudra aussi intégrer la librairie de gestion de cette mémoire :

Des variables simples

Pour enregistrer une variable, il vous suffira simplement de la déclarer comme d'habitude, à la seule différence qu'il faut rajouter le modificateur PROGMEM pour qu'elle soit enregistrée au bon endroit. Par exemple pour enregistrer un int :

Le mot-clé PROGMEM peut aussi s'écrire avant le type, mais pas entre le type et le nom de la variable : PROGMEM int unInt = 42 ;

Il semble, à ce jour, qu'il y ait un problème avec la sauvegarde des nombres flottants. Les seuls types à utiliser sont donc char, int et long (unsigned ou signed)

Une fois que les variables sont enregistrées, il ne nous reste plus qu'à les récupérer pour les utiliser dans notre programme. Pour cela, il existe des fonctions pour chaque type de variable. Elles sont toutes plutôt simple à retenir :

  • pgm_read_byte() -> pour lire un char
  • pgm_read_word() -> pour lire un int
  • pgm_read_dword() -> pour lire un long

Pour chacune de ces fonctions, il vous faudra mettre en argument la variable créée, précédée par le symbole '&'. Les habitués des pointeurs doivent savoir pourquoi. Pour les autres voici une petite explication. Lorsque vous déclarer votre variable, celle-ci va sagement se mettre dans une case mémoire. Cette case possède une adresse pour retrouver la variable plus tard (comme avec l'EEPROM souvenez-vous). Lorsque vous faite appelle à la fonction pgm_read_byte(), vous devez passer l'adresse de la variable plutôt que sa valeur (passer la valeur n'a en effet aucun intérêt ici). C'est ce que permet l'opérateur '&'.

Je comprends que cela soit flou, et le cours n'est pas là pour faire une explication exhaustive des pointeurs. Je vous demanderais juste de ne pas oublier de mettre le symbole '&' pour utiliser la variable en flash.

Un petit exemple :

Une chaîne de caractères

Un usage très fréquent de l'utilisation de la mémoire de programme est le stockage de chaînes de caractères vouées à être affichées plus tard. En effet, une chaîne de caractères qui sert uniquement à indiquer un menu ou un message d'accueil ne sera pas modifiée et a donc pleinement sa place dans une mémoire en lecture seule. On va commencer par déclarer un tableau comme on le ferait normalement, puis comme précédemment on va lui ajouter le modificateur PROGMEM :

Maintenant que les données sont enregistrées, l'étape de lecture arrive et c'est plus délicat... En effet, les seules fonctions permettant de lire des données dans la Flash sont celles que nous avons vu juste avant, et elles ne permettent donc que de récupérer qu'un char... Je sens qu'on va s'amuser ! 😛 Il va donc falloir créer une boucle pour tout récupérer ! Comme ici le contenu stocké est une chaîne de caractères, nous allons détecter le caractère de fin de chaîne pour arrêter la boucle. Il n'y a pas de solutions magiques, chaque cas doit avoir son traitement (si vous ne stocker pas que des chaînes de caractères). Cette fois-ci, par contre, nous n'allons pas mettre le symbole '&' devant le nom de la variable dans la fonction pgm_read_byte(). En effet, un tableau représente déjà une adresse mémoire et il n'est donc pas nécessaire d'utiliser le '&' pour l'indiquer.

Une autre solution existe cependant pour les chaînes de caractères uniquement. En effet, si vous voulez utiliser une chaîne sans vous fatiguer, vous pouvez simplement utiliser :

Lors de la compilation, tout le mécanisme de stockage et de lecture sera ainsi mis en place de manière transparente. Par exemple vous pourriez afficher la même chose que ci-dessus en faisant :

Cela dit, si vous devez utiliser plusieurs fois la même chaîne de caractères cette solution n'est pas idéale puisque l'espace de stockage utilisé sera différent pour chaque appel de cette fonction même si le contenu ne change pas, ce qui vous fera donc consommer de la mémoire pour rien... enfin si, pour ne pas se fatiguer avec le code ! :mrgreen:

Vous en savez maintenant un peu plus sur les différents types de mémoires présentes au sein d'Arduino. Cependant, si vous avez toujours un besoin plus important de mémoire, vous pouvez essayer de vous tourner vers des composants tels que des EEPROM externes.

35 commentaires

  1. Merci beaucoup.

    A 68 ans ouvrier du bâtiment, je comprend, j’avance et je commence à écrire de petit programme ou modifier de beaucoup plus tel que ceux qui gère le circuit AD 9850.

    Encore une fois merci beaucoup.

  2. Bonjour,
    Je vous remercie pour cette belle présentation de la gestion de la mémoire d’une carte arduino.
    Je voulais savoir s’il est possible de récupérer des données via des capteurs analogiques (température, lumière etc…), les envoyer à l’arduino ( aux entrées analogiques ) et stocker les valeurs mesurées dans la carte arduino.
    Merci d’avance.

  3. Salut Eskimon !
    Au moment ou tu ecris F("Chaine completement en flash !"), il y a un probleme de comprehension :
    Soit « Chaine completement en flash ! » veut dir qu’elle est en actionscript, soit ca veut dire qu’elle est dans la memoire flash; une bonne forme serait « Chaine completement dans la memoire flash ! » !

  4. Salut !
    J’ai pas tout à fais compris un petit point : quelle est l’intérêt d’utiliser le « PROGMEM » si le « const » sauvegarde déjà la variable dans la mémoire flash ?

  5. Pingback: Logiciels, docs | Pearltrees

  6. Bonjour,
    Merci pour ces explications bien détaillées et très utiles ma foi :).
    Juste une question : À quel moment il faut placer sa variable dans l’une des 3 mémoires, quels sont les cas de figures qui pousseraient à placer soit sa variable dans la RAM soit dans l’EEPROM soit dans la Flash ?
    Je demande parce que je suis confronté à un problème, je ne sais pas si je dois mettre ma variable dans l’EEPROM ou Flash.
    J’aimerai en fait que lors d’une coupure de courant par exemple, ma variable garde la valeur courante et reprenne à cette valeur lorsque le courant sera remis.

    Encore merci

    • Pour simplifier :

      FLASH = Lecture seule
      EEPROM = si besoin de mémoire non volatile
      RAM = Fonctionnement normal, mais volatile (donc qui disparaît lors d’une coupure de courant)

      Dans ton cas, il faudra donc être en mesure de détecter la coupure de courant pour (rapidement) sauvegarder la variable a ce moment la puis la relire plus tard (dans le setup). Il faut éviter de sauvegarder sans arrêt dans l’EEPROM (en se disant « je sauvegarde toutes les secondes au cas ou) car cette mémoire n’est pas adaptée pour ce genre d’utilisation.

      • Bonjour,
        Merci pour ce retour.
        Si FLASH = Lecture Seule pourquoi on peut y enregistrer des données comme la chaine de caractère dans ce tuto ?
        C’est difficile de détecter une coupure de courant dans la mesure où l’Arduino doit être alimenter pour détecter cette coupure.Pas de courant pas de détection possible.
        J’aimerai éviter justement de sauvegarder toutes les secondes dans la EEPROM pour ne pas l’user trop rapidement.

        • J’ai manque de précision effectivement. Dans la Flash, on peut y mettre des données a la compilation (grossièrement) puis ensuite, au fonctionnement on ne pourra que lire ces données.

          Pour détecter le courant ET pouvoir enregistrer, il faudra utiliser une réserve d’énergie qui pourra alimenter le mode « sauvegarde en catastrophe » de l’Arduino. Par exemple en utilisant un condensateur et un peu d’électronique (pour plus d’infos je te propose d’ouvrir un sujet sur Zeste de Savoir 🙂 ).

          • Ah dac, à la compilation uniquement…
            Je vais de ce pas ouvrir le sujet.
            Merci

  7. Pingback: Arduino et ses mémoires | Quai Lab

    • Oui un int correspond bien a deux octets (sur Arduino). Mais la fonction EEPROM.write() ne peut écrire qu’un seul octet a la fois (choix cohérent avec la structure interne de l’eeprom qui est divises en case d’un octet). Ensuite c’était au choix des développeurs d’Arduino d’exposer ou non une fonction permettant d’ecrire un octet ou deux a la fois. Ils ont pris le premier choix, pourquoi pas (assez logique, il permet de sauvegarder des char sans gaspiller d’espace).

      Mais j’ai peut-être mal compris ta remarque ^^

      • Bonjour & merci pour votre réponse rapide.

        C’est parfaitement clair comme cela.
        C’était une question de forme et de structure dans les variables. On se retrouvera donc avec dans le programme des INT dont la valeur sera de -2^15 à 2^15 -1 (INT « classique » – 2 octets signés) et d’autres dont la valeur sera de 0 à 2^8 – 1 (INT « EEPROM » – 1 octet). En cas de modification, il serait donc bon de prendre en compte un test de débordement de mémoire afin de s’assurer que la variable n’est pas plus grande que la mémoire qui lui est allouée.

        Merci encore de votre réponse et meilleurs vœux pour cette nouvelle année.

        • Ce que tu appelles « int eeprom » n’est rien d’autre qu’un char, le type « de base et universel » qui contient 1 seul octet quel que soit la machine (microcontrôleur 8 bits ou PC 64 bits, il reste 1 octet !)

          • Jusque là, nous sommes donc d’accord un octet est un octet. Merci.

            Le point que je soulève est que dans le sketch Arduino un INT (1 octet stocké en EEPROM) n’est plus réellement un INT avec cette méthode (définit sur 2 octets, cf documentation officielle). Il existe donc un risque d’overflow si ce point n’est pas bien maîtrisé. Confronté à ce problème, je profite de cet excellent tutoriel pour partager ce retour.

            Bien à vous.

          • J’avoue être perdu sur ce qui pose problème (notamment a quel sketch Arduino fais tu reference ? Ceux du tuto ? )… Dans le tuto je propose bien de stocker un int en l’eclatant en 2 fois 1 octet puis de le « reassembler » quand on le recupere. Vu que l’on fait toutes les operations bit a bit on ne risque normalement rien. (Mais encore une fois, j’ai peut etre mal compris la question)

  8. Bonjour Eskimon,

    Un grand merci pour ton tuto qui m’a permis de comprendre que je remplissais trop la mémoire ram.
    Comportement aléatoire et plantages divers… J’ai donc stocké mes musiques buzzer dans la flash.

    Bonne journée 😉

  9. Hello,
    merci pour les routines INT eeprom, j’ai pas eu besoin de réinventer la roue 🙂

    et voila aussi en plus condensée tes routine INT :

    int EepromReadInt (byte adresse) {
    return (EEPROM.read(adresse) <> 8) & 0x00FF); //poids fort
    EEPROM.write(adresse + 1, valeur & 0x00FF); // poids faible
    }

    Stef

  10. la librairie eepromex est parfaite pour ça.
    mais (oui il y a toujours exception) quand tu joue avec un ESP8266, elle n’est pas compatible avec sa gestion eeprom (qui utilise une zone de sa flash).

    les deux codes de read et write int sont exactement les codes de Eskimon, juste réécrit autrement.
    pour le coté pédagogique de la chose, j’ai partagé mon écriture pour permettre aussi aux débutants de comparer les deux façon d’écrire la meme chose en gagnant aussi sur l’empreinte mémoire.

    et puis comme je le dis plus haut, quand tu utilises autre chose qu’un Arduino, les librairies ne sont pas forcement (encore) compatibles (peut être même jamais pour certaines qui utilisent certaines particularités hardwares).

    alors avant de dire que ce n’est pas nécessaire…

    Stef

Laisser un commentaire