uso della parola PROGMEM

Buongiorno a tutti!!

Avrei bisogno di un chiarimento riguardo l'istruzione PROGMEM

Praticamente il mio sketch inizia a "sbarellare" a causa probabilmente dellla saturazione della memoria RAM (ho un arduino Uno).
Gironzonlando sul forum ho visto che esiste la possibilita di utilizzare questa macro PROGMEM, in modo da poter salvare degli Array sulla memoria flash.
Tuttavia sto vedendo che questa istruzione è adatta solo per array che vengono inizializzati e usati solo in lettura ( e non in scrittura ), per cui penso che nel mio caso non vada bene, avendo la necessita di dover scrivere e leggere su questi array.
Esiste qualche altra soluzione per recuperare spazio al di la di un eventuale ottimizzazione del programma=

Grazie in anticipo a chi riponde :slight_smile:

Se devi scrivere e leggere sugli array, NON puoi usare Progmem. Progmem dice al compilatore di gestire i dati direttamente dalla Flash senza, prima dell'utilizzo, copiarli in RAM (i micro Atmel sono architetture Harvard per cui hanno memorie separate per il codice e per i dati del programma). Però in Flash tu a runtime non puoi scriverci dallo sketch (lo può fare solo il bootloader), quindi questa soluzione non va bene per te.

Esiste qualche altra soluzione per recuperare spazio al di la di un eventuale ottimizzazione del programma=

Dipende. Ad esempio, fai uso di stampe sulla seriale o su display Lcd? Allora puoi usare la funzione F() per le stringhe di testo. Così:
Serial.println("TEST") --> Serial.println(F("TEST"))

La funzione F() usa proprio Progmem per recuperare le stringhe di testo fisso dalla Flash, senza copiarle in Ram prima di usarle. Salvi un sacco di memoria ma puoi usarla solo su stringhe fisse.
Altra cosa che puoi fare, è ottimizzare il tipo di variabili: dove i numeri non superano il valore di 255, usa il tipo byte. Dove il numero non supera 32767 usa il signed int, dove il numero non passa 65535 e non va sotto zero, usa l'unsigned int. Se non usi la seriale e nel tuo sketch ce l'hai per debug, toglila perché consuma tanta flash e ram. ecc...

La macro F() la sto gia utilizzando....per quanto riguarda la seriale la sto utilizzando per una comunicazione tramite seriale con un display....le stringhe fisse sono tutte in flash.
Quello che sto facendo ora è cercare di utilizzare gli identificatori unsigned e cose varie...
Ma il mio problema sono gli array......ne ho alcuni e sono tutti di caratteri......come posso intervenire ?
se ad esempio faccio una dichiarazione con unsigned char dimezzo l'occupazione di memoria di quell array?
Poi ovviamente quando devo fare una stampa su file o su seriale ad esempio sono costretto ad effetturare la conversione con il modificatore (char*)

Come detto, se nell'array devi anche scriverci non puoi usarlo dalla Flash con PROGMEM. Se invece è un array statico, puoi farlo.
Alcuni link:

http://arduiniana.org/libraries/flash/
http://www.nongnu.org/avr-libc/user-manual/pgmspace.html
http://www.nongnu.org/avr-libc/user-manual/pgmspace_8h.html

PS:
convertire solo una porzione di array dalla Flash ti occupa sempre meno risorse rispetto a convertire l'intero array.
Ad esempio, il firmware per una centralina con display che ho realizzato tempo fa con Michele Menniti aveva non so quante voci di menu tutte in flash, che ripescavo man mano dovevo mandarle a video. Un lavoraccio, ma devi fartene una ragione considerando i 2K di RAM degli Atmega328.. :smiley_cat:

Perdonami per l'ignoranza leo ma cosa intendi per convertire solo una porzione di array in flash?
Mi stai per caso dicendo che una porzione dell'array va in flash ( ovvero quello usata), mentre la restante in RAM?
O non ho capito io?

@ tntsix: Allora, unsigned char e char occupano esattamente lo stesso spazio ... 1 byte ... vatti a rivedere nel reference, sezione "Data types" l'occupazione delle variabili.

Poi, come ti ha detto e ribadito Leo, in PROGMEM si possono mettere SOLO valori COSTANTI ovvero che non cambiano nel corso del programma, che puoi quindi SOLO leggere e NON scrivere.

Se hai delle cose costanti che NON devi alterare, quelle le puoi spostare nella Flash, altrimenti ... devono restare in SRAM ... c'è poco da inventarsi.

Altrimenti, collega una memoria esterna (ce ne sono varie con interfaccia I2C) e appoggia i tuoi dati da leggere/scrivere li ... :roll_eyes:

Guglielmo

Sisi ho verificato con sizeof l'occupazione di memoria di ogni variabile....
Non posso fare molto allora nel mio codice...o trovo un modo per ottimizzarlo altrimenti niente

tntsix:
Non posso fare molto allora nel mio codice...o trovo un modo per ottimizzarlo altrimenti niente

... t'ho detto, esistono memorie esterne facilmente collegabili e gestibili in I2C ... certo, poi è tutto da programma spostare avanti e indietro i dati occorrenti in un dato momento dalla memoria esterna alla SRAM e viceversa ... ::slight_smile:

Guglielmo

tntsix:
Perdonami per l'ignoranza leo ma cosa intendi per convertire solo una porzione di array in flash?
Mi stai per caso dicendo che una porzione dell'array va in flash ( ovvero quello usata), mentre la restante in RAM?
O non ho capito io?

Ti ho detto che i dati, per poterli gestire, devi prima copiarli in RAM. Quindi se tu hai un array ogni elemento sarà composto da qualcosa. Se è un array di stringhe di char, ogni elemento sarà quindi una stringa. Per poterla usare, la devi prima copiare in una stringa di char temporanea. L'occupazione di RAM sarà perciò data solo dalla dimensione della stringa di char.

Questo vale se devi solo leggere questi dati. Se li devi anche scrivere, le cose cambiano. Ma di quanti dati parliamo? Come che frequenza dovresti aggiornarli? Necessiti di velocità oppure no?

No non necessito di velocita....i dati sono caratteri che transitano su seriale e che vengono memorizzati in un array di caratteri

... quindi puoi definire una array di char in SRAM che usi come appoggio e spostarci dentro e fuori degli altri array che metti su una memoria esterna di appoggio. E' una rottura di scatole, ma, progettata bene la cosa, poi funziona efficientemente :wink:

Guglielmo

Purtroppo in inglese, ma Gammon ha scritto una buona guida su PROGMEM:

C'e' anche una parte relativa ad array di stringhe (NON oggetto String, vade retro satana).
Queste "tecniche" di programmazione non sono però semplici per programmatori poco esperti.
Infatti si inizia a parlare di puntatori, un argomento a volte indigesto.

Nid, quello che dovrebbe fare è BANALE … e non serve certo scomodare Gammon per usare quattro chiamate in croce per muovere caratteri (uno ad uno) avanti e indietro verso una memoria esterna.

La cosa più difficile è scrivere il tutto in modo modulare e intelligente in modo che poi … ci si riduca a due funzioni … leggiDaMemoria() e scriviSuMemoria() … ovvero fare swap-in e swap-out :grin:

Guglielmo

Si Nid, ma comunque lui non può memorizzare in flash dati durante l'esecuzione del programma perché la flash diventa a sola lettura.
Quindi i dati in arrivo da seriale li deve elaborare sempre e comunque in RAM.
Se non vuole usare una memoria esterna gli unici modi sono di ottimizzare al massimo il codice o passare ad un microcontrollore superiore. Es. Arduino MEGA.

tntsix:
i dati sono caratteri che transitano su seriale e che vengono memorizzati in un array di caratteri

Non si può fare con PROGMEM, te l'ho spiegato nei miei precedenti post.