Unterrichts- und Lernmaterial für Mikrocontroller
Unterrichts- und Lernmaterial fürMikrocontroller

Die Speicher der benutzten AVR Controller

Informationen zu den Mikrocontrollern

  • ATtiny13x
  • ATmega8
  • ATmega16
  • ATmega8515

a - Der Programmspeicher (FLASH)

Der Speicher enthält wortorganisierte Befehle und konstante Daten. Ein Befehlswort besteht aus zwei Byte (16 Bit). Ein ATtiny13x mit 1 kByte FLASH kann somit maximal 512 Befehle enthalten.

Nach einem Reset wird der auf Adresse 0x0000 liegende Befehl ausgeführt, danach folgen im Flash die Adressen von Interrupts, des Befehlsbereichs und dem Konstantenbereich.

b - Der Arbeitsspeicher (SRAM)

Er enthält veränderbare Byte-Daten, die während eines Programmlaufs durch Befehlsaufrufe umgeschrieben werden können.

Zum SRAM gehören

  • der byteadressierbare 1kB SRAM-Bereich (ATmega8) (SRAM Adressen: 0x0060 - 0x045F)
  • die nur teilweise bitadressierbaren 64 SF-Register (Special-Function Register) und I/O Register teilen sich auf in
    32 byteadressierbare SF-Register (SRAM Adressen: 0x0040 - 0x005F bzw.
                                                               PORT Adressen: 0x20 - 0x3F) und
    32 bit-/byteadressierbare SF-Register (SRAM Adressen: 0x0020 - 0x003F bzw.
                                                                       PORT Adressen: 0x00 - 0x1F).
  • die bitadressierbaren 32 Arbeitsregister (Adressen: 0x0000 - 0x001F)
  • Der SRAM Bereich ist, je nach Prozessortyp, unterschiedlich groß. Die höchste SRAM-Adresse ist defniert als RAMEND. Bei einem ATmega8 ist dies die Adresse 0x045F. An dieser Stelle wird der sogenannte Stapel (Stack) angelegt, der die Rücksprungadressen von Interrupts und Unterprogrammen aufnimmt. Er arbeitet nach dem Prinzip last in - first out, LIFO).
  • SF-Register sind nicht Bestandteil der CPU (central processing unit). Deshalb lassen sie sich nur beschreiben oder auslesen. Arithmetische oder logische Operationen können nur in Arbeitsregistern ausgeführt werden und müssen ggf. anschließend in ein SF-Register geschrieben werden.

c - Der EEPROM Speicher

Ein nicht flüchtiger Speicher, in dem nur Daten abgelegt werden, zum Beispiel während eines Programmablaufes.

Speicherdaten zum ATtiny13x (8 Pin DIL)

Abb. 1 - Speicherorganisation des ATtiny13x

Speicherdaten zum ATmega8 (28 Pin DIL)

Abb. 2 - Speicherorganisation des ATmega8

Bei einem ATmega8 sieht die detaillierte Adressbereich der Arbeitsregister, der SFR und des SRAM wie in der folgende Abb. 2a gezeigt aus:

Abb. 2a - Adressbereich der Arbeitsregister, des SFR und des SRAM Bereichs.

Speicherdaten zum ATmega16 (40 Pin DIL)

Abb. 3 - Speicherorganisation des ATmega16

Speicherdaten zum ATmega8515 (40 Pin DIL)

Abb. 4 - Speicherorganisation des ATmega8515

d - I/O Anschlüsse

Die in meinen Übungen eingesetzten Mikrocontroller verfügen - je nach Controller-Typ - über unterschiedlich viele 8-Bit breite I/O‐Anschlüsse, sogenannte PORTS oder I/O Register, als Verbindung zur Außenwelt; sie werden als PORTB, PORTC usw. bezeichnet.

  • Jeder der acht Port-Anschlüsse (Port-Pins) lässt sich als Eingang oder Ausgang per Software initialisieren.
  • Einzelne Portanschlüsse können auch über mehrere erweiterte Funktionen (SPI, ADC, etc.) verfügen.
  • Nach einem Reset oder dem Anlegen der Betriebsspannung werden alle I/O Register auf 0 gesetzt.
  • Ein direktes Schreiben in I/O Register mit der LDI Instruktion ist nicht möglich.
  • Das Übertragen eines Wertes in ein I/O Register erfolgt über die Instruktion OUT, das Auslesen eines Wertes über die Instruktion IN.

Genauere Informationen findet man im Datenblatt zum jeweilig eingesetzten Controller.

e - Was ist ein Stack und was sind Stackpointer?

Der Stack wird hauptsächlich zum Speichern

  • temporärer Daten,
  • lokaler Variablen und
  • von Rücksprungadressen nach Interrupts und Unterprogrammaufrufen

verwendet.

Er wird am oberen Ende des SRAM über zwei 8 Bit Register (SPH, SPL) implementiert und wächst nach jedem Eintrag von oben nach unten.

 

Werden Daten mit einem

  • PUSH-Befehl auf den Stack geschoben,

dann wird der Stapel-Zeiger um 1 dekrementiert.

 

Um 2 wird er dekrementiert, wenn die

  • Rückkehradresse bei einem Unterprogrammaufruf oder Interrupt

auf den Stack geschoben wird.

 

Umgekehrt wird der Stapelzeiger um 1 erhöht, wenn

  • Daten mit einer POP-Anweisung dem Stapel entnommen werden.

Er wird um 2 erhöht, wenn eine Adresse bei

  • Rückkehr von einer Unterroutine RET oder einer Unterbrechung RETI

entnommen wird.

Übung 1 - Stackpointer initialisieren - Instruktionen LDI, OUT

Das nachfolgende einfache Programm macht nichts anderes als nur den Stack zu initialisieren.

 

  • Gib das folgende Programm in den Editor ein, speichere es unter dem Namen stackpointer.asm ab und kompiliere es anschließend. Benutzt wird hier der ATmega8515 Controller.
Abb. 5 - Programm stackpointer.asm - Zum Programmstart zeigt der Stackpointer auf die Startadresse im SRAM.

Betrachten wir als erstes die Instruktion

  • LDI hreg1, high(RAMEND)

Im AVR Instruction Manual werden alle Instruktionen der AVR-Controller beschrieben. Die LDI Instruktion ist ein 16-Bit Opcode mit folgendem Format:

Die 16-Bit der Instruktion LDI (load immediately) sind in vier Nibble aufgeteilt.

Nibble 3 ist der sogenannte OP-Code der Instruktion, hier also 0b1110.

Nibble 0 und 2 stellen acht Bit für eine Konstante K zur Verfügung. Es lassen sich damit Werte von 0 bis  255 darstellen.

Nibble 1 beschreibt das Zielregister (dddd -> 4 Bit), in das die Konstante geladen werden soll. Mit vier Bits lassen sich maximal 16 Register benennen: R16 - R31. Zur Darstellung der Zahlen 16 bis 31 benötigt man binär eigentlich 5 Bits, die alle im höchsten Bit eine 1 stehen haben. "Schneidet" man diese 1 ab, dann entspricht der Binärzahl 0b0000 das Register R16, 0b0001 das Register R17 usw.

 

Der Befehl

  • LDI hreg1, high(RAMEND)

lädt in das Register hreg1 (R16) das higher Byte von Ramend und das ist 04. Der zugehörige  binäre Maschinencode lautet:

  • 1110  0000  0000  0100    oder hexadezimal   $E0 04

Nibble 3 ist der OP-Code für die Instruktion LDI, in Nibble 2 und Nibble 0 steht die Konstante 2 und in Nibble 2 das Zielregister R16 mit der Adresse 0b0000.

 

Der Befehl

  • LDI hreg2, low(RAMEND)

lädt in das Register hreg2 (R17) das lower Byte von Ramend, das ist 5F. Der zugehörige binäre Maschinencode lautet jetzt:

  • 1110  0101  0001  1111    oder hexadezimal  $E5 1F

Gleich zu Anfang des Programms wurde die Direktive

  • .LIST

eingebaut. Im Project-Manager von AVR Studio im Verzeichnis OUTPUT wird nach dem Kompilierungsvorgang eine Datei stackpointer.lst erzeugt. Mit einem Doppelklick öffnen wir sie.

Abb. 6 - stackpointer.lst Datei

Ganz links befinden sich zwei Spalten. Die schauen wir uns jetzt näher an. Die Spalte ganz links beginnt bei 000000 und gibt die Adresse im Programmspeicher an. Rechts daneben steht der Maschinencode, also das, was der Compiler aus unserem Assemblerprogramm "gemacht" hat. Der Maschinencode ist für jede Instruktion einzeln ausgewiesen.

  • Der Befehl LDI hreg1, high(Ramend) wird als Maschinencode zu $E0 04.
  • Der Befehl LDI hreg2, low(Ramend) wird als Maschinencode zu $E5 1F.

Es sind genau die Ergebnisse, die wir oben gerade besprochen haben.

Auf die gleiche Weise lassen sich die beiden anderen Maschinenbefehle aus dem Assemblerprogramm herleiten. Dazu muss nur der OP-Code der Instruktion OUT (AVR Instruction Manual) und die Adresse des Stackpointer-Registers nachgeschlagen werden.

 

Die OUT Instruktion ist ein 16-Bit Opcode mit folgendem Format:

Nibble 3 ist der sogenannte OP-Code der Instruktion OUT.

Nibble 0 und 2 stellen sieben Bit für eine Zieladresse im I/O Registerraum. Es lassen sich damit Werte von 0 bis  63 eingeben. Das Highbyte des Stackpointers (SPH) hat die Adresse $3E oder 0b0011 1110, das Lowbyte $3D oder 0b0011 1101. Das höchste Bit in Nibble 2 ist vom Hersteller vorgegeben eine 1 und das niedrigste Bit ist das höchste Bit (Bit 5) für das in der Instruktion angesprochene Arbeitsregister R16 (0b10000).

Nibble 1 beschreibt die restlichen vier Bits des angesprochenen Arbeitsregisters (hier: 0000), aus dem Daten an die Zieladresse übertragen werden.

Der Befehl

  • OUT SPH, hreg1

wird als binärer Maschinencode zu:

  • 1011  1111  0000  1110    oder hexadezimal   $BF 0E

Der Befehl

  • OUT  SPL, hreg2

wird als binärer Maschinencode zu:

  • 1011  1111  0001 1101   oder hexadezimal  $BF 1D.

Im Programmlisting finden wir genau diese Eintragungen.

Auf die gleiche Weise lässt sich für die abschließende RJMP-Instruktion dem Instruction Manual entnehmen:

In den Nibbeln 0 - 2 steht die Anzahl der Zeilen, die innerhalb des Programmes zurück- oder vorgesprungen werden soll. In diesem Fall ist es ein Rücksprung um eine Programmzeile, also -1 oder 0b1111 1111 1111 oder $FFF.

 

Zusammen mit dem OP-Code ergibt sich als Maschinencode: $CF FF.

Der Maschinencode ist im Programmspeicher abgelegt und kann mit Hilfe des Debuggers im AVR-Studio sichtbar gemacht werden.

Der Maschinencode ist in little-endian-order im Programmspeicher ab Position $0000 abgelegt. Er setzt sich aus sechs Instruktionen zusammen: zwei LDI-, zwei OUT-Instruktionen und zwei RJMP-Instruktion.

Die Map-Datei

Im Verzeichnis Output wird nach dem Compilieren eines Programms eine Tabelle *.map angelegt, in der alle benutzten Symbole mit den ihnen zugeordneten Werten zu finden sind. Für das vorliegende Beispielprogramm finden sich am Ende der Liste folgende Eintragungen:

In der Zeile EQU  takt ist die im Programm angegebenen Frequenz 1000000 als Hexadezimalzahl dargestellt. Die Registerbenennungen von r16 und r17 folgen.

  • init startet mit Zeile 1 und
  • start mit Zeile 5

im Codesegment (s. Abb. 6).

Druckversion | Sitemap
© Reinhard Rahner - Gettorf