Que puis-je faire si je manque de mémoire Flash ou de SRAM?

28

Selon la documentation Arduino, l'ATmega328 a 32 Ko de mémoire Flash pour le chargeur de démarrage + le croquis téléchargé, et seulement 2 Ko de SRAM pour les données d'exécution. L'ATmega2560 en a un peu plus, totalisant respectivement 256 Ko et 8 Ko.

Dans les deux cas, ces limites semblent plutôt petites, en particulier par rapport aux appareils grand public de taille similaire, tels que les smartphones.

Que pouvez-vous faire si vous manquez? Par exemple, si votre esquisse est trop volumineuse ou si vous devez traiter beaucoup de données (telles que des chaînes) lors de l'exécution? Existe-t-il un moyen d'étendre Flash ou SRAM?

Peter Bloomfield
la source
Essayez d'utiliser une optimisation variable. Certaines variables différentes sont discutées ici
TheDoctor
1
Utilisez des portées appropriées pour vos variables si ce n'est pas déjà fait, le compilateur optimisera l'utilisation de la RAM pour vous lorsque les variables ne sont pas utilisées.
jippie
1
Vous pourriez en fait utiliser un Teensy 3.2 (avec le logiciel Teensyduino), qui serait comparable à un Arduino. Étant donné que vous manquez de RAM / PROGMEM, cela signifie que vous êtes également susceptible de pousser votre Arduino. Un Teensy 3.2 n'est pas beaucoup plus cher. mais a: 32 bits, 72 MHz (wtf!?) 256 Ko de FLASH et 64 Ko de RAM et 3x UART. Pas plus de mémoire programme que l'ATmega2560, mais l'augmentation de RAM et de vitesse devrait suffire.
Paul

Réponses:

30

Optimisation
La programmation de bas niveau pour les systèmes embarqués est très différente de la programmation pour les appareils à usage général, tels que les ordinateurs et les téléphones portables. L'efficacité (en termes de vitesse et d'espace) est beaucoup plus importante car les ressources sont précieuses. Cela signifie que la toute première chose à faire si vous manquez d'espace est de regarder quelles parties de votre code vous pouvez optimiser.

En termes de réduction de l'utilisation de l'espace programme (Flash), la taille du code peut être assez difficile à optimiser si vous êtes inexpérimenté ou si vous êtes plus habitué à la programmation pour les ordinateurs de bureau qui n'ont généralement pas besoin de cette compétence. Malheureusement, il n'y a pas d'approche miracle qui fonctionnera dans toutes les situations, bien que cela aide si vous considérez sérieusement ce que votre croquis doit vraiment avoir. Si une fonctionnalité n'est pas nécessaire, retirez-la.

Parfois, il est également utile d'identifier où plusieurs parties de votre code sont identiques (ou très similaires). Vous pourrez peut-être les condenser en fonctions réutilisables qui peuvent être appelées à partir de plusieurs endroits. Cependant, sachez que parfois, essayer de rendre le code trop réutilisable finit par le rendre plus verbeux. C'est un équilibre délicat à frapper qui a tendance à venir avec la pratique. Passer du temps à regarder comment les modifications de code affectent la sortie du compilateur peut aider.

L'optimisation des données d'exécution (SRAM) a tendance à être un peu plus facile lorsque vous y êtes habitué. Un écueil très courant pour les programmeurs débutants utilise trop de données globales. Tout ce qui est déclaré à l'échelle mondiale existera pendant toute la durée de vie du croquis, et ce n'est pas toujours nécessaire. Si une variable n'est utilisée que dans une fonction et qu'elle n'a pas besoin de persister entre les appels, faites-en une variable locale. Si une valeur doit être partagée entre les fonctions, demandez-vous si vous pouvez la passer comme paramètre au lieu de la rendre globale. De cette façon, vous n'utiliserez SRAM pour ces variables que lorsque vous en aurez réellement besoin.

Un autre tueur pour l'utilisation de SRAM est le traitement de texte (par exemple en utilisant la Stringclasse). De manière générale, vous devez éviter de faire des opérations String si possible. Ce sont des porcs de mémoire massifs. Par exemple, si vous sortez beaucoup de texte en série, utilisez plusieurs appels à Serial.print()au lieu d'utiliser la concaténation de chaînes. Essayez également de réduire le nombre de littéraux de chaîne dans votre code si possible.

Évitez aussi la récursivité si possible. Chaque fois qu'un appel récursif est effectué, la pile prend un niveau plus profond. Refactorisez vos fonctions récursives pour qu'elles soient itératives à la place.

Utiliser l'EEPROM L'
EEPROM est utilisée pour le stockage à long terme de choses qui ne changent qu'occasionnellement. Si vous devez utiliser de grandes listes ou des tables de recherche de données fixes, envisagez de les stocker à l'avance dans l'EEPROM et de ne retirer ce dont vous avez besoin que si nécessaire.

De toute évidence, l'EEPROM est assez limitée en taille et en vitesse, et a un nombre limité de cycles d'écriture. Ce n'est pas une excellente solution aux limitations de données, mais cela pourrait suffire à alléger le fardeau de Flash ou SRAM. Il est également tout à fait possible de s'interfacer avec un stockage externe similaire, comme une carte SD.

Expansion
Si vous avez épuisé toutes les autres options, l'extension peut être une possibilité. Malheureusement, l'extension de la mémoire Flash pour augmenter l'espace du programme n'est pas possible. Cependant, il est possible d'étendre SRAM. Cela signifie que vous pourrez peut-être refactoriser votre croquis pour réduire la taille du code au détriment de l'augmentation de la taille des données.

Obtenir plus de SRAM est en fait assez simple. Une option consiste à utiliser une ou plusieurs puces 23K256 . Ils sont accessibles via SPI, et il y a la bibliothèque SpiRAM pour vous aider à les utiliser. Attention, ils fonctionnent à 3,3 V et non à 5 V!

Si vous utilisez le Mega, vous pouvez également obtenir des boucliers d'extension SRAM à partir de Lagrangian Point ou de Rugged Circuits .

Peter Bloomfield
la source
1
Vous pouvez également stocker des données constantes dans la mémoire programme, plutôt que SRAM, si vous avez des problèmes d'espace SRAM et de la mémoire programme libre. Voir ici ou ici
Connor Wolf
1
Une autre excellente alternative à l'EEPROM est une carte SD. Il prend quelques ports d'E / S, mais si vous avez besoin d'un grand espace pour, par exemple, des données cartographiques ou similaires, il peut être facile d'échanger et de modifier avec un programme personnalisé sur un PC.
Anonymous Penguin
1
Les gens ne devraient pas être encouragés à utiliser des extensions SPI SRAM ou RAM, si leur mémoire est insuffisante. C'est juste un gaspillage d'argent. Choisir un MCU plus grand serait moins cher. De plus, les performances pourraient être très médiocres. Il faut d'abord faire une estimation approximative: si l'utilisation estimée de la RAM est trop proche de la limite, alors vous choisissez la mauvaise carte / microcontrôleur / plate-forme de développement. Bien sûr, une bonne utilisation (stockage des chaînes en flash) et une optimisation (éviter d'utiliser certaines bibliothèques) peuvent être de véritables modificateurs de jeu. Cependant, à ce stade, je ne vois aucun avantage à utiliser la plate-forme logicielle Arduino.
prochain hack le
24

Lorsque vous téléchargez votre code sur votre Arduino, dites un Uno par exemple, il vous dira combien d'octets il utilise sur les 32 Ko disponibles. C'est la quantité de mémoire flash dont vous disposez (pensez au disque dur de l'ordinateur). Pendant que votre programme est en cours d'exécution, il utilise ce qu'on appelle SRAM, et il y en a beaucoup moins disponible.

Parfois, vous remarquerez que votre programme se comporte bizarrement à un point que vous n'avez même pas touché depuis longtemps. Il se peut que vos modifications les plus récentes entraînent un manque de mémoire (SRAM). Voici quelques conseils pour libérer de la mémoire SRAM.

Stockage de chaînes dans Flash au lieu de SRAM.

L'une des choses les plus courantes que j'ai vues est la puce qui manque de mémoire car il y a trop de longues chaînes.

Utilisez la F()fonction lorsque vous utilisez des chaînes afin qu'elles soient stockées dans Flash au lieu de SRAM, car vous en avez beaucoup plus disponible.

Serial.println(F("This string will be stored in flash memory"));

Utilisez les bons types de données

Vous pouvez enregistrer un octet en passant d'un int(2 octets) à un byte(1 octet). Un octet non signé vous donnera 0-255, donc si vous avez des nombres qui ne dépassent pas 255, enregistrez un octet!

Comment savoir que je manque de mémoire?

Habituellement, vous observerez que votre programme se comporte étrangement et vous vous demanderez ce qui ne va pas ... Vous n'avez rien changé dans le code près du point où il gâche, alors qu'est-ce qui donne? Il manque de mémoire.

Il existe deux fonctions pour vous indiquer la quantité de mémoire disponible dont vous disposez.

Mémoire disponible

sachleen
la source
Savez-vous si la F()chose est une fonction spécifique à Arduino ou si elle se trouve dans les bibliothèques AVR? Vous pourriez aussi envisager de le mentionner PROGMEM const ....
jippie
Vous pouvez également utiliser des structures de bits pour réduire davantage l'espace utilisé par vos variables 5eg si vous traitez avec beaucoup de booléens).
jfpoilpret
17

En plus de ce que d'autres ont dit (sur lequel je suis entièrement d'accord), je vous conseille de lire cet article sur la mémoire d' adafruit ; il est bien écrit, explique beaucoup de choses sur la mémoire et fournit des conseils pour l'optimiser.

À la fin de la lecture, je pense que vous obtiendriez une réponse assez complète à votre question.

Pour résumer, vous avez 2 cibles d'optimisation possibles (en fonction de l'emplacement de vos problèmes de mémoire):

  • Flash (c.-à-d. Mémoire de programme); pour cela, vous pouvez:
    • supprimer le code mort (par exemple, tout code inclus mais non utilisé) et les variables inutilisées (que l'on aide également avec SRAM)
    • factoriser le code dupliqué
    • supprimer complètement le chargeur de démarrage (vous pouvez gagner entre 0,5 K pour un UNO et 2 ou 4K pour d'autres modèles Arduino); cela a cependant quelques inconvénients
  • SRAM (c'est-à-dire pile, tas et données statiques); pour cela vous pouvez:
    • supprimer les variables inutilisées
    • optimisez la taille de chaque variable (par exemple, n'utilisez pas de longs octets -4 si vous n'avez besoin que de -2 octets)
    • utilisez la bonne portée pour vos variables (et préférez la pile aux données statiques lorsque cela est possible)
    • réduire la taille des tampons au strict minimum
    • déplacer des données constantes vers PROGMEM (c'est-à-dire que vos données statiques resteront dans la mémoire Flash et ne seront pas copiées sur SRAM au démarrage du programme); cela s'applique également aux chaînes constantes pour lesquelles vous pouvez utiliser une F()macro)
    • éviter l'allocation dynamique si elle n'est pas absolument nécessaire; vous éviterez un tas fragmenté qui peut ne pas rétrécir même après avoir libéré de la mémoire

Une approche supplémentaire pour réduire l'utilisation de la SRAM est également décrite (mais rarement utilisée, car elle est un peu lourde lors du codage et peu efficace), elle consiste à utiliser l'EEPROM pour stocker des données construites par votre programme, mais n'est utilisée que plus tard lorsque certaines conditions se produire, lorsque les données peuvent être chargées à partir de l'EEPROM.

jfpoilpret
la source
1
Supprimer le code mort - le compilateur est vraiment bon pour gérer cela pour vous - cela ne fera aucune différence si vous avez beaucoup de code qui n'est jamais appelé. Si vous appelez accidentellement un code dont vous n'avez pas besoin, c'est différent, bien sûr.
dethSwatch
9

Il y a deux choses à faire si vous manquez de stockage:

  • D'une certaine manière, "optimisez" votre code pour qu'il ait besoin de moins de stockage; ou au moins utilise moins du type de stockage particulier dont vous avez manqué (et utilise plus du type de stockage dont vous avez encore beaucoup). Ou,
  • Ajoutez plus de stockage.

Il y a beaucoup de conseils en ligne sur la façon de faire le premier (et pour la grande majorité des choses que les gens font avec l'Arduino, le stockage intégré est plus que suffisant après "l'optimisation"). Je vais donc me concentrer sur le second:

Il y a 3 choses qui utilisent flash ou SRAM; chacun a besoin d'une approche légèrement différente pour ajouter du stockage:

  • stockage variable: il est possible d'étendre SRAM, comme l'a déjà souligné sachleen. SRAM, FRAM et NVSRAM conviennent tous aux variables à évolution rapide. (Alors qu'en principe, vous pouvez utiliser le flash pour stocker des variables, vous devez vous soucier de l'usure du flash). SPI (un protocole série) est le plus facile à connecter à l'Arduino. La bibliothèque SpiRAM fonctionne avec la puce série SRAM Microchip 23K256 . La puce FRAM série Ramtron FM25W256 (qui appartient maintenant à Cypress) utilise également SPI. Le Cypress CY14B101 NVSRAM utilise également SPI. Etc.

  • des données constantes qui doivent toujours être là la prochaine fois que l'alimentation est activée: c'est presque aussi simple que d'étendre la SRAM. Il existe de nombreux périphériques de stockage EEPROM, FRAM, NVSRAM et FLASH externes. Actuellement, le coût par Mo le plus bas sont les cartes flash SD (accessibles via SPI). Le Ramtron FM25W256 (voir ci-dessus), le Cypress CY14B101 (voir ci-dessus), etc. peuvent également stocker des données constantes. De nombreux boucliers d'extension incluent un emplacement pour carte SD, et plusieurs bibliothèques et didacticiels prennent en charge la lecture et l'écriture sur des cartes SD (flash). (Nous ne pouvons pas utiliser SRAM pour cela, car SRAM oublie tout lorsque l'alimentation est coupée).

  • code exécutable: Malheureusement, l'extension de la mémoire Flash d'un Arduino pour augmenter l'espace du programme n'est pas possible. Cependant, un programmeur peut toujours refactoriser une esquisse pour réduire la taille du code au détriment de l'augmentation de la taille des données et de le faire fonctionner un peu plus lentement. (En théorie, vous pouvez aller jusqu'à traduire l'intégralité de votre croquis dans un langage interprété, stocker cette version de votre croquis sur une carte SD, puis écrire un interprète pour cette langue qui s'exécute sur l'Arduino pour récupérer et exécuter des instructions à partir du Carte SD - Forth sur Arduino , un interprète BASIC, un interprète Tom Napier Picaro, un langage spécifique à l'application, etc.).

David Cary
la source