Verificare SRAM utilizzata

Buongiorno a tutti

Mi trovo in difficoltà a caricare dati da un file .ini su matrici che a conti fatti non dovrebbe essere più di 1100 byte, essendoci però molte altre variabili pubbliche + quelle private che vanno e vengono non riesco a quantificare quanto spazio sto usando.
Diciamo che la lettura dei dati funziona perfettamente, quando poi fondo il programma aggiungendo altre fuzioni testate singolarmente arduino si pianta (non sono errori di programma) se riduco le quantità di byte usate nelle matrici funziona nuovamente.

le caratteristiche della MEGA 2560 sono:
Flash Memory 256 KB of which 8 KB used by bootloader
SRAM 8 KB
EEPROM 4 KB

C'è un modo per farsi restituire solo lo spazio utilizzato dalle variabili?

Spesso dichiaro le variabili pubbliche così non devo sbattermi a inviarle a determinate funzioni, le pesco e basta da qualsiasi punto del programma. Adesso è ora di finirla, ho bisogno di imparare bene come passare le variabili alle funzioni void senza renderle pubbliche, qualcuno potrebbe accennarmi qualcosa di corretto ?

Grazie saluti

Ci sono 2 metodi, uno dinamico ed uno statico.
Quello dinamico prevede l'uso di una piccola lib che calcola istantaneamente il quantitativo di memoria disponibile e lo spedisce via seriale. Quello statico calcola l'occupazione della memoria "sulla carta", cioè cosa il compilatore ha riservato in memoria ai dati del programma.
Ci sono pro e contro per entrambi i metodi: il primo, come detto, necessita di una modifica al tuo sketch e poi serve che la scheda sia collegata al PC per spedire i dati; il secondo non può tener conto di array dinamici creati a runtime.
A parte questo, io preferisco sempre il secondo.

http://www.leonardomiliani.com/?p=572

Grazie Leo :slight_smile:

E' qui che non capisco

Serial.println(freeMemory());
questo metodo è invasivo ed altera il consumo di SRAM dato che sia la libreria che l’uso della comunicazione seriale aumentano la memoria usata dallo sketch. Esso inoltre richiede un modo per poter comunicare all’utente il valore della memoria disponibile.

forse il mio problema sono proprio i debug su seriale, ma quanta SRAM prende il buffer della seriale?

Fino all'IDE 002x prendeva 128 byte, dalla 1.0 in poi ne prende 64.
Ma hai fatto il test con avr-size? Cosa ti dice?

pablos:
forse il mio problema sono proprio i debug su seriale, ma quanta SRAM prende il buffer della seriale?

Con l'IDE 1.x in totale 128 byte suddivisi in parti uguali (64 e 64) tra trasmissione e ricezione.
Per passare dei dati alle funzioni è indispensabile che queste siano dichiarate nel modo corretto, p.e. "void myfunc (char v1, byte v2, int v3)", ove ho una funzione che riceve tre parametri, v1, v2, v3, il primo è uno char, il secondo è un byte e il terzo è un int.
All'interno della funzione hai disponibili le variabili v1,v2,v3, senza ulteriori dichiarazioni, che rappresentano i valori ricevuti.
Trovo strano che sulla MEGA2560 hai problemi ad utilizzare una matrice di 1100 byte, a meno che non hai in giro per il programma molti array e molte variabili long/float che si "mangiano" tutta la ram.

leo72:
Fino all'IDE 002x prendeva 128 byte, dalla 1.0 in poi ne prende 64.

Sono sempre 128, però suddivisi tra 64 in ricezione e 64 in trasmissione, questo perché con l'IDE 1.0 è stato introdotta la gestione della seriale tramite interrupt anche in trasmissione, prima era tramite polling, e questo rende indispensabile il buffer anche per trasmettere.

astrobeed:
Sono sempre 128, però suddivisi tra 64 in ricezione e 64 in trasmissione, questo perché con l'IDE 1.0 è stato introdotta la gestione della seriale tramite interrupt anche in trasmissione, prima era tramite polling, e questo rende indispensabile il buffer anche per trasmettere.

E' vero.

No, Leo non ho ancora provato con AVR, ho usato quello invasivo

#include <MemoryFree.h>
Serial.println(freeMemory());

che mi restituisce dai 200 ai 240 rimanenti, credo sia sull'orlo di crashare

char charBuf[40];  >>>>>>> 40
byte port[54][2];  >>>>>>> 108
byte on[30][8][6];  >>>>>>> 1440
byte off[30][8][6];  >>>>>>> 1440 
byte gruppi[15][5];  >>>>>>> 75
IPAddress ip_ntp_1(0,0,0,0); >>>>>>> 4
IPAddress ip_ntp_2(0,0,0,0); >>>>>>> 4
IPAddress ip_ntp_3(0,0,0,0); >>>>>>> 4
byte mac[] = { 0x00, 0x11, 0x22, 0x33, 0xFB, 0x11 }; >>>>>>> 4
byte ip[] = {0,0,0,0}; >>>>>>> 4
byte subnet[] = {0,0,0,0}; >>>>>>> 4
byte gateway[] = {0,0,0,0}; >>>>>>> 4
unsigned long A; >>>>>>> 4
unsigned long B; >>>>>>> 4
unsigned long C; >>>>>>> 4
unsigned long D; >>>>>>> 4
unsigned long E; >>>>>>> 4
unsigned long F; >>>>>>> 4
unsigned long G; >>>>>>> 4
unsigned long H; >>>>>>> 4

3163 solo in queste variabili
50 in variabili varie tra INT e BYTE

8KB = 8192 byte questi sono i byte totale a disposizione

Dovrei averne 4979 da lasciare ai buffer seriale, alle librerie, buffer SPI, ma si vede che ci vogliono tutti.

una variabile String=.... quanto prende? 1 byte per ogni char?

ciao

pablos:
che mi restituisce dai 200 ai 240 rimanenti, credo sia sull'orlo di crashare

Direi proprio di si.

Dovrei averne 4979 da lasciare ai buffer seriale, alle librerie, buffer SPI, ma si vede che ci vogliono tutti.
una variabile String=.... quanto prende? 1 byte per ogni char?

Oltre alle variabili che dichiari tu ci sono pure quelle di sistema, tra cui l'array dello stack, che non vedi direttamente però esistono e si mangiano qualche centinaio di byte.
Un array di char richiede un byte per ogni valore, uno string oltre allo spazio fisico per i caratteri che contiene, 1 byte ciascuno, richiede alcuni byte aggiuntivi.

Grazie ragazzi per le risposte.

Sono un po' deluso, vedo se posso usare un pezzo di Eeprom per le costanti anche se mettere un altra lib per liberare SRAM mi occupa altra SRAM ahahahahah e poi i tempi di lettura della stessa ....

Magari quando il software della DUE sarà completo un "96 KBytes of SRAM e un 512 KBytes of Flash memory for code" mi verrà comodo

BYE

pablos:
Sono un po' deluso, vedo se posso usare un pezzo di Eeprom per le costanti anche se mettere un altra lib per liberare SRAM mi occupa altra SRAM ahahahahah e poi i tempi di lettura della stessa ....

Non scordarti che puoi usare la flash per tutte le costanti, sopratutto per eventuali stringhe fisse ad uso visualizzazione su display e/o terminale seriale.

nelle mie reminescenze di C scolastico mi ricordo che i compilatori di norma allocano uno spazio per lo stack ed uno spazio per l'heap oltre allo spazio necessario per il codice e le variabili globali: lo stack in effetti è una "pila", una zona di memoria riservata dove quando chiami una funzione con dei parametri il processore si annota l'indirizzo di ritorno ed i parametri... cioè ad esempio se fai un digitalwrite(10,HIGH) il processore fa un push in memoria dell'indirizzo attuale, del 10 e dell High e poi la funzione fa il pull del high, poi del 10 e poi quando ha finito facendo un "ret" si recupera l'indirizzo del ciclo che l'ha chiamato... invece l'heap serviva quando facevi i "malloc"... e forse... ma non mi ricordo bene... quando fai un "int cicillo =0;" all'interno delle procedure o del main ma non nella dichiarazione globale lui intrinsecamente usa l'heap... alloca e poi a fine procedura disalloca con notevole perdita di tempo...in ogni caso 'sto allocare di disallocare non mi pare che fosse esattamente dinamico... forse c erano delle funzioni che usavano l'heap e delle funzioni che allocavano roba nuova non mi ricordo proprio... è brutto diventare vecchi...
Comunque a parte la pappardella teorica c'era 'sta cosa di qualche kb allocati a prescindere e nascosti alla vista del programmatore che era possibile modificare con delle direttive al compilatore.... questo sui computer normali ma non vedo perchè arduino debba fare differenza... prova a leggere qua:
http://arduino.cc/forum/index.php/topic,41871.0.html

Grazie per l'interessamento :slight_smile:

quando fai un "int cicillo =0;" all'interno delle procedure o del main ma non nella dichiarazione globale lui intrinsecamente usa l'heap... alloca e poi a fine procedura disalloca con notevole perdita di tempo...

che ci mettesse "molto tempo" non ci avevo mai pensato, in effetti sembra logico che creare una cosa che non c'è e poi smontarla implica un certo tempo rispetto a qualcosa che già esiste, ma non mi risolve il problema dell'insufficienza.

Astro mi ricorda che c'e' la possibilità di usare la flash, probabilmente con "progmem" che ho sempre lasciato come ultima spiaggia poichè in diversi post lessi che non è proprio il massimo dell'affidabilità ed efficienza, senza mai leggere il perchè.

visto che sono questi i valori costanti che mi servono e che lo sketch usa 48k su 248k
byte port[54][2];
byte on[30][8][6];
byte off[30][8][6];
byte gruppi[15][5];

con una disponibilità elevata e in progetto iniziale queste matrici dovevano essere
byte on[54][10][6];
byte off[54][10][6];
ma vista la limitata mem ho dovuto restringere i campi, ipotizzando di usare un alternativa come potrei metterli su un progmem e richiamarli in modo abbastanza veloce e intuitivo (senza troppe pretese)?

ciao

P.s.
Quando qualcuno scrive ad un altro utente "Non ti consiglio di usare questa cosa" sarebbe bello scrivere anche il perchè secondo lui non andrebbe usata, altrimenti la risposta crea ancora più dubbi.

pablos:
Grazie per l'interessamento :slight_smile:

quando fai un "int cicillo =0;" all'interno delle procedure o del main ma non nella dichiarazione globale lui intrinsecamente usa l'heap... alloca e poi a fine procedura disalloca con notevole perdita di tempo...

che ci mettesse "molto tempo" non ci avevo mai pensato, in effetti sembra logico che creare una cosa che non c'è e poi smontarla implica un certo tempo rispetto a qualcosa che già esiste, ma non mi risolve il problema dell'insufficienza.

ti sei scordato ci citare la mia incertezza su quello che dico... inoltre prendi sempre quello che dico con mooolta calma: sono un newbi e le sQuole le ho finite una decina di anni fa...anche qualcuno di più adesso che ci penso...
tornando a noi il tempo di montare e smontare era più che altro riferito ad un pc normale che alloca e disalloca la memoria perchè ha un sistema operativo e n processi sottostanti che devono convivere: in questi arduino la cosa sicuramente è un po' diversa perchè non cè un sistema operativo eccetera... intendevo comunque più che altro che non metterei volentieri una dichiarazione di una variabile in una procedura che magari deve gestire interrupt veloci con timer e cose del genere...
In ogni caso non ho per il momento una soluzione: dovrei provare a capire come il compilatore riserva queste due aree di memoria: sicuro qualosa deve dargli specie allo stack se no non chiami manco una funzione... dovrebbe esserci anche una funzione di malloc che si può vedere di usare però... spetta un attimo vedo se googolando mi esce qualcosa da provare.

E' vero, oltre allo stack c'è l'heap ma riguarda principalmente l'allocazione dinamica della memoria (malloc e free).
Nello stack ci vengono memorizzati il PC (Program Counter) quando viene chiamata una funzione in modo da sapere da dove riprendere l'esecuzione del programma, i registri di sistema quando vengono chiamati gli interrupt che sospendono il codice principale della funzione chiamante.
Allego una immagine trovata su Avr-Freaks.
.data contiene le variabili staticamente allocate
.bss le variabili globali e statiche non inizializzate
poi c'è l'heap, che parte da dove finisce la zona riservata ai dati .bss e cresce verso l'alto mentre alla fine della memoria c'è lo stack, che parte dall'ultima locazione libera e si sviluppa occupando la Ram verso il basso.
Visto però che l'allocazione dinamica è usata raramente, nella maggior parte delle volte la memoria SRAM è occupata da .data, .bss e stack.

malloc-std.png

pablos:
Astro mi ricorda che c'e' la possibilità di usare la flash, probabilmente con "progmem" che ho sempre lasciato come ultima spiaggia poichè in diversi post lessi che non è proprio il massimo dell'affidabilità ed efficienza, senza mai leggere il perchè.

L'affidabilità è massima, dalla Flash i dati sono letti così come lo è il codice.
Se sono stringhe e devi stamparle, puoi usare la funzione F(), introdotta con l'IDE 1.0, che maneggia in automatico tali dati dalla Flash. Se i tuoi dati sono invece array di byte/char, con un paio di mal di testa riuscirai a gestire i dati dalla Flash :sweat_smile:
Ricordati però che puoi gestire solo costanti, non dati cioè che devono cambiare in fase di elaborazione.

Qui

c'è un esempio di array di byte letto direttamente dalla Flash. Alla fine, sono poche righe di codice, come vedi

Grazie ... ti meriti una confezione di karma. Ma con karma però una alla volta ehehehhe

si sono degli array di byte
il file è così composto i numeri sono di esempio, in realtà saranno byte di giorni mesi ore e minuti + 2 byte di enable

[digital PORT ON timer]
(portimer_hi150) = 53,54,55,56,57,58
(portimer_hi151) = 59,60,61,62,63,64
(portimer_hi152) = 65,66,67,68,69,80
(portimer_hi153) = 81,82,83,84,85,86
(portimer_hi154) = 87,88,89,90,91,92
(portimer_hi155) = 93,94,95,96,97,98
(portimer_hi156) = 03,04,05,06,07,08
(portimer_hi157) = 08,10,12,14,16,18

(portimer_hi160) = 53,54,55,56,57,58
(portimer_hi161) = 59,60,61,62,63,64
(portimer_hi162) = 65,66,67,68,69,80
(portimer_hi163) = 81,82,83,84,85,86
(portimer_hi164) = 87,88,89,90,91,92
(portimer_hi165) = 93,94,95,96,97,98
(portimer_hi166) = 03,04,05,06,07,08
(portimer_hi167) = 08,10,12,14,16,18
....... ecc ecc per 30 porte dalla 15 alla 45

pablos:
Grazie ... ti meriti una confezione di karma. Ma con karma però una alla volta ehehehhe

Con molta caRma :wink:

si sono degli array di byte
il file è così composto i numeri sono di esempio

Uhm.. leggi i dati da un file?

si leggo da un txt creato da un prog eseguibile

nello sketch vengono organizzati cosi'

...
...
               
void get_port_timer()
{
  char *p = charBuf;  
  byte i = 0;
   while (*p != '\0')  
  {
    if (*p == ',') { ++i;  ++p;  continue;}
        if (isdigit(*p)) 
        {
            if(tipo_str == 7)
            {
             port_on[x][y][i] *= 10; 
             port_on[x][y][i] += (*p - '0');
            }

             if(tipo_str == 8)
            {
             port_off[x][y][i] *= 10; 
             port_off[x][y][i] += (*p - '0');           
            }
        }   
    ++p;
  }   	  
}

che funziona bene, ma sappiamo già qual'è il limite