Sylvain Mahé Le site Web Retour à l'accueil Principes Partager mes idées et mes projets librement et gratuitement. Thématiques Mécatronique du système embarqué, artisanat pluridisciplinaire, bricolage commun, esthétique logicielle et matérielle, minimalisme fonctionnel, conceptualisation alternative, rédaction technique et littéraire, partage pédagogique documenté. Contact ✆ Téléphone : 06.45.49.96.98
✉ E-mail : contact@sylvainmahe.site
✎ Site Web : sylvainmahe.site
Écriture de la page : Sylvain Mahé
Lire et écrire dans une mémoire externe de 1Mio avec la classe Spi25aa1024 Une mémoire EEPROM externe plus importante que celle interne au microcontrôleur peut être indispensable pour des projets qui demandent l'enregistrement de beaucoup de données, quelques exemples : - Sauvegarder une partition de musique.
- Sauvegarder des acquisitions périodiques de valeurs de capteurs.
- Sauvegarder les pixels d'une image.
La classe Spi25aa1024 permet très aisément de communiquer avec le composant 25AA1024 qui est une mémoire EEPROM de 1Mio. Les échanges s'effectuent via le bus SPI à la vitesse de 4MHz avec le microcontrôleur (l'automate programmable). Ports des automates programmables concernés par le SPI : Automate programmable MODULABLE 20 :
- Port GPIO 11 (PB2) = SS (slave select)
- Port GPIO 12 (PB3) = MOSI (master output slave input)
- Port GPIO 13 (PB4) = MISO (master input slave output)
- Port GPIO 14 (PB5) = SCK (serial clock)

Automate programmable MODULABLE 32 :
- Port GPIO 5 (PB4) = SS (slave select)
- Port GPIO 6 (PB5) = MOSI (master output slave input)
- Port GPIO 7 (PB6) = MISO (master input slave output)
- Port GPIO 8 (PB7) = SCK (serial clock)
Comme toutes les mémoires EEPROM, la mémoire 25AA1024 offre les caractéristiques suivantes : - Autorise de nombreux cycles de lecture/écriture.
- Est non volatile, cela signifie que la rétention de données perdure même quand celle-ci est coupée de son alimentation électrique.
Les 1048576 octets de la mémoire sont représentés par des emplacements mémoire accessibles à l'aide des fonctions read et write de la classe Spi25aa1024. Lire la mémoire 25AA1024 : La lecture de la mémoire 25AA1024 ne demande pas beaucoup d'opérations. Exemple de lecture de la mémoire 25AA1024 : #include <Spi25aa1024.h> int main() { Spi25aa1024 myExternalMemory = Spi25aa1024 (5); unsigned char myData = 0; myData = myExternalMemory.read (1, 8); return 0; } Dans cet exemple, un objet myExternalMemory de type Spi25aa1024 est déclaré, en paramètre est indiqué d'utiliser le port GPIO numéro 5 de l'automate programmable pour sélectionner l'esclave (slave select) sur le bus SPI. Par habitude en SPI, je connecte la sélection de l'esclave au port de l'automate programmable relié à la fonction SS (slave select) du microcontrôleur quand je le peux, ce qui permet de regrouper tout le câblage relatif au SPI.

Mais en réalité, cette entrée/sortie n'est en fait un port SS à la fonction spécifique que lorsque le SPI est configuré en mode esclave, ce qui n'arrive jamais avec MODULE. Vous pouvez donc choisir l'esclave sur la sortie SS du microcontrôleur, ou tout autre port d'entrée/sortie disponible (sauf MISO qui même inutilisé doit rester comme une entrée libre lorsque le SPI est en fonctionnement).
Puis la fonction read de l'objet myExternalMemory est appelée prenant en 1er paramètre 1, l'emplacement mémoire demandé (soit la lecture du 1er octet de la mémoire). Le 2ème paramètre 8 est le nombre de bits à lire. Ce paramètre peut prendre les valeurs possibles 8, 16, et 32 : - 8 : 8 bits de mémoire seront lus sur l'emplacement mémoire 1.
- 16 : 16 bits de mémoire seront lus sur l'emplacement mémoire 1 à 2.
- 32 : 32 bits de mémoire seront lus sur l'emplacement mémoire 1 à 4.
Et également les valeurs -8, -16, et -32 (voir plus bas : "Lecture et interprétation des nombres négatifs") : - -8 : 8 bits de mémoire seront lus sur l'emplacement mémoire 1.
- -16 : 16 bits de mémoire seront lus sur l'emplacement mémoire 1 à 2.
- -32 : 32 bits de mémoire seront lus sur l'emplacement mémoire 1 à 4.
Bien entendu le nombre de bits indiqué en paramètre doit être cohérent avec ce que vous souhaitez lire, de même avec la taille de donnée de destination (myData dans l'exemple), sauf si ces transformations sont nécessaires et trouvent une logique dans le fonctionnement de votre programme. Lecture et interprétation des nombres négatifs : Si vous souhaitez lire en mémoire EEPROM un nombre signé tout en conservant son interprétation correcte, il convient de renseigner le 2ème paramètre de la fonction read comme étant négatif. Exemple de lecture d'un nombre négatif de 8 bits dans la mémoire 25AA1024 : #include <Spi25aa1024.h> int main() { Spi25aa1024 myExternalMemory = Spi25aa1024 (5); signed char myData = 0; myData = myExternalMemory.read (1, -8); return 0; } Dans cet exemple le 2ème paramètre de la fonction read prend la valeur -8, ce qui force le format retourné sur 8 bits signés. Exemple de lecture d'un nombre négatif de 32 bits dans la mémoire 25AA1024 : #include <Spi25aa1024.h> int main() { Spi25aa1024 myExternalMemory = Spi25aa1024 (5); signed long myData = 0; myData = myExternalMemory.read (1, -32); return 0; } Ici le 2ème paramètre de la fonction read prend la valeur -32, ce qui force le format retourné sur 32 bits signés. Écrire dans la mémoire 25AA1024 : La fonction d'écriture reprend les mêmes principes que la fonction de lecture, soit 1048576 emplacements disponibles et une certaine taille de donnée. Exemple d'écriture d'un octet dans la mémoire 25AA1024 : #include <Spi25aa1024.h> int main() { Spi25aa1024 myExternalMemory = Spi25aa1024 (5); myExternalMemory.write (1, 135, 8); return 0; } Après la déclaration de l'objet myExternalMemory de type Spi25aa1024, la fonction write instanciée à cet objet est appelée prenant en 1er paramètre l'emplacement mémoire demandé, en 2ème paramètre la donnée à écrire dans la mémoire EEPROM, et en 3ème paramètre le nombre de bits qui seront écrits dans la mémoire. Ici c'est le nombre 135 qui est écrit dans la mémoire à l'emplacement 1. Ce nombre occupe 8 bits de mémoire, soit 1 octet. Exemple d'écriture de deux octets dans la mémoire 25AA1024 : #include <Spi25aa1024.h> int main() { Spi25aa1024 myExternalMemory = Spi25aa1024 (5); myExternalMemory.write (1, 6950, 16); return 0; } Dans l'exemple ci-dessus c'est le nombre 6950 qui est écrit dans la mémoire à partir de l'emplacement 1. Il est indiqué que ce nombre occupe 16 bits de mémoire, soit 2 octets. Il s'étend donc jusqu'à l'emplacement 2 de la mémoire. Exemple d'écriture de quatre octets dans la mémoire 25AA1024 : #include <Spi25aa1024.h> int main() { Spi25aa1024 myExternalMemory = Spi25aa1024 (5); myExternalMemory.write (101, -125000, -32); return 0; } Dans cet exemple le nombre -125000 est écrit dans la mémoire à partir de l'emplacement 101. Ce nombre occupe 32 bits de mémoire, soit 4 octets. Il s'étend donc jusqu'à l'emplacement 104 de la mémoire. La fonction write n'est pas sujette à la contrainte des nombres négatifs comme l'est la fonction read, vous pouvez donc renseigner indifféremment le paramètre LENGTH comme étant positif ou négatif (dans l'exemple ci-dessus 32 ou -32). Effacer la mémoire 25AA1024 : Pour effacer la totalité de la mémoire 25AA1024, autrement dit remettre tous les bits à 0, il suffit d'appeler la fonction erase comme le montre l'exemple ci-dessous. Exemple pour effacer la totalité de la mémoire 25AA1024 : #include <Spi25aa1024.h> int main() { Spi25aa1024 myExternalMemory = Spi25aa1024 (5); myExternalMemory.erase(); return 0; } Ci-dessus la fonction erase attachée à l'objet myExternalMemory est appelée, ce qui efface toute la mémoire EEPROM. À noter que les fonctions d'écriture comme write ou d'effacement comme erase (qui est une écriture de 0) offrent l'avantage d'économiser les cycles d'écriture pour garantir la meilleure durée de vie de la mémoire EEPROM. En effet ces fonctions lisent la mémoire avant d'y écrire, de sorte que l'écriture n'intervient que lorsque nécessaire. Références : Récapitulatif des fonctions de cette classe : Spi25aa1024 (const unsigned char PIN_SS); signed long read (const unsigned long ADDRESS, const signed char LENGTH); void write (const unsigned long ADDRESS, const signed long DATA, const signed char LENGTH); void erase();