Pfad: Home => AVR-Überblick => Programmiertechniken => AVR Nummer 1    (This page in English: Flag EN) Logo

Warum AVRs die idealen Prozessoren sind

Nun, das ist alles Unsinn. Ich habe 1999 damit angefangen, verwende die AVR seither für alle möglichen Zwecke und habe noch nie das Bedürfnis verspürt, mehr zu brauchen (Speicher, Rechenleistung, Bits, etc.), weil ich noch nie an solche Grenzen gestoßen bin. Ich will aber auch kein Handy bauen, keinen WLAN-Server, keinen Navi oder keinen PC, das gibt es schon für billig zu kaufen und ist für Eigenentwicklungen viel zu langweilig.

AVR's überragende Architektur: Register satt

Warum also unbedingt AVRs? Nun, weil sie 32 Register haben. Das ist mehr als alle anderen Controller und Prozessoren und sowas wie ein Alleinstellungsmerkmal der AVRs.

Was macht solche Register so einzigartig? Von den 32 Registern der AVRs aus kann man direkt die zentrale Prozessoreinheit CPU ansteuern. Mit einem einzigen Befehl in Maschinencode, z. B. add R0,R1, kann man zwei 8-Bit-Zahlen in den Registern R0 und R1 addieren und das Ergebnis in R0 abspeichern. Mit zweien, z. B. add R0,R2 und adc R1,R3 hat man mal eben eine 16-Bit-Addition der beiden Zahlen, die in den Registern R1:R0 und R3:R2 stehen, ausgeführt. Das geht rapp-zapp und in zwei Controller-Taktzyklen. Wer mehr über die Befehlsausführung in AVRs wissen will, wird hier fündig.

Mach das gleiche mal in einem PIC: der hat nur ein einziges Register und Du bist dauernd damit beschäftigt, irgendwelche Bytes aus dem SRAM zur CPU zu transportieren und sie von dort wieder dahin zurückzuschreiben. Aus den zwei AVR-Instruktionen werden daher im PIC sehr viele mehr, weil ihm einfach diese genialen Register fehlen.

Da sagt ein Vergleich der Megahertze Takt von AVRs und PICs aber rein gar nix drüber aus. Wenn jede AVR-Instruktion vier Instruktionen eines PICs ersetzt, rennt der AVR bei 1 MHz Takt halt schon mal vierfach schneller.

Meistens kommt man bei einfacheren Projekten und Aufgaben mit den internen Registern des AVR schon ganz alleine hin und braucht gar nix in den langsameren SRAM-Speicher auslagern (Schreiben oder Lesen aus dem SRAM-Speichern braucht zwei Takte statt einem). Auch die Tatsache, dass manche AVR-Instruktionen nur mit den oberen Registern ab R16 aufwärts funktionieren (wie z. B. ldi R16, Konstante), tut der Sache keinen Abbruch: es sind immer noch 16, die alles können, und damit wesentlich mehr als alle anderen Controller. Und mit ein bisschen Überlegung und Planung kriegt man die beiden Registerarten schon entsprechend ihrer jeweiligen Fähigkeiten ordentlich und optimal zugeteilt. Wer die Zuteilung dem Compiler überlässt, weil er glaubt, hohes C sei besser als Assembler, hat es dann halt nicht anders verdient und kriegt Kuddelmuddel statt Wohlordnung.

(Fast) Doppelte Geschwindigkeit durch Pre-Fetch

Noch so eine Eigenschaft, die AVRs doppelt so schnell macht wie PICs: während ein Befehl gerade bearbeitet wird, wird schon der Nächste aus dem Flashspeicher geholt (Pre-Fetch). Pech, wenn der aktuelle Befehl ein Sprungbefehl ist: dann war das Holen umsonst und es muss ein weiterer Takt zum erneuten Lesen einschoben werden. War er kein Sprungbefehl, braucht nicht neu eingelesen zu werden und es geht sofort an das Ausführen des schon gelesenen Befehls.

Hier gibt es mehr zum Pre-Fetch.

Um zu sehen, wie häufig Sprungbefehle in Assembler-Quellcodes vorkommen, habe ich meine knapp 22.000 verwendeten Instruktionen gezählt und festgestellt, dass 28,11% davon Sprunginstruktionen waren. Geht man davon aus, dass die Häufigkeit des Vorkommens von Sprungbefehlen in etwa der Häufigkeit ihrer Ausführung entspricht und dass alle bedingten Sprünge ihre Bedingung einhalten und springen, laufen AVR-Programme etwa 1,72-mal so schnell wie dies ohne Pre-Fetch der Fall wäre. Nicht ganz doppelt so viel, aber nahe dran.

Mit dem Faktor 4 von oben und dem Faktor 1,72 hier sind wir bei 20 MHz Takt schon bei 137 MHz scheinbarer Taktgeschwindigkeit. So macht man High-Speed ohne zusätzlichen Stromverbrauch. Aber es gibt noch mehr Beschleuniger in AVRs: Zeiger.

Optimaler Zugriff auf Register und Ports bei den AVR

Dass AVRs Befehlsworte mit 16 Bit Breite verarbeiten und PICs dazu nur 12 Bits zur Verfügung haben, bedingt bei den AVR eine Reihe zusätzlicher Instruktionsarten. Ein Beispiel für diesen Unterschied sind die vielfältigeren Adressierungsarten f6uuml;r Speicherzugriffe.

Es gibt in AVRs folgende Adressierungsarten:

AdressierungsartBefehlsworteVariantenCode-Beispiele
DirektZwei: Instruktion mit
Adresse als zweites Wort
Lesen, SchreibenLDS Register,Adresse
STS Adresse,Register
Zeigerregister-PaarEins (Instruktion)Zeigerregister X, Y, Z
Lesen, Schreiben
LD Register,X/Y/Z
ST Register,X/Y/Z
Zeigerregister-Paar
mit Post-Auto-Inkrement
Eins (Instruktion)Zeigerregister X, Y, Z
Lesen, Schreiben
LD Register,X/Y/Z+
ST Register,X/Y/Z+
Zeigerregister-Paar
mit Pre-Auto-Dekrement
Eins (Instruktion)Zeigerregister X, Y, Z
Lesen, Schreiben
LD Register,-X/Y/Z
ST Register,-X/Y/Z
Zeigerregister-Paar
mit positiver Ablage
Eins (Instruktion)Zeigerregister Y, Z
Lesen, Schreiben
LDD Register,Y/Z+D
STD Y/Z+D,Register

Mit dieser breiten Vielfalt ist für jeden Bedarf etwas dabei. So was haben nicht so arg viele Prozessoren.

Das geht aber nicht nur mit dem SRAM: der Speicherraum der 32 Register in AVRs kann mit diesem Instrumentarium genauso gut wie ein SRAM verwendet werden. Zu diesem Zweck sind die Register an den Adressen 0x0000 bis 0x001F eingeblendet. Beim Lesen von diesen Adressen wird der Registerinhalt erhalten, beim Schreiben der Registerinhalt überschrieben. Das geht in Assembler z. B. so:

  ; Register-Adresse in eine Konstante
  .equ Adresse = 3 ; Adresse 3 einstellen = R3
  ; Aus Adresse lesen und schreiben
  lds R16,Adresse ; Aus Adresse lesen (R3 in R16 kopieren)
  inc R16 ; Zahl um Eins erhoehen
  sts Adresse,R16 ; In Register R3 zurueckschreiben

Die Adresse wird bei dieser Möglichkeit fest kodiert. Nachfolgend ist gezeigt, wie man das mit dem Zeigerregisterpaar X (R27:R26) macht.

  ; Register-Adresse in eine Konstante
  .equ Adresse = 3 ; Adresse 3 einstellen = R3
  ; Zeiger X mit der Adresse laden
  ldi XH,High(Adresse) ; MSB der Adresse in den X-Zeiger
  ldi XL,Low(Adresse) ; LSB der Adresse in den X-Zeiger
  ; Aus Zeigeradresse lesen und schreiben
  ld R16,X ; Register R16 aus Adresse lesen (R3 in R16 kopieren)
  inc R16 ; Um eins erhoehen
  st X,R16 ; In Register R3 zurueckschreiben

Der Zeiger in X kann danach erhöht (Post-Auto-Inkrement) oder vor seiner Verwendung erniedrigt (Pre-Auto-Dekrement) und dasselbe mit einem anderen Register ausgeführt werden, auf die der Zeiger dann zeigt.

Diesselben Methoden können auch für den Zugriff auf die Port-Hardware verwendet werden. Die 64 Ports der AVRs liegen adressmäßig auf 0x0020 bis 0x005F. Hier ein Auszug aus der Portliste des ATtiny13:

Portregister im ATtiny13
Die Portregister des Ports B im ATtiny13 liegen demnach an den Adressen 0x16 (Leseport), 0x17 (Richtungsport) und 0x18 (Ausgabeport). Um die Ausgabeports auf Eins zu setzen, kann man dies schreiben:

  ldi R16,0x1F ; Alle Bits auf Eins
  out PORTB,R16 ; In Ausgangsport

Man kann denselben Port aber auch über seine eingeblendete Adresse im Speicherraum ansprechen. Diese liegt um die 32 Register nach oben verschobene I/O-Adresse (auf den untersten 32 Adressen liegen die Register).

  ldi R16,0x1F ; Alle Bits auf Eins
  sts PORTB+32,R16 ; In Ausgangsport PORTB

Diese Formulierung wird man kaum verwenden, denn sie braucht einen Takt mehr als mit out. Diese Lösung wählt man dann, wenn die Anzahl der Portregister nicht mehr in den 64-Byte-I/O-Raum passt. Das ist bei größeren AVR der Fall. Als Beispiel hier ein Auszug aus den Portregistern des ATmega48.

Portregister ATmega48

Hier sind nicht die Portadressen angegeben, sondern die sogenannte Offset-Adresse. Daher liegt das Statusregister SREG hier auf Adresse 0x5F, nicht bei der OUT-Adresse 0x3F wie sonst üblich. Oberhalb von 0x5F liegende Portregister sind nicht mehr über out-Instruktionen zugänglich. Sie werden direkt mit ihrem Offset über sts Offset-Adresse,Register beschrieben bzw. mit lds Register,Offset-Adresse gelesen. Bei Portregistern mit einem Offset unterhalb 0x60 kann weiterhin out und inverwendet werden, indem vom Offset 32 abgezogen werden.

Eine besondere Adressierungsart ist das temporäre Addieren einer positiven Ablage D mit LDD Register,Y+D und STD Y+D,Register. Diese Adressierung wird man verwenden, wenn man mehrere unterschiedliche Datensätze hat, mit denen man dasselbe machen will, also z. B. einen gemessenen AD-Wert in zwei Speicherplätzen in einen binären Spannungswert umrechnen und danach in eine Dezimal-ASCII-Zeichenkette umrechnen. Hat mein Messgerät vier Messkanäle, brauche ich diese Datenstruktur vier mal und im SRAM ergibt sich folgendes Bild:

Vierkanal-Datenstruktur

Natürlich kann man die ADC-Messergebnisse der vier Kanäle auch hintereinander im SRAM ablegen und, je nach Kanal, die Spannungsumrechnung in eine binäre Spannung sowie die Umwandlung in eine dezimale ASCII-Zeichenkette bei jedem einzelnen Kanal auch einzeln aufrufen und jeweils die Adresse in Zeigern mitgeben.

Eleganter geht es aber mit dem Zeigerregister Y: Es zeigt an den Anfang des jeweiligen Datensatzes und wird mit jeder Messung um 11 Positionen erhöht: adiw YL,11. Die Multiplikationsroutine holt den ADC-Wert des Kanals dann mit ld R0,Y und ldd R1,Y+1 in das Registerpaar R1:R0, multipliziert mit einer Konstanten und legt das Ergebnis mit std Y+2,rLsb und std Y+3,rMsb in den beiden Ergebniszellen ab.

Auch diese Adressierungsarten wirken sehr beschleunigend, ohne dass man zusätzliche Hertze und entsprechenden Betriebsstrom aufwenden muss. Versuche solche Strukturen mal mit Prozessoren, die wegen eingeschränkter Föhigkeiten des Befehlssatzes (PIC) solche Instruktionen erst gar nicht kennen. Kannste vergessen, geht gar nicht erst!

Fazit

Schon alleine wegen der Register, ihres Pre-Fetch-Mechanismus und der Vielfalt an Adressierungsarten mit Zeigern sind die AVRs auch nach zwanzig Jahren noch immer die Allerbesten und werden von vielen anderen Prozessoren bei Weitem nicht erreicht.

Vergesse daher den Spruch, dass Neueres immer besser sei. Manchmal ist es halt doch umgekehrt.

zum Seitenanfang


©2019 by http://www.avr-asm-tutorial.net