Memory


TinyMega Home

Adressen
Memory
Sram geheugen.
Flash geheugen.

Memory

Elke computer heeft een geheugen om mee te werken, ook onze AVR controllers. Zo een geheugen bestaat uit een array van bytes. Een ATMega32 heeft bijvoorbeeld een werkgeheugen van 2K, ofwel 2048 bytes.

Adresseren

Sram Adresseren

Het werkgeheugen (Sram) heeft dus een hoeveelheid bytes. Als we nu data willen opslaan dan moet de processor een bit-waarde in zo een byte schrijven. Het programma moet dan wel aangeven welke van de bytes beschreven moet worden, dus moet er een methode zijn om de bytes uit elkaar te houden. Dat gaat gemakkelijk als de bytes genummerd worden. Een AtMega32 heeft 2048 bytes geheugen dus dan ligt het voor de hand om de nummers 1 t/m 2048 te gebruiken. In werkelijkheid worden een ander bereik gebruikt: 96 t/m 2143 (ofwel 0x0060 - 0x085F). Deze nummering wordt addresseren genoemd. De eerste byte van het Sram 'ligt op geheugen adress 0x60'.

De adressen 0 t/m 95 bestaan ook wel. De adressen 0 t/m 31 geven toegang tot de werkregisters van de processor. In de praktijk kunt u deze adressen beter met rust laten omdat deze registers al volop gebruikt worden door de compiler.

En de adressen 32 t/m 95 worden gebruikt om de hardware registers te manipuleren.

Sram variabelen

In de praktijk hoeft u meestal niet te weten welke bytes er precies gebruikt worden. Dat wordt door de compiler geregeld. En wel als volgt: U schrijft in uw programma het volgende statement:

   char x;
Als u later in het programma de variabele x gebruikt, dan weet de compiler dat die op adress 96 ligt, en dan genereert de compiler de benodigde instrukties om die byte te bewerken.
   char x;
   char y;
   ...
   x = 12;
   y = x;
In dit programma zijn dus twee variabelen, x op adress 96 en y op adress 97, en de compiler genereert instrukties om het getal 12 weg te schrijven naar geheugen adres 96, en vervolgens om de data uit geheugen adres 96 (=x) te copieren naar geheugen adres 97 (=y).

Nu past een variabele niet altijd in een enkele byte. Een 'int' is bijvoorbeeld 16 bits en heeft dan ook 2 bytes nodig.

   char x = 0x0C;
   char y = 0xFA;
   int  Aantal = 0x3B88;
   char Naam[] = "Jan";
   char i = 0x05;
Hier krijg x weer het adres '96', maar 'Aantal' heeft 2 geheugen lokaties nodig. 'Aantal' krijgt hier adres 97, maar de compiler weet dat dit een 2-byte getal is en reserveert dan ook adres 97 en 98. De volgorde van de bytes in het geheugen is niet altijd even duidelijk. De Atmel AVR familie is 'Little Endian', en dat betekent dat de laagste bits op de laagste geheugen lokatie ligt. Dus op adres 97 liggen de onderste 8 bits, en op adres 98 de hoogste 8 bits. Sommige andere processor families doen dit net andersom ('Big Endian'). en zo verder.

AdresWaardeBeschrijving
960x600x0Cvariabele 'x'
970x610xFAvariabele 'y'
980x620x88variabele 'Aantal', 1e byte
990x630x3Bvariabele 'Aantal', 2e byte
1000x640x4A1e byte van 'Naam'
1010x650x612e byte van 'Naam'
1020x660x6E3e byte van 'Naam'
1030x670x00laatste byte van 'Naam'
1040x680x05variabele 'i'

Hier ziet u een tabel met een overzicht van een stukje geheugen met onze variabelen. Let erop dat voor de string variabele precies voldoende bytes gereserveerd zijn en dat de waarde ook is ingevuld. Dit wordt ingevuld door opstart-code die door de compiler wordt aangemaakt. De ruimte die voor de string gereserveerd is ligt vast, hier 4 bytes en daar moet u in het programma rekening mee houden. U kunt bijvoorbeeld wel een andere waarde in de string schrijven (bijvoorbeeld met memcpy()), maar als u ooit meer dan 4 bytes schrijft dan worden ook de volgende geheugen lokaties overschreven, en dat is doorgaans niet de bedoeling.

Ook ziet u dat variabelen altijd in het SRAM geheugen worden opgeslagen. En dat is maar goed ook want dan kunnen ze gemakkelijk worden gewijzigd, dwz dan kunnen ze een nieuwe waarde krijgen. De lokatie (het adres) wordt bepaald tijdens compilatie en ligt vast gedurende het verloop van het programma.

Tenminste, als u zoals hier de variabelen buiten een funktie definiëert. Variabelen binnen een funktie en ook funktie parameters hebben een beperkte levensduur. Die krijgen een geheugen lokatie (adres) op het moment dat de funktie wordt aangeroepen, en datzelfde adress kan na afloop van de funktie weer gebruikt worden voor andere -tijdelijke- variabelen. Maar ook dan ligt het adress vast zolang de variabele aktief is.
PS : de benaming "Little endian" / "Big endian" komt oorspronkelijk uit 'Gullivers reizen'.

Flash Adresseren

Het flash geheugen gebruikt ook adressen om de geheugen lokaties uit elkaar te kunnen houden. Maar daar werkt het toch net een beetje anders, want het flash geheugen wordt gebruikt om instrukties op te slaan, en de AVR familie gebruikt 16 bits per instruktie.
Een instruktie in het geheugen is gewoon een getal van 16 bits. De processor leest het getal uit het geheugen en dat getal bepaalt welke bewerking er dan wordt uitgevoerd. Het getal 0xEF0F betekent bijvoorbeeld dat de waarde 0xFF wordt weggeschreven naar processor register R0. De processor heeft een 'Program counter', en dat is een teller die aangeeft welke instruktie aan de beurt is. Die teller bevat een adres in het flash geheugen en wordt opgehoogd bij het uitvoeren van een instruktie.
Maar een instruktie is 16 bits en beslaat dus 2 bytes in het geheugen. De Avr gebruikt dus 2 verschillende methodes om het flash geheugen te adresseren. Soms worden de bytes geteld, en dan krijg je Byte addressen, en soms worden instrukties geteld, en dan krijg je word addressen. Een byte adres is dan altijd 2 keer zo groot als een word adress van dezelfde lokatie. Want de eerste instruktie (op adress 0) correspondeert met byte 0 en byte 1, en de tweede instruktie (word address 1) correspondeert met byte 2 en byte 3, enz.