Go Down

Topic: Verificare SRAM utilizzata (Read 4005 times) previous topic - next topic

astrobeed

Come ulteriore riscontro al test fatto da Leo ecco un semplicissimo sketch che dimostra al di la di ogni dubbio che avr-gcc consente la ricorsività delle funzioni ed è abbastanza intelligente da non riempire lo stack.
Lo sketch conta da 0 a 10001 usando una funzione ricorsiva, l'uscita è determinata da una if e una return, i valori vengono inviati al monitor seriale e alla fine delle iterazioni viene ceduto il controllo al main loop che fa lampeggiare un led a dimostrazione che non c'è stato nessun stack overflow.

Code: [Select]

long iter = 0;
void setup()
{
  Serial.begin(115200);
  pinMode(13, OUTPUT);
  digitalWrite(13, HIGH);
  recurse();
  Serial.println("fine iterazioni");
}

void loop()
{
digitalWrite(13, HIGH);
delay(100);
digitalWrite(13, LOW);
delay(100);
}

void recurse(void)
{
iter++;
Serial.println(iter,DEC);
if (iter > 10000)
   {
    iter = 0;
    return;
   }
recurse();
}


qsecofr



qua non abbiamo 2k ma 8... in pratica anneghiamo in un mare  :smiley-roll: di ram che non usiamo

Guarda che gli Atmega328 hanno solo 2 kB di RAM, l'ho scritto diverse volte.



pensavo che si parlasse del  Atmega2560 con 8k. comunque mi permane il dubbio di come faccia a farsi 'ste funzioni ricorsive senza toccare lo stack... deve essere un barbatrucco non da poco.

astrobeed


comunque mi permane il dubbio di come faccia a farsi 'ste funzioni ricorsive senza toccare lo stack... deve essere un barbatrucco non da poco.


La cosa è molto più semplice di quelli che pensi, in realtà il compilatore si rende conto che c'è una ricorsività e la gestisce in modo opportuno senza incrementare lo stack ad ogni iterazione.
Se provi a fare un ricerca con argomento "tail call" e "tail recursive" trovi tutte le spiegazioni del caso.

qsecofr



Se provi a fare un ricerca con argomento "tail call" e "tail recursive" trovi tutte le spiegazioni del caso.



vedo... grassie...

leo72

In allegato trovate un piccolo sketch che stampa alcune info sull'allocazione della SRAM del microcontrollore.

La memoria SRAM viene suddivisa in 5 pezzi:
1) all'inizio della SRAM viene messa l'area .data, che contiene le variabili dichiarate nel programma
2) dopo c'è l'area .bss/.init: essa contiene le variabili non inizializzate
3) a seguire c'è l'HEAP, che contiene i dati per l'allocazione dinamica della memoria. L'HEAP cresce verso l'alto.
4) dopo l'HEAP c'è un'area vuota che funge da "materasso"
5) infine c'è lo STACK, collocato a partire dall'ultima locazione di memoria a crescere verso il basso, verso l'HEAP. Nello STACK ci vanno a finire non solo i punti di ritorno per i salti alle subroutine ma anche i registri di sistema durante le ISR nonché le variabili create localmente.

Sia lo STACK che l'HEAP si espandono nell'area materasso. Se queste 2 aree vengono a collidere sovrapponendosi, il micro crasha.
La memoria libera che lo sketch calcola è data dall'area compresa fra l'inizio dell'HEAP e l'inizio dello STACK.

Ovviamente potete inserire questo sketch in un vostro programma, ma anche infarcirlo di altre funzioni per vedere come i vari puntatori variano.

La funzione più importante è freeRam, pubblicata da JeeLabs, che può essere estrapolata per essere utilizzata in un proprio sketch.

Buonanotte   ;)

leo72

#50
Nov 23, 2012, 09:21 am Last Edit: Nov 23, 2012, 04:39 pm by leo72 Reason: 1
Mi sono dimenticato di precisare una cosa.
Se avete lanciato lo sketch, avrete visto che la SRAM inizia all'indirizzo $100. Questo perché in realtà un microcontrollore possiede 256 byte ($100) di RAM in più, che però usa per le sue necessità: nei primi 160 256 byte vengono infatti salvati i registri interni del microcontrollore ed i registri che controllano le linee di I/O. Poi inizia la RAM destinata ai dati del programma, che parte da $100 appunto e termina a $RAMEND, che varia a seconda del micro. Nel caso dell'Atmega328, che ha 2048 ($800) byte di RAM disponibile per i dati, la fine è a ($100+$800-$1)=2303 ($8FF). Questo indirizzo rappresenta anche la cella più alta dello STACK.

Ecco l'output del mio Arduino UNO:
Code: [Select]

SRAM and .data space start: 256 $100
.data space end/.bss start: 456 $1C8
.bss space end/HEAP start: 641 $281
HEAP end: 654 $28E
STACK start: 2241 $8C1
STACK and SRAM end: 2303 $8FF
Free memory at the moment: 1600 $640


Questo invece l'output della mia Leonardo:
Code: [Select]

SRAM and .data space start: 256 $100
.data space end/.bss start: 482 $1E2
.bss space end/HEAP start: 601 $259
HEAP end: 614 $266
STACK start: 2753 $AC1
STACK and SRAM end: 2815 $AFF
Free memory at the moment: 2152 $868

Qui ci sono 512 byte di memoria in più (2303+512=2815).

MauroTec

Provato anche io su ATmega 644A, funziona.

Ho dovuto modificare tutti gli int in unsigned int perché sto usando utoa per convertire il numero in stringa, potrei usare itoa se ci sono controindicazioni, ma al momento mi sembra funzioni alla perfezione.

Ciao.
AvrDudeQui front end per avrdude https://gitorious.org/avrdudequi/pages/Home


leo72


Provato anche io su ATmega 644A, funziona.

Ho dovuto modificare tutti gli int in unsigned int perché sto usando utoa per convertire il numero in stringa, potrei usare itoa se ci sono controindicazioni, ma al momento mi sembra funzioni alla perfezione.

Ciao.


La cosa è ininfluente, tanto un indirizzo non sarà mai negativo per cui int o unsigned int sempre quello è.

Go Up