Je voulais enregistrer certaines valeurs dans l'EEPROM et je voulais également libérer de la mémoire SRAM en évitant certaines déclarations de variables, mais la mémoire EEPROM est en octets.
Si je veux stocker une valeur int, je dois utiliser plusieurs expressions à plusieurs reprises. Je pensais que je ferais quelques fonctions pour ceux-ci. Mais je crains que, si je crée une fonction, elle occupe toujours la mémoire SRAM, mieux je déclare une variable int au lieu d'utiliser EEPROM.
Comment les fonctions et les variables locales sont-elles stockées dans SRAM? Est-ce qu'il stocke uniquement l'adresse du pointeur fuction à partir de la mémoire flash ou toutes les variables et commandes sont stockées sur la pile?
sram
eeprom
memory-usage
Nafis
la source
la source
Réponses:
Seules les données de la fonction sont stockées sur la pile; son code reste en flash. Vous ne pouvez pas vraiment réduire l'utilisation de SRAM en utilisant plutôt l'EEPROM car, comme vous l'avez vu, l'EEPROM n'est pas adressable de la même manière. Le code pour lire et stocker l'EEPROM doit également utiliser de la mémoire SRAM - probablement autant de mémoire SRAM que vous tentiez d'enregistrer! L'EEPROM est également lente à écrire et a une durée de vie limitée (en nombre d'écritures dans chaque octet), ce qui la rend peu pratique à utiliser pour stocker le type de données temporaires que nous mettons habituellement sur la pile. Il est mieux adapté à la sauvegarde de données rarement modifiées, comme la configuration unique des appareils pour les appareils produits en série, ou à la capture d'erreurs peu fréquentes pour une analyse ultérieure.
Modifié: il n'y a pas de pile pour cette fonction jusqu'à ce que la fonction soit appelée, donc oui, c'est à ce moment-là que les données de la fonction y sont mises. Ce qui se passe après le retour de la fonction, c'est que sa trame de pile (sa zone réservée de SRAM) n'est plus réservée. Il sera éventuellement réutilisé par un autre appel de fonction. Voici un schéma d'une pile C en mémoire. Lorsqu'un cadre de pile n'est plus utile, il est simplement libéré et sa mémoire devient disponible pour être réutilisée.
la source
Les variables locales et les paramètres de fonction sont stockés sur la pile. Cependant, ce n'est pas une raison pour ne pas les utiliser. Les ordinateurs sont conçus pour fonctionner de cette façon.
La mémoire de pile n'est utilisée que lorsqu'une fonction est active. Dès que la fonction revient, la mémoire est libérée. La mémoire de pile est une BONNE chose.
Vous ne voulez pas utiliser de fonctions récursives avec beaucoup de niveaux de récursivité ou allouer beaucoup de grandes structures sur la pile. Une utilisation normale est cependant très bien.
La pile 6502 ne fait que 256 octets, mais l'Apple II fonctionne très bien.
la source
L'AVR (la famille de microcontrôleurs traditionnellement utilisée sur les cartes Arduino) est une architecture Harvard , ce qui signifie que le code exécutable et les variables sont dans deux mémoires distinctes - dans ce cas, flash et SRAM. Le code exécutable ne quitte jamais la mémoire flash.
Lorsque vous appelez une fonction, l'adresse de retour est généralement envoyée à la pile - l'exception est lorsque l'appel de fonction se produit à la fin de la fonction appelante. Dans ce cas, l'adresse de retour de la fonction qui a appelé la fonction appelante sera utilisée à la place - elle est déjà sur la pile.
Si d'autres données sont placées sur la pile, cela dépend de la pression de registre dans la fonction appelante et dans la fonction appelée. Les registres sont la zone de travail du CPU, l'AVR a 32 registres de 1 octet. Les registres sont accessibles directement par des instructions CPU, tandis que les données dans SRAM devront d'abord être stockées dans des registres. Ce n'est que si les arguments ou la variable locale sont trop grands ou trop nombreux pour tenir dans les registres qu'ils seront placés sur la pile. Cependant, les structures sont toujours stockées sur la pile.
Vous pouvez lire les détails de l'utilisation de la pile par le compilateur GCC sur la plate-forme AVR ici: https://gcc.gnu.org/wiki/avr-gcc#Frame_Layout
Lisez les sections "Frame Layout" et "Calling Convention" .
la source
Immédiatement lors d'un appel de fonction entrant dans la fonction, le premier code qui est exécuté consiste à décrémenter le pointeur de pile d'une quantité égale à l'espace requis pour les variables temporaires internes à la fonction. La chose brillante à ce sujet est que toutes les fonctions deviennent donc rentrantes et récursives, car leurs variables sont construites sur la pile du programme appelant. Cela signifie que si une interruption arrête l'exécution d'un programme et transfère l'exécution à un autre, elle peut également appeler la même fonction sans interférer les unes avec les autres.
la source
J'ai essayé très fort de créer un exemple de code pour démontrer ce que les excellentes réponses ici disent, sans succès jusqu'à présent. La raison en est que le compilateur optimise agressivement les choses. Jusqu'à présent, mes tests n'ont pas du tout utilisé la pile, même avec des variables locales dans une fonction. Les raisons sont les suivantes:
Le compilateur peut en ligne l'appel de fonction, donc l'adresse de retour peut ne pas être poussée du tout sur la pile. Exemple:
void foo (byte a) { digitalWrite (13, a); } void loop () { foo (5); }
Le compilateur transforme cela en:
void loop () { digitalWrite (13, 5); }
Aucun appel de fonction, aucune pile utilisée.
Le compilateur peut passer des arguments dans les registres , ce qui lui évite de les pousser sur la pile. Exemple:
digitalWrite (13, 1);
Se compile en:
158: 8d e0 ldi r24, 0x0D ; 13 15a: 61 e0 ldi r22, 0x01 ; 1 15c: 0e 94 05 01 call 0x20a ; 0x20a <digitalWrite>
Les arguments sont placés dans des registres et donc aucune pile n'est utilisée (à part l'adresse de retour pour appeler digitalWrite).
Le compilateur optimise les variables que vous n'utilisez pas. Exemple:
void foo (byte a) { unsigned long bar [100]; bar [1] = a; digitalWrite (9, bar [1]); } void loop () { foo (3); } // end of loop
Maintenant, il faut allouer 400 octets pour "bar", n'est-ce pas? Nan:
00000100 <_Z3fooh>: 100: 68 2f mov r22, r24 102: 89 e0 ldi r24, 0x09 ; 9 104: 0e 94 cd 00 call 0x19a ; 0x19a <digitalWrite> 108: 08 95 ret 0000010a <loop>: 10a: 83 e0 ldi r24, 0x03 ; 3 10c: 0e 94 80 00 call 0x100 ; 0x100 <_Z3fooh> 110: 08 95 ret
Le compilateur a optimisé l' ensemble du tableau ! Cela peut dire que nous ne faisons vraiment qu'un
digitalWrite (9, 3)
et c'est ce qu'il génère.Morale de l'histoire: n'essayez pas de dépasser le compilateur.
la source