Dieser Abschnitt beschreibt die verschiedenen Speicher des ATmegaX8. Die AVR-Architektur enthält zwei Hauptspeicher, den Datenspeicher und den Programmspeicher. Zusätzlich steht noch ein EEPROM-Speicher für die dauerhafte Sicherung von Daten zur Verfügung. Alle drei Speicherbereiche sind linear und regulär.
Der ATmegaX8 enthält 4/8/16/32 KByte Programmspeicher, der als Flash ausgeführt ist und im System programmiert werden kann. Da alle AVR-Befehle 16 oder 32 Bit lang sind, ist der Programmspeicher in 2/4/8/16 K Speicherzellen mit je 16 Bit organisiert. Aus Gründen der Softwaresicherheit ist der Programmspeicher beim ATmega88/168/328 in zwei Bereiche unterteilt, den Urlader-Bereich und dem Anwendungs-Bereich. Siehe SPMEM-Register-Beschreibung.
Der Flash hat eine Haltbarkeit von mindestens 10.000 Schreib-/Löschzyklen. Der Programmzähler (PC) ist 11/12/13/14 Bit breit. Damit können alle Speicherzellen im Programmspeicher adressiert werden. Die Funktionen des Urlader-Bereichs und den dazugehörigen Urlader-Sperrbits sind für ATmega48 sowie ATmega88/168/328 getrennt beschrieben. Die Programmierung des Programmspeichers im SPI- und Parallel-Modus ist ebenfalls in einem hinteren Kapitel beschrieben.
Datentabellen können im gesamten Programmspeicherbereich hinterlegt werden (siehe LPM-Befehl).
Die Zeitabläufe für das Auslesen und Ausführen von Befehlen sind in den Seiten zuvor abgebildet.
Dieser Controller hat mehr Peripherie als es die 64 Bytes I/O-Adressraum der AVR-Struktur zulässt. Daher gibt es Erweiterten I/O-Adressraum im Adressbereich 0x60..0xFF im SRAM, mit dem auf die Peripherie nur mit den Befehlen ST/STS/STD und LD/LDS/LDD zugegriffen werden kann.
Die 768/1280/2303 Zellen des Datenspeichers enthalten die 32 Register, den I/O-Adressraum, den Erweiterten I/O-Adressraum und den eigentlichen internen SRAM-Datenspeicher. Die ersten 32 Zellen adressieren die Register, weitere 64 den I/O-Adressraum, weitere 160 den Erweiterten I/O-Adressraum, und schließlich 512/1024/2048 Bytes Datenspeicher.
Es gibt fünf verschiedene Möglichkeiten die Speicherzellen zu adressieren: Direkt, indirekt mit Versatz, indirekt, indirekt mit vorherigem Dekrement und indirekt mit anschließendem Inkrement. Die Register R26 bis R31 bilden die Zeiger für die vier indirekten Adressierungsarten.
Mit der direkten Adressierung kann der gesamte Speicher angesprochen werden.
Mit der Methode der indirekten Adressierung mit Versatz können, ausgehend von der Basisadresse, die durch das Y- oder Z-Register vorgegeben ist, 63 Speicherzellen adressiert werden.
Wenn die Methode der indirekten Adressierung mit vorherigem Dekrement oder anschließendem Inkrement genutzt werden, bilden das X-, Y- oder Z-Register den Adresszeiger, der inkrementiert bzw. dekrementiert wird.
Die 32 Register, die 64 I/O-Speicher und die 1024 Byte des internen Datenspeichers können mit allen Adressierungsarten angesprochen werden.
Datenspeicher | |
---|---|
32 Register | 0x0000 - 0x001F |
64 I/O-Register | 0x0020 - 0x005F |
160 Erweiterte I/O-Register | 0x0060 - 0x00FF |
Interner SRAM 512/1024/2048 × 8 | 0x0100 |
0x02FF/0x04FF/0x08FF |
Das EEPROM kann ähnlich wie der Programmspeicher auch durch die ISP oder im parallelen Programmiermodus programmiert werden, siehe Programmieren des Speichers.
Praxistipp: Beim Compiler avrgcc stehen in der Kopfdatei„avr/eeprom.h“
Routinen zum Lese- und Schreibzugriff zur Verfügung, beispielsweiseeeprom_read_block()
. Dabei ist es häufig günstig, im RAM eine Kopie des EEPROM-Speicherbereiches zu halten, der zur allgemeinen Konfiguration dient. Das Rückschreiben von Änderungen kann dann die Hauptschleife „nebenbei“ erledigen, indem sie Byte für Byte vergleicht (geht schnell) und bei Ungleichheit ein Byte schreibt (dauert lange) und sofort zurückkehrt. So hält die Hauptschleife RAM und EEPROM auf Dauer konsistent, ohne sich um jedes einzelne Byte kümmern zu müssen oder gar zu blockieren. (Hierfür steht leider keine avr-libc-Funktion zur Verfügung.)
Die Zeit für den schreibenden Zugriff auf das EEPROM ist in nachfolgender Tabelle angegeben. Mit selbst programmierten Zeitfunktionen kann die Anwendersoftware überwachen, ob ein Schreibvorgang abgeschlossen wurde und somit das nächste Byte in den EEPROM geschrieben werden kann. Wenn das EEPROM genutzt wird, sind ein paar Vorsichtsmaßnahmen zu beachten. In stark gefilterten Spannungsversorgungen neigt UCC dazu, sehr langsam zu steigen bzw. zu fallen, wenn die Spannungsversorgung ein- bzw. ausgeschaltet wird. Das heißt, dass der Baustein für eine gewisse (verhältnismäßig lange) Zeit in einem Spannungsbereich arbeitet, der kleiner als das spezifizierte Minimum ist, in der der Takt arbeitet. Wie in solchen Fällen ein Fehlverhalten verhindert werden kann, ist unter Schutzmaßnahmen beschrieben.
Ferner ist, um das ungewollte Beschreiben des EEPROMs zu verhindern, ein Schreibvorgang nur in zwei Schritten durchführbar (siehe EEPROM-Kontrollregister).
Wenn der EEPROM gelesen wird, wird die CPU für vier Taktzyklen angehalten, bevor der nächste Befehl ausgeführt wird. Beim Schreiben des EEPROM wird die CPU für zwei Taktzyklen angehalten, bevor der nächste Befehl ausgeführt wird.
Ein Verfälschen der EEPROM-Daten kann durch zwei Situationen ausgelöst werden, in denen UCC zu niedrig ist. Erstens benötigt ein regulärer Schreibvorgang eine Mindestspannung, um einen korrekten Schreibvorgang durchzuführen. Zweitens kann es dazu kommen, dass die CPU selbst in der Ausführung der Befehle unsauber arbeitet, wenn die Versorgungsspannung zu gering ist.
Das Verfälschen der EEPROM-Daten kann auf einfache Weise verhindert werden, wenn folgende Design-Empfehlungen angewendet werden.
Den RESET-Eingang auf Low halten, solange die Spannungsversorgung unzureichend ist. Dies kann durch einen externen Resetbaustein erfolgen oder durch die interne Unterspannungsüberwachung. Wenn der Level der internen Unterspannungsdetektors nicht ausreicht, kann auch eine externe Resetschaltung verwendet werden, die einen Spannungsabfall erkennt. Wenn ein Reset während eines laufenden Schreibvorganges auftritt, so wird dieser noch zu Ende geführt, vorausgesetzt die Versorgungsspannung ist noch ausreichend.
Alle I/O-Funktionen und peripheren Einheiten sind im I/O-Speicher platziert. Auf die I/O-Speicher wird mit den IN- und OUT-Befehlen zugegriffen, die Daten zwischen den Registern und den I/O-Speicherzellen transportieren. Die I/O-Speicher im Adressbereich zwischen 0x00 (0x20) und 0x1F (0x3F) sind bitadressierbar. Das heißt, dass einzelne Bits in diesen Speichern mit den SBI- und CBI-Befehlen gesetzt oder gelöscht werden können. Der Zustand der einzelnen Bits kann mit den Befehlen SBIS und SBIC abgefragt werden.
Wenn die I/O-Speicher mit den IN- und OUT-Befehlen angesprochen werden, dann müssen die Adressen 0x00 bis 0x3F verwendet werden. Wenn die I/O-Speicher mit den Befehlen LD und ST über die Adressen des Datenspeichers angesprochen werden, so muss der Wert 0x20 zu den ursprünglichen Adressen hinzuaddiert werden (Adressen 20h bis 5Fh im Datenspeicher). Dieser Controller hat mehr Peripherie als es die 64 Bytes I/O-Adressraum der AVR-Struktur zulässt. Auf den Erweiterten I/O-Adressraum im Adressbereich 0x60..0xFF kann nur mit den Befehlen ST/STS/STD und LD/LDS/LDD zugegriffen werden kann.
Um die Kompatibilität mit zukünftigen Bausteinen zu gewährleisten, werden reservierte Bits als Null gelesen, wenn auf diese zugegriffen wird. Reservierte Adressen im I/O-Adressraum dürfen nicht beschrieben werden.
Einige Statusbits können gelöscht werden, indem sie mit einer logischen 1 beschrieben werden. Dass heißt, dass durch Zurückschreiben einer 1 in ein Bit, das zuvor als 1 gelesen wurde, dieses Bit gelöscht wird. Im Gegensatz zu anderen AVR-Controllern kann dies auch mit den Befehlen SBI und CBI geschehen.
Die Übersicht über alle I/O-Register ist gegen Ende des Dokumentes abgebildet.
Bit | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
(0x42) | - | - | - | - | - | - | EEAR9(1)EEAR8(1) | EEARH
| (0x42) | EEAR7 | EEAR6 | EEAR5 | EEAR4 | EEAR3 | EEAR2 | EEAR1 | EEAR0 | EEARL
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0
| Zugriff | R | R | R | R | R | R | R/W | R/W
| Zugriff | R/W | R/W | R/W | R/W | R/W | R/W | R/W | R/W
| Startwert | 0 | 0 | 0 | 0 | 0 | 0 | X | X
| X | X | X | X | X | X | X | X
| |
---|
Bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | |
(0x40) | MSB | LSB | EEDR | ||||||
---|---|---|---|---|---|---|---|---|---|
Zugriff | R/W | R/W | R/W | R/W | R/W | R/W | R/W | R/W | |
Startwert | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
Bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | |
(0x3F) | - | - | EEPM1 | EEPM0 | EERIE | EEMPE | EEPE | EERE | EECR |
---|---|---|---|---|---|---|---|---|---|
Zugriff | R | R | R/W | R/W | R/W | R/W | R/W | R/W | |
Startwert | 0 | 0 | X | X | 0 | 0 | X | 0 |
EEPM1 | EEPM0 | Programmierzeit | Operation |
---|---|---|---|
0 | 0 | 3,4 ms | Löschen und Schreiben in einer atomaren Operation |
0 | 1 | 1,8 ms | nur löschen |
1 | 0 | 1,8 ms | nur schreiben |
1 | 1 | – | reserviert für später |
Achtung: Ein Interrupt zwischen Schritt 5 und 6 wird zu einem fehlerhaften Schreibversuch führen, da das Zeitfenster von EEMPE dann überschritten wird. Wenn eine Interruptroutine auf das EEPROM zugreift, wird dadurch ein laufender Zugriff unterbrochen, die Register EEAR und EEDR werden verändert und der durch den Interrupt unterbrochene Zugriff misslingt. Es ist daher zu empfehlen, die Interrupts während der Schritte 4 und 5 global zu sperren.
Wenn der Schreibvorgang beendet ist, wird das EEPE-Bit durch die Hardware automatisch gelöscht. Der Zustand des Bits kann also durch die Software permanent abgefragt werden, um das Ende des Schreibvorganges zu erkennen. Wenn das EEPE-Bit mit einer 1 gesetzt wurde, wird die CPU für zwei Takte angehalten, bevor der nächste Befehl ausgeführt wird.
Der Anwender sollte das EEPE-Bit abfragen, bevor ein Lesevorgang gestartet wird. Während eines laufenden Schreibvorganges ist es nicht möglich, den EEPROM zu lesen oder das EEPROM-Daten-Register zu ändern.
Nachfolgende Tabelle zeigt die typischen Programmierzeiten des EEPROMs, die zeitliche Steuerung erfolgt durch den kalibrierten RC-Oszillator.
Parameter | Anzahl der RC-Oszillator-Takte | Typische Programmierzeit |
---|---|---|
EEPROM schreiben (von CPU) | 26.368 | 3,3 ms |
Im Gegensatz zu älteren AVR-Mikrocontrollern mit knapp 10 ms EEPROM-Programmierzeit ist hier die Schreibzeit deutlich kürzer.Die folgenden Programmbeispiele zeigen den Schreibvorgang für das EEPROM. Die Beispiele unterstellen, dass keine Interrupts auftreten können und der Flash nicht durch ein Programm im Urlader-Bereich beschrieben wird. Falls doch muss die EEPROM-Schreibroutine auf das Ende einer SPM-Schreiboperation warten.
Beispiel in Assembler | ||
---|---|---|
EEPROM_write: sbic EECR,EEPE ; Warte bis vorheriges Schreiben fertig rjmp EEPROM_write out EEARH,r18 ; Lade Adresse (r18:r17) out EEARL,r17 out EEDR,r16 ; Lade Datenbyte (r16) sbi EECR,EEMPE ; Setze EEMPE-Bit sbi EECR,EEPE ; EEPROM schreiben starten durch Setzen des EEPE-Bits ret |
Beispiel in Assembler | ||
---|---|---|
EEPROM_read: sbic EECR,EEPE ; Warte bis vorheriges Schreiben fertig rjmp EEPROM_read out EEARH,r18 ; Lade Adresse (r18:r17) out EEARL,r17 sbi EECR,EERE ; Starte EEPROM lesen in r16,EEDR ; Lese Datenbyte ret |
Bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | |
(0x4B) | MSB | LSB | GPIOR2 | ||||||
---|---|---|---|---|---|---|---|---|---|
Zugriff | R/W | R/W | R/W | R/W | R/W | R/W | R/W | R/W | |
Startwert | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
Bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | |
(0x4A) | MSB | LSB | GPIOR1 | ||||||
---|---|---|---|---|---|---|---|---|---|
Zugriff | R/W | R/W | R/W | R/W | R/W | R/W | R/W | R/W | |
Startwert | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
Bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | |
(0x3E) | MSB | LSB | GPIOR0 | ||||||
---|---|---|---|---|---|---|---|---|---|
Zugriff | R/W | R/W | R/W | R/W | R/W | R/W | R/W | R/W | |
Startwert | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |