Cosa posso fare se esaurisco la memoria Flash o SRAM?


28

Secondo la documentazione di Arduino, l'ATmega328 ha 32 KB di memoria Flash per il bootloader + schizzo caricato e solo 2 KB di SRAM per i dati di runtime. L'ATmega2560 ne ha un po 'di più, per un totale di 256 KB e 8 KB rispettivamente.

In entrambi i casi, tali limiti sembrano piuttosto piccoli, soprattutto se confrontati con dispositivi di consumo di dimensioni simili, come gli smartphone.

Cosa puoi fare se finisci? Ad esempio, se lo schizzo è troppo grande o è necessario elaborare molti dati (come le stringhe) in fase di esecuzione? Esiste un modo per espandere Flash o SRAM?


Prova a utilizzare alcune ottimizzazioni variabili. Qui
TheDoctor,

1
Usa gli ambiti corretti per le tue variabili se non lo fai già, il compilatore ottimizzerà l'utilizzo della RAM per te quando le variabili non sono utilizzate.
jippie,

1
Potresti effettivamente utilizzare un Teensy 3.2 (con il software Teensyduino), che sarebbe paragonabile a un Arduino. Dato che stai esaurendo la RAM / PROGMEM, ciò significherebbe che probabilmente stai anche spingendo Arduino. Un Teensy 3.2 non è molto più costoso. ma ha: 32 bit, 72 MHz (wtf !?) 256 KB FLASH e 64 KB RAM e 3x UART. Non più memoria di programma come ATmega2560, ma l'aumento della RAM e della velocità dovrebbe essere sufficiente.
Paul,

Risposte:


30

Ottimizzazione
La programmazione di basso livello per sistemi embedded è molto diversa dalla programmazione per dispositivi di uso generale, come computer e telefoni cellulari. L'efficienza (in termini di velocità e spazio) è molto più importante perché le risorse sono a un prezzo elevato. Ciò significa che la prima cosa da fare se si esaurisce lo spazio è esaminare quali parti del codice è possibile ottimizzare.

In termini di riduzione dell'utilizzo dello spazio del programma (Flash), la dimensione del codice può essere piuttosto difficile da ottimizzare se non si ha esperienza o se si è più abituati alla programmazione per computer desktop che non hanno bisogno di tale competenza. Sfortunatamente, non esiste un approccio a "proiettile magico" che funzioni in tutte le situazioni, anche se aiuta a considerare seriamente ciò che il tuo schizzo deve davvero avere. Se una funzione non è necessaria, eliminala.

A volte è anche utile identificare dove più parti del codice sono uguali (o molto simili). Potresti essere in grado di condensarli in funzioni riutilizzabili che possono essere chiamate da più punti. Tuttavia, tieni presente che a volte provare a rendere il codice troppo riutilizzabile finisce per renderlo più dettagliato. È un equilibrio difficile da colpire che tende a venire con la pratica. Trascorrere del tempo a guardare come le modifiche al codice influiscono sull'output del compilatore può aiutare.

L'ottimizzazione dei dati di runtime (SRAM) tende ad essere un po 'più semplice quando ci si è abituati. Una trappola molto comune per i programmatori principianti sta usando troppi dati globali. Tutto ciò che viene dichiarato nell'ambito globale esisterà per l'intera durata dello schizzo e ciò non è sempre necessario. Se una variabile viene utilizzata solo all'interno di una funzione e non deve persistere tra le chiamate, impostarla come variabile locale. Se un valore deve essere condiviso tra le funzioni, considerare se è possibile passarlo come parametro invece di renderlo globale. In questo modo utilizzerai SRAM per quelle variabili solo quando ne avrai davvero bisogno.

Un altro killer per l'utilizzo di SRAM è l'elaborazione del testo (ad es. Utilizzando la Stringclasse). In generale, dovresti evitare di eseguire operazioni su String, se possibile. Sono enormi maiali della memoria. Ad esempio, se si sta inviando molto testo in seriale, utilizzare più chiamate Serial.print()invece di utilizzare la concatenazione di stringhe. Prova anche a ridurre il numero di letterali stringa nel tuo codice, se possibile.

Evitare anche la ricorsione, se possibile. Ogni volta che viene effettuata una chiamata ricorsiva, lo stack raggiunge un livello più profondo. Rifattorizza invece le tue funzioni ricorsive in modo iterativo.

Usa EEPROM
EEPROM è usato per conservare a lungo termine cose che cambiano solo occasionalmente. Se è necessario utilizzare elenchi di grandi dimensioni o tabelle di ricerca di dati fissi, prendere in considerazione la possibilità di archiviarli in anticipo in EEPROM e di estrarre ciò di cui si ha bisogno solo quando necessario.

Ovviamente EEPROM ha dimensioni e velocità piuttosto limitate e ha un numero limitato di cicli di scrittura. Non è un'ottima soluzione alle limitazioni dei dati, ma potrebbe essere sufficiente per alleviare l'onere per Flash o SRAM. È anche del tutto possibile interfacciarsi con una memoria esterna simile, come una scheda SD.

Espansione
Se hai esaurito tutte le altre opzioni, l'espansione potrebbe essere una possibilità. Sfortunatamente, non è possibile espandere la memoria Flash per aumentare lo spazio del programma. Tuttavia, è possibile espandere SRAM. Ciò significa che potresti essere in grado di riformattare il tuo schizzo per ridurre la dimensione del codice a spese dell'aumento della dimensione dei dati.

Ottenere più SRAM è in realtà abbastanza semplice. Un'opzione è utilizzare uno o più chip 23K256 . Sono accessibili tramite SPI e c'è la libreria SpiRAM per aiutarti a usarli. Basta fare attenzione che funzionano a 3,3 V non a 5 V!

Se stai usando il Mega, puoi in alternativa ottenere scudi di espansione SRAM da Lagrangian Point o Rugged Circuits .


1
È inoltre possibile archiviare dati costanti nella memoria del programma, anziché in SRAM, se si hanno problemi di spazio SRAM e memoria di programma libera. Vedi qui o qui
Connor Wolf,

1
Un'altra ottima alternativa a EEPROM è una scheda SD. Occupa alcune porte I / O, ma se hai bisogno di una grande porzione di spazio per, diciamo dati di mappe o simili, può essere facile scambiare e modificare con un programma personalizzato su un PC.
Pinguino anonimo,

1
Le persone non dovrebbero essere incoraggiate a usare SPI SRAM o espansioni RAM, se stanno esaurendo la memoria. È solo uno spreco di denaro. Scegliere un MCU più grande sarebbe più economico. Inoltre, le prestazioni potrebbero essere molto scadenti. Bisogna prima fare una stima del ballpark: se l'utilizzo della RAM stimato è troppo vicino al limite, allora stai scegliendo la scheda / microcontrollore / piattaforma di sviluppo sbagliata. Certo, un buon utilizzo (memorizzazione delle stringhe in flash) e l'ottimizzazione (evitando l'uso di alcune librerie) possono essere dei veri e propri cambi di gioco. Tuttavia, a questo punto non vedo alcun vantaggio nell'uso della piattaforma software Arduino.
prossimo hack del

24

Quando carichi il tuo codice sul tuo Arduino, ad esempio uno Uno, ti dirà quanti byte utilizza fino a 32 KB disponibili. Ecco quanta memoria flash hai (pensa al disco rigido del computer). Mentre il tuo programma è in esecuzione, utilizza quello che si chiama SRAM, e ce n'è molto meno disponibile.

A volte noterai che il tuo programma si comporta in modo strano a un punto che non hai nemmeno toccato da un po 'di tempo. È possibile che le modifiche più recenti causino l'esaurimento della memoria (SRAM). Ecco alcuni suggerimenti su come liberare un po 'di SRAM.

Memorizzazione di stringhe in Flash anziché in SRAM.

Una delle cose più comuni che ho visto è la memoria insufficiente del chip perché ci sono troppe stringhe lunghe.

Utilizzare la F()funzione quando si utilizzano le stringhe in modo che siano archiviate in Flash anziché in SRAM, poiché ne si dispone molto di più.

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

Usa i giusti tipi di dati

È possibile salvare un byte passando da int(2 byte) a byte(1 byte). Un byte senza segno ti darà 0-255, quindi se hai numeri che non superano 255, salva un byte!

Come faccio a sapere che sto esaurendo la memoria?

Di solito osserverai il tuo programma comportarsi in modo strano e ti chiederai cosa è andato storto ... Non hai cambiato nulla nel codice vicino al punto in cui è incasinato, quindi cosa ti dà? Si sta esaurendo la memoria.

Ci sono un paio di funzioni per dirti quanta memoria disponibile hai.

Memoria disponibile


Sai se la F()cosa è una funzione specifica di Arduino o è nelle librerie AVR? Potresti considerare di menzionare PROGMEM const ...anche.
jippie,

Inoltre, puoi utilizzare le strutture di bit per ridurre ulteriormente lo spazio utilizzato dalle variabili 5eg se hai a che fare con un sacco di valori booleani).
jfpoilpret,

17

Oltre a ciò che altri hanno detto (su cui concordo pienamente), consiglierei di leggere questo articolo di adafruit sulla memoria; è ben scritto, spiega molte cose sulla memoria e fornisce suggerimenti su come ottimizzarla.

Alla fine della lettura, penso che otterrai una risposta abbastanza completa alla tua domanda.

Per riassumere, hai 2 possibili obiettivi di ottimizzazione (a seconda di dove si trovano i problemi di memoria):

  • Flash (ad es. Memoria di programma); per questo puoi:
    • rimuovere il codice morto (ad es. qualsiasi codice incluso ma non utilizzato) e le variabili non utilizzate (che si aiuta anche con SRAM)
    • estrarre il codice duplicato
    • rimuovere del tutto il bootloader (è possibile guadagnare tra 0,5K per UNO e 2 o 4K per altri modelli Arduino); questo ha alcuni aspetti negativi però
  • SRAM (ovvero stack, heap e dati statici); per questo puoi:
    • rimuovere le variabili non utilizzate
    • ottimizzare le dimensioni di ciascuna variabile (ad es. non utilizzare long -4 byte- se sono necessari solo int -2 byte)
    • usa l'ambito giusto per le tue variabili (e preferisci lo stack ai dati statici quando possibile)
    • ridurre le dimensioni dei buffer al minimo indispensabile
    • sposta i dati costanti su PROGMEM (ovvero i tuoi dati statici rimarranno nella memoria Flash e non verranno copiati su SRAM all'avvio del programma); questo vale anche per stringhe costanti per le quali è possibile utilizzare la F()macro)
    • evitare l'allocazione dinamica se non è assolutamente necessario; eviterai un mucchio frammentato che potrebbe non restringersi anche dopo aver liberato la memoria

Viene anche descritto un ulteriore approccio per ridurre l'utilizzo della SRAM (ma usato raramente, poiché è un po 'pesante durante la codifica e non molto efficiente), consiste nell'utilizzare EEPROM per archiviare i dati creati dal programma, ma non utilizzato fino a quando in determinate condizioni si verificano quando i dati possono essere ricaricati dalla EEPROM.


1
Rimozione del codice morto: il compilatore è davvero bravo a gestirlo per te, non farà alcuna differenza se hai un sacco di codice che non è mai stato chiamato. Se si chiama accidentalmente il codice che non è necessario, è diverso, ovviamente.
dethSwatch

9

Ci sono due cose da fare se si esaurisce la memoria:

  • In qualche modo "ottimizza" il tuo codice, quindi ha bisogno di meno spazio di archiviazione; o almeno utilizza meno del particolare tipo di spazio di archiviazione che hai esaurito (e utilizza più del tipo di spazio di archiviazione di cui hai ancora un sacco). O,
  • Aggiungi più spazio di archiviazione.

Ci sono molti consigli online su come fare per primi (e per la stragrande maggioranza delle cose che le persone fanno con Arduino, lo spazio di archiviazione integrato è più che sufficiente dopo "l'ottimizzazione"). Quindi mi concentrerò sul secondo:

Ci sono 3 cose che usano flash o SRAM; ognuno ha bisogno di un approccio leggermente diverso per aggiungere spazio di archiviazione:

  • memoria variabile: è possibile espandere SRAM, come già sottolineato da Sachleen. SRAM, FRAM e NVSRAM sono tutti appropriati per le variabili che cambiano rapidamente. (Mentre in linea di principio è possibile utilizzare il flash per memorizzare le variabili, è necessario preoccuparsi dell'usura del flash). SPI (un protocollo seriale) è il più semplice da collegare ad Arduino. La libreria SpiRAM funziona con il chip SRAM seriale Microchip 23K256 . Anche il chip FRAM seriale FM25W256 di Ramtron (ora di proprietà di Cypress) utilizza SPI. Cypress CY14B101 NVSRAM utilizza anche SPI. Eccetera.

  • dati costanti che devono essere ancora presenti la prossima volta che si accende: questo è quasi semplice quanto espandere SRAM. Sono disponibili molti dispositivi di archiviazione EEPROM, FRAM, NVSRAM e FLASH esterni . Attualmente il costo più basso per MB sono le schede flash SD (a cui è possibile accedere tramite SPI). Il Ramtron FM25W256 (vedi sopra), il Cypress CY14B101 (vedi sopra), ecc. Possono anche memorizzare dati costanti. Molti scudi di espansione includono uno slot per schede SD e diverse librerie ed esercitazioni supportano la lettura e la scrittura su schede (flash) SD. (Non possiamo usare SRAM per questo, perché SRAM dimentica tutto quando si spegne).

  • codice eseguibile: Sfortunatamente, non è possibile espandere la memoria Flash di Arduino per aumentare lo spazio del programma. Tuttavia, un programmatore può sempre eseguire il refactoring di uno schizzo per ridurre la dimensione del codice a spese dell'aumento della dimensione dei dati e della sua esecuzione leggermente più lenta. (In teoria, potresti andare fino a tradurre l'intero schizzo in un linguaggio interpretato, memorizzare quella versione del tuo schizzo su una scheda SD e quindi scrivere un interprete per quel linguaggio che gira su Arduino per recuperare ed eseguire le istruzioni dal Scheda SD - Avanti su Arduino , un interprete BASIC, un interprete Tom Napier Picaro, un linguaggio specifico dell'applicazione, ecc.).

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.