{"id":724,"date":"2013-03-26T11:38:51","date_gmt":"2013-03-26T10:38:51","guid":{"rendered":"http:\/\/www.leonardomiliani.com\/?p=724"},"modified":"2022-11-04T16:50:22","modified_gmt":"2022-11-04T15:50:22","slug":"la-memoria-sram-dei-microcontrollori","status":"publish","type":"post","link":"https:\/\/leonardomiliani.com\/?p=724","title":{"rendered":"La memoria SRAM dei microcontrollori"},"content":{"rendered":"<p>Come detto in un <a title=\"Come sapere l\u2019occupazione di RAM del proprio sketch\" href=\"https:\/\/fpg.cfk.mybluehost.me\/?p=572\">precedente articolo<\/a>, l&#8217;architettura di un microcontrollore \u00e8 di tipo Harvard, dove la SRAM (Static Random Access Memory) che contiene i dati del programma \u00e8 separata dalla memoria Flash che contiene il programma stesso. Ma non tutti sanno che l&#8217;interno di questa RAM (ometto la &#8220;S&#8221;) \u00e8 condiviso da pi\u00f9 aree dati, alcune delle quali poco note. Vediamole insieme&#8230;<\/p>\n<p><!--more--><\/p>\n<p>Quello che vedete qui sotto \u00e8 un grafico che riproduce la RAM di un ATmega328P mentre \u00e8 in esecuzione il programma registrato nella sua memoria Flash:<\/p>\n<p><a href=\"http:\/\/www.leonardomiliani.com\/wp-content\/uploads\/2013\/03\/mcu_memory_usage.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-medium wp-image-727\" src=\"http:\/\/www.leonardomiliani.com\/wp-content\/uploads\/2013\/03\/mcu_memory_usage-300x83.jpg\" alt=\"SRAM memory usage\" width=\"300\" height=\"83\" srcset=\"https:\/\/leonardomiliani.com\/wp-content\/uploads\/2013\/03\/mcu_memory_usage-300x83.jpg 300w, https:\/\/leonardomiliani.com\/wp-content\/uploads\/2013\/03\/mcu_memory_usage.jpg 660w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<p>La prima considerazione da fare riguarda l&#8217;indirizzo di partenza. Noterete che \u00e8 $100, esadecimale per 256. Questo perch\u00e9 le prime 255 locazioni sono utilizzate dal microcontrollore stesso per mappare in memoria i suoi registri interni (come quelli dei timer, quelli relativi alle porte di I\/O ecc..). A partire dall&#8217;indirizzo $100 c&#8217;\u00e8 la memoria disponibile per il programma dell&#8217;utente: nel caso dell&#8217;ATmega328P, che ha 2048 byte di SRAM disponibile, la memoria inizia a $100, ossia 256, e termina a $8FF, ossia 2303 (2303-256=2047).<\/p>\n<p>La RAM \u00e8 organizzata in diverse aree, che hanno un nome proprio assegnato dal compilatore <code>avr-gcc<\/code>:<\/p>\n<ul>\n<li>all&#8217;inizio \u00e8 posta l&#8217;area denominata <strong>.data<\/strong>,\u00a0che contiene le variabili statiche dichiarate nel programma.<\/li>\n<li>A seguire troviamo l&#8217;area <strong>.bss<\/strong>,\u00a0dove risiedono le variabili statiche non inizializzate nel programma.<\/li>\n<li>L&#8217;area successiva \u00e8 l&#8217;<strong>heap<\/strong>: l&#8217;heap \u00e8 una struttura dati particolare che serve a gestire l&#8217;allocazione dinamica della memoria. Tutto quello che creiamo con malloc() finisce nell&#8217;heap, da cui \u00e8 tolto poi con free().<\/li>\n<li>L&#8217;ultima area \u00e8 lo <strong>stack<\/strong>, collocato nella parte alta della RAM, che serve a contenere non solo i punti di ritorno per i salti alle subroutine del codice utente ma anche\u00a0le variabili create localmente nonch\u00e9 i\u00a0registri di sistema durante le ISR (tutte le volte che viene sollevato un interrupt viene chiamata la corrispondente routine di servizio ma, prima di questo, la CPU salva nello stack lo stato corrente dei registri per poter riprendere\u00a0dallo stesso punto\u00a0l&#8217;esecuzione del codice interrotto quando la ISR \u00e8 terminata).<\/li>\n<\/ul>\n<p>La somma dalle aree .data e .bss da come risultato la memoria occupata staticamente dal vostro programma, ed \u00e8 il risultato che restituisce il programma <code>avr-size<\/code>. L&#8217;heap e lo stack, invece, sono strutture create durante l&#8217;esecuzione del programma e non possono essere predette per cui la memoria libera effettiva deve essere calcolata a runtime (per entrambi i casi, fai riferimento al mio\u00a0<a title=\"Come sapere l\u2019occupazione di RAM del proprio sketch\" href=\"https:\/\/fpg.cfk.mybluehost.me\/?p=572\">precedente articolo<\/a>).<\/p>\n<p>L&#8217;heap non pu\u00f2 sovrascrivere la memoria destinata alle variabili statiche perch\u00e9 l&#8217;area che lo contiene si espande verso la zona alta della memoria mentre le aree .data e .bss sono poste prima dell&#8217;heap stesso. Lo stack, invece, si espande verso la zona bassa: il rischio che si corre \u00e8 la collisione delle due aree che porta l&#8217;heap a sovrascrivere i dati dello stack e viceversa, perch\u00e9 la CPU del microcontrollore non esegue nessun controllo sul verificarsi di questo fatto. I risultati sono catastrofici perch\u00e9 l&#8217;accavallamento dell&#8217;heap e dello stack porta al malfunzionamento immediato del programma ma anche al blocco improvviso del microcontrollore.<\/p>\n<p>Durante la stesura di un programma \u00e8 perci\u00f2 di fondamentale importanza ricordarsi che stiamo lavorando con microcontrollori dalle ridotte capacit\u00e0 di memoria (sull&#8217;Arduino UNO abbiamo 2 kB di RAM quando i nostri computer hanno tagli di memoria che si misurano in GB!!) ed usare tutti gli accorgimenti che possiamo per ridurre il consumo inutile di RAM:<\/p>\n<ul>\n<li>la seriale sull&#8217;Arduino viene gestita tramite 2 buffer (uno per la ricezione ed uno per la trasmissione) di 64 byte l&#8217;uno, quindi abbiamo gi\u00e0 un consumo di 128 byte con il semplice utilizzo della seriale. Quindi usate la seriale solo quando serve oppure per debug, e toglietela se il vostro programma non la usa.<\/li>\n<li>Usate i tipi di variabili pi\u00f9 adatti per gestire i vostri dati. Ad esempio \u00e8 un errore utilizzare un <em>int<\/em>\u00a0per memorizzare il valore di un pin dato che esso non avr\u00e0 mai un valore numerico elevato. Utilizzate un tipo <em>byte<\/em>: questo occupa 1 byte di RAM, mentre l&#8217;<em>int<\/em>\u00a0ne occupa 2.<\/li>\n<li>Qualunque variabile che viene utilizzata in un programma deve essere, prima di venir utilizzata, copiata in RAM! Questo \u00e8 per via dell&#8217;architettura Harvard, che separa la memoria Flash dove risiede il codice dalla memoria SRAM dove &#8220;vivono&#8221; i dati. Questo vale anche per le stringhe: se usate molte stringhe, ad esempio lavorando con un display LCD oppure interagendo con la seriale, il rischio di saturare la memoria \u00e8 molto elevato. Fortunatamente con l&#8217;IDE 1.0 \u00e8 stata introdotta la funzione <code>F()<\/code> nel core dell&#8217;Arduino che permette di leggere le stringhe direttamente dalla Flash (questa \u00e8 un&#8217;operazione possibile a runtime) senza doverle prima ricopiare in RAM. Questa funzione, per\u00f2, si pu\u00f2 utilizzare soltanto per testi predefiniti e non per stringhe composte a runtime e solo nelle funzioni di Arduino <code>Serial.print\/ln<\/code> e <code>Lcd.print\/ln<\/code> (la prima per la scrittura su seriale, la seconda per la scrittura su un display LCD con la libreria integrata LiquidCrystal). Quindi questo uso va bene:<br \/>\n<code>Serial.println(F(\"Salve\")); \/\/questo uso \u00e8 consentito<\/code><br \/>\nmentre questo uso non va bene:<br \/>\n<code>String temp = \"Ciao\";<br \/>\nSerial.println(F(temp)); \/\/questo uso NON \u00e8 consentito<\/code><\/li>\n<li>Ricordatevi che la Flash \u00e8 organizzata in word, ossia una coppia di byte. Fateci caso: quando compilate uno sketch, non otterrete mai la dimensione del vostro sketch con un valore dispari ma sempre pari. Questo perch\u00e9 nonostante l&#8217;MCU sia ad 8 bit la memoria \u00e8 invece a 16 bit. Quindi se il vostro sketch occupa 1353 byte, in Flash ne occuper\u00e0 1354. Questo vale anche per le stringhe che, come detto, sono memorizzate all&#8217;interno dello sketch (quindi in Flash) ma copiate in RAM durante l&#8217;esecuzione del programma (a meno che non utilizziate la funzione <code>F()<\/code>\u00a0appena menzionata). Perci\u00f2 quando la vostra stringa viene trasportata in RAM, anche qui occuper\u00e0 lo stesso quantitativo di memoria che occupava in Flash: &#8220;CIAO&#8221; occuper\u00e0 4 byte, tanti quanti la stringa &#8220;AIO&#8221; nonostante questa sia lunga 3 byte.<\/li>\n<\/ul>\n<p>Allegato trovate uno sketch che serve ad avere informazioni sull&#8217;utilizzo della RAM in tempo reale: la memoria libera calcolata \u00e8 data dall&#8217;area compresa fra l&#8217;inizio dell&#8217;HEAP e l&#8217;inizio dello STACK. Sono poi stampate informazioni sull&#8217;indirizzo di inizio e fine di ogni area di cui abbiamo parlato.<\/p>\n<p>Per approfondire: <a href=\"http:\/\/www.nongnu.org\/avr-libc\/user-manual\/malloc.html\" target=\"_blank\" rel=\"noopener\">link 1<\/a>.<\/p>","protected":false},"excerpt":{"rendered":"<p>Come detto in un precedente articolo, l&#8217;architettura di un microcontrollore \u00e8 di tipo Harvard, dove la SRAM (Static Random Access&#46;&#46;&#46;<\/p>\n","protected":false},"author":193,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[14],"tags":[],"class_list":["post-724","post","type-post","status-publish","format-standard","hentry","category-arduino"],"_links":{"self":[{"href":"https:\/\/leonardomiliani.com\/index.php?rest_route=\/wp\/v2\/posts\/724","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/leonardomiliani.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/leonardomiliani.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/leonardomiliani.com\/index.php?rest_route=\/wp\/v2\/users\/193"}],"replies":[{"embeddable":true,"href":"https:\/\/leonardomiliani.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=724"}],"version-history":[{"count":5,"href":"https:\/\/leonardomiliani.com\/index.php?rest_route=\/wp\/v2\/posts\/724\/revisions"}],"predecessor-version":[{"id":2092,"href":"https:\/\/leonardomiliani.com\/index.php?rest_route=\/wp\/v2\/posts\/724\/revisions\/2092"}],"wp:attachment":[{"href":"https:\/\/leonardomiliani.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=724"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/leonardomiliani.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=724"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/leonardomiliani.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=724"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}