26. Flash-Selbstprogrammierung, ATmega48
26.1 Übersicht
Der ATmega84(P)A hat nicht die Möglichkeit des Lesens-beim-Schreiben des Flash-Speichers.
Der SPM-Befehl kann vom gesamten Flash-Speicher aus ausgeführt werden.
Der Chip unterstützt Selbstprogrammierung zum Download und Upload von Programmkode.
Dazu kann jedes verfügbare Dateninterface und -protokoll herangezogen werden.
Der Programmspeicher wird Seite für Seite beschrieben und gelöscht.
Bevor eine Seite mit den Daten, die in dem temporären Seitenpuffer geladen sind,
programmiert wird, muss die Seite gelöscht werden.
Der temporäre Seitenpuffer wird 16-bitweise mit dem SPM-Befehl gefüllt.
Der Seitenpuffer kann sowohl vor dem Seitenlösch-Kommando
als auch zwischen dem Seitenlösch-Kommando und dem Schreiben der Seite gefüllt werden.
Variante 1: Füllen des Puffers vor dem Löschen:
- Füllen des temporären Seitenpuffers
- Löschen der Seite
- Schreiben der Seite
Variante 2: Füllen des Puffers zwischen dem Löschen und Schreiben:
- Löschen der Seite
- Füllen des temporären Seitenpuffers
- Schreiben der Seite
Wenn nur ein Teil einer Seite verändert werden muss, muss der Rest der Seite vorher rückgelesen werden
(z.B. im temporären Seitenpuffer), da vor dem Schreiben immer die gesamte Seite gelöscht wird.
Wenn Variante 1 verwendet wird, bietet der Urloader echtes, byteweises Lesen-Verändern-Schreiben an.
In dieser wird die Software zunächst die Seite lesen, dann die notwendigen Veränderungen durchführen
und anschließend die modifizierten Daten zurückschreiben.
Wenn Variante 2 verwendet wird, ist es nicht möglich, die alten Daten zu lesen,
da die Seite bereits gelöscht wurde.
Auf den temporären Seitenpuffer kann frei zugegriffen werden.
Es ist wichtig, dass die Seitenadresse beim Löschen und Schreiben der Seite
die gleiche Flash-Seite adressiert.
26.1.1 Seite löschen
Zum Löschen einer Seite wird die Seitenadresse im Zeigerregisterpaar Z hinterlegt,
der Wert 0b00000011 in das SPMCSR geschrieben und innerhalb von 4 Taktzyklen ein SPM-Befehl ausgeführt.
Die Daten in R1 und R0 werden dabei ignoriert.
Die Seitenadresse muss in den Bereich PCPAGE in Z geschrieben werden,
die anderen Bits von Z werden bei dieser Operation ignoriert.
- Die CPU wird für die Dauer des Löschens der Seite angehalten.
So als ob der SPM-Befehl eine Ausführungszeit von einigen Millisekunden hätte.
- Hinweis:
-
Wenn ein Interrupt innerhalb der zulässigen vier Taktzyklen zwischen den beiden Befehlen auftaucht,
kann der Zugriff nicht korrekt erfolgen.
Um atomare (unterbrechungsfreie) Aneinandereihung der Befehlsausführung zu garantieren,
sollten die Interrupts vor dem Schreiben von SPMCSR gesperrt werden.
26.1.2 Zwischenpuffer füllen (Seite laden)
Zum Schreiben eines Befehlswortes wird die Adresse im Zeigerregisterpaar Z hinterlegt,
die Daten in R1:R0 geschrieben, der Wert 0b00000001 in das SPMCSR geschrieben
und innerhalb von vier Taktzyklen ein SPM-Befehl ausgeführt.
Der PCWORD-Bereich von Z wird verwendet, um die Daten im temporären Puffer zu adressieren.
Der temporäre Puffer wird automatisch nach dem Befehl Seite-Schreiben gelöscht,
aber auch durch Beschreiben des RWWSRE Bits im SPMCSR.
Er wird auch nach einem System-Reset gelöscht.
Man beachte, dass es nicht möglich ist, mehr als einmal in eine Adresse zu schreiben,
ohne dass der temporäre Puffer gelöscht wird.
Wenn der EEPROM mitten in einer Seitenlade-Operation beschrieben wird,
gehen alle geladenen Daten verloren.
26.1.3 Seite schreiben
Um das Schreiben einer Seite durchzuführen, wird die Adresse im Zeigerregisterpaar Z hinterlegt,
der Wert 0b0000101 in das SPMCSR geschrieben und innerhalb von vier Taktzyklen ein SPM-Befehl ausgeführt.
Die Daten in R1:R0 werden dabei ignoriert.
Die Seitenadresse muss in dem Bereich PCPAGE von Z geschrieben werden,
die anderen Bits von Z müssen während dieser Operation auf Null gesetzt sein.
- Die CPU wird für die Dauer des Löschens der Seite angehalten.
So als ob der SPM-Befehl eine Ausführungszeit von einigen Millisekunden hätte.
26.2 Adressierung beim Selbstprogrammieren
Das Zeigerregisterpaar Z wird zur Adressierung des SPM-Befehls benutzt (= impliziter Operand).
Bit | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8
|
ZH(R31) | Z15 | Z14 | Z13 | Z12 | Z11 | Z10 | Z9 | Z8
|
---|
ZL(R30) | Z7 | Z6 | Z5 | Z4 | Z3 | Z2 | Z1 | Z0
|
---|
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0
|
Da der Flash-Speicher in Seiten organisiert ist (siehe Tabelle 28-11),
kann man sich den Programmzähler in zwei Teile aufgeteilt vorgestellen.
Die niederwertigen Bits addressieren ein 16-Bit-Wort in einer Seite, und der höherwertige Teil
adressiert die Seite. Siehe Bild 26-1.
Man beachte, das Seite-Löschen und Seite-Schreiben unabhängig adressiert werden.
Daher muss die Software gleiche Adressen zum Seitenlöschen und Seitenschreiben
sicherstellen.
Auch für den LPM-Befehl wird Z (implizit oder explizit) zur Adressierung verwendet.
Da dieser Befehl byteweise arbeitet, wird hierbei auch das LSB (Bit 0) von Z verwendet.
Bild 26-1: Flash-Adressierung während SPM (1)
- Hinweis:
- Die verschiedenen Variablen im Bild 26-1 sind in Tabelle 28-11 gelistet.
26.2.1 EEPROM schreiben behindert Schreibzugriff auf SPMCSR
Man beachte, dass das Beschreiben des EEPROM alle Programmierungen des Flash blockiert.
Das Lesen der Fuses und Sperrbits durch die Software ist ebenfalls
während der Beschreibens des EEPROM nicht möglich.
Es wird daher empfohlen, dass der Anwender überprüft,
ob das Statusbit EEWE im EECR-Register gelöscht ist, bevor in das SPMCSR geschrieben wird.
26.2.2 Fuse- und Sperrbits lesen
Es ist möglich, sowohl die Fuses als auch die Sperrbits durch die Software auszulesen.
Zum Lesen der Sperrbits wird das Zeigerregisterpaar Z mit 0x0001 geladen
und die Bits BLBSET und SPMEN im SPMCSR gesetzt.
Wenn innerhalb der nächsten drei Taktzyklen nach dem Setzen der beiden Bits
ein LPM-Befehl ausgeführt wird, werden die Werte der Sperrbits in das LPM-Zielregister geladen.
Die beiden Bits werden nach dem Ausführen des Befehls automatisch gelöscht oder dann,
wenn innerhalb der Zeit kein LPM-Befehl ausgeführt wird.
Wenn BLBSET und SPMEN gelöscht sind, arbeitet der LPM-Befehl wieder normal,
so wie in der Befehlsübersicht beschrieben.
Bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0
|
Rd | - | - | - | - | - | - | LB2 | LB1
|
---|
Das Auslesen der Low-Fuse ist mit dem Lesen der Sperrbits vergleichbar.
Zum Lesen der Low-Fuse (Fuse-Low-Bits = FLB)
wird das Zeigerregisterpaar Z mit 0x0000 geladen und die Bits BLBSET und SPMEN im SPMCSR gesetzt.
Wenn innerhalb der nächsten drei Taktzyklen nach dem Setzen der beiden Bits
ein LPM-Befehl ausgeführt wird, werden die Werte der Low-Fuse in das LPM-Zielregister geladen,
wie nachfolgend dargestellt.
Siehe Tabelle 28-9 zur Zuordnung der Bits der Low-Fuse.
Bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0
|
Rd | FLB7 | FLB6 | FLB5 | FLB4 | FLB3 | FLB2 | FLB1 | FLB0
|
---|
Vergleichbar wird zum Lesen der High-Fuse (Fuse-High-Bits = FHB)
das Zeigerregisterpaar Z mit 0x0003 geladen und die Bits BLBSET und SPMEN im SPMCSR gesetzt.
Wenn innerhalb der nächsten drei Taktzyklen nach dem Setzen der beiden Bits
ein LPM-Befehl ausgeführt wird, werden die Werte der High-Fuse in das LPM-Zielregister geladen,
wie nachfolgend dargestellt.
Siehe Tabelle 28-7 zur Zuordnung der Bits der High-Fuse.
Bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0
|
Rd | FHB7 | FHB6 | FHB5 | FHB4 | FHB3 | FHB2 | FHB1 | FHB0
|
---|
Vergleichbar wird zum Lesen der Extended-Fuse (Extended-Fuse-Bits = EFB)
das Zeigerregisterpaar Z mit 0x0002 geladen und die Bits BLBSET und SPMEN im SPMCSR gesetzt.
Wenn innerhalb der nächsten drei Taktzyklen nach dem Setzen der beiden Bits
ein LPM-Befehl ausgeführt wird, werden die Werte der Extended-Fuse in das LPM-Zielregister geladen,
wie nachfolgend dargestellt.
Siehe Tabelle 28-4 zur Zuordnung der Bits der Extended-Fuse.
Bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0
|
Rd | - | - | - | - | - | - | - | EFB0
|
---|
Programmierte Fuse- und Sperrbits werden als Null gelesen. Unprogrammierte Fuse- und Sperrbits werden als Eins gelesen.
26.2.3 Schreibfehler vermeiden
Wenn UCC zu niedrig ist, kann das Programmieren des Flash verderben,
weil die Versorgungsspannung zu niedrig für ein korrektes Arbeiten der CPU und des Flash ist.
Das gilt für alle Systeme mit Flash-Speicher.
Ein Verfälschen des Flash-Programmierens kann in zwei Situationen,
in denen die Versorgungsspannung zu gering ist, begründet sein.
Erstens benötigt ein regulärer Schreibvorgang eine Mindestspannung, um korrekt zu arbeiten.
Zweitens kann die CPU selbst Befehle falsch ausführen, wenn die Versorgungsspannung zu gering ist.
Flash-Fehler können verhindert werden, wenn folgende Designregeln beachtet werden (eine genügt):
- Halten des AVR-Resets auf aktiv Low in Zeiten unzureichender Versorgungsspannung.
Dies kann durch Freigabe des internen Unterspannungs-Detektors geschehen.
Andernfalls kann eine externe Spannungsüberwachung eingesetzt werden.
Wenn ein Reset auftritt, während ein Schreibvorgang läuft,
so wird dieser Vorgang noch bis zum Ende ausgeführt, vorausgesetzt,
die Spannungsversorgung ist noch ausreichend.
- Versetzen des AVR-Kerns in den Power-Down Sleep-Modus wenn UCC zu gering ist.
Das schützt die CPU davor, Befehle zu dekodieren und auszuführen,
woduch auch das SPMCSR geschützt wird und somit auch der Flash.
26.2.4 Programmierzeit für Flash-Speicher mittels SPM
Der kalibrierte RC-Oszillator regelt die Zeiten beim Flash-Zugriff.
Nachfolgende Tabelle zeigt die typischen Programmierzeiten des Flash durch die CPU.
Tabelle 26-1: SPM-Programmierzeit(1)
Aktion | Minimale Programmierzeit | Maximale Programmierzeit
|
---|
Flash schreiben (Seiten löschen, Seite schreiben, Sperrbits mittels SPM setzen) | 3,7 ms | 4,5 ms
|
- Hinweis:
- Minimale und maximale Programmierzeit gelten für jede einzelne Operation.
26.2.5 Einfaches Assembler-Beispiel für einen Urlader
Beachte, dass das RWWSB-Bit im ATmega48 stets Null liest.
Nichtsdestotrotz wird empfohlen, das Bit wie in den Kode-Beispielen zu überprüfen,
damit die Software auch bei den größeren oder künftigen Chips mit Lesen-beim-Schreiben funktioniert.
;- Diese Routine schreibt eine Seite vom RAM zum Flash.
; Die erste RAM-Speicherzelle wird durch Y adressiert.
; Die erste Flash-Speicherzelle wird durch Z adressiert.
;- Fehlerbehandlung ist nicht dabei.
;- Verwendete Register: R0, R1, temp1 (R16), temp2 (R17), loop (R18), spmcrval (R19)
; Retten und Siederherstellen (Push+Pop) ist hier nicht eingebaut.
; Registerverbrauch kann gegen Kodegröße eingespart werden.
;- Es wird PAGESIZEB ≤ 256 für 8-Bit-Schleifenzähler vorausgesetzt.
.equ PAGESIZEB = PAGESIZE*2 ;PAGESIZEB = Seitengröße in BYTE, nicht in WORD
.org SMALLBOOTSTART
Write_page:
; Seite löschen
ldi spmcrval, (1<<PGERS) | (1<<SPMEN)
rcall Do_spm
; RWW-Bereich wiederherstellen (unnötig für ATmega48)
ldi spmcrval, (1<<RWWSRE) | (1<<SPMEN)
rcall Do_spm
; Daten vom RAM zum Flash-Seitenpuffer schaufeln
ldi loop, PAGESIZE ;Schleifenzähler initialisieren
Wrloop:
ld r0, Y+
ld r1, Y+
ldi spmcrval, (1<<SPMEN)
rcall Do_spm
subi ZL, -2 ;= +2, ohne Überlauf zum High-Teil
dec loop
brnz Wrloop
; execute Page Write
subi ZL, PAGESIZEB ;Zeiger wiederherstellen
ldi spmcrval, (1<<PGWRT) | (1<<SPMEN)
rcall Do_spm
; re-enable the RWW section
ldi spmcrval, (1<<RWWSRE) | (1<<SPMEN)
rcall Do_spm
; read back and check, optional
ldi loop, PAGESIZEB ;Schleifenzähler initialisieren
subi YL, PAGESIZEB ;Zeiger wiederherstellen
sbci YH, 0
Rdloop:
lpm r0, Z+
ld r1, Y+
cpse r0, r1
rjmp Error ;Nicht gezeigte Fehlerbehandlung
dec loop
brnz Rdloop
; Rückkehr zum RWW-Bereich
Return: ; Warten bis RWW-Bereich bereit zum Lesen ist (unsinnig für ATmega48)
in temp1, SPMCSR
sbrs temp1, RWWSB
ret
; RWW-Bereich wiederherstellen (unsinnig für ATmega48)
ldi spmcrval, (1<<RWWSRE) | (1<<SPMEN)
rcall Do_spm
rjmp Return
Do_spm:
; Warten bis vorheriges SPM fertig (unsinnig für ATmega48)
Wait_spm:
in temp1, SPMCSR
sbrc temp1, SPMEN
rjmp Wait_spm
; Warten bis evtl. EEPROM-Schreibzugriff fertig ist (Interrupts okay)
Wait_ee:
sbic EECR, EEPE
rjmp Wait_ee
; Eingabe: spmcrval legt SPM-Aktion fest
; Interrupts sperren, falls freigegeben, Zustand retten
in temp2, SREG
cli
; Spezielle zeitabhängige SPM-Sequenz
out SPMCSR, spmcrval
spm
; SREG wiederherstellen (Interrupts freigeben wenn vorher freigegeben)
out SREG, temp2
ret
|
26.3 Register-Beschreibung
26.3.1 SPMCSR — SPM-Kontroll- und Statusregister
Das SPMCSR enthält Steuerbits, die benötigt werden, um die Urlader-Funktionen zu steuern.
Bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0
|
(0x57) | SPMIE | RWWSB | SIGRD | RWWSRE | BLBSET | PGWRT | PGERS | SPMEN | SPMCSR
|
---|
Zugriff | R/W | R | R/W | R/W | R/W | R/W | R/W | R/W
|
Startwert | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
|
- Bit 7 — SPMIE: SPM-Interruptfreigabe
Wenn das SPMIE-Bit auf 1 gesetzt ist und das I-Bit im Statusregister gesetzt ist, wird der SPM-Fertig-Interrupt freigegeben.
Der SPM-Fertig-Interrupt wird ausgeführt, sobald das SPMEN-Bit im SPMCSR (durch die Hardware) gelöscht ist.
Beim ATmega48 ist dieser Interrupt wegen der angehaltenen CPU recht zweckfrei.
- Bit 6 — RWWSB: Lesen-beim-Schreiben-Bereich beschäftigt
Beim ATmega48 ist dieses Bit stets Null.
- Bit 5 — SIGRD: Lesen der Signaturzeile
Mit diesem Bit kann man die Chip-Signatur (Herstellerkennung) sowie das RC-Oszillator-Werkskalibrierbyte auslesen.
Siehe Signaturbytes lesen.
Das Beschreiben mittels SPM ist wirkungslos und sollte wegen künftiger Erweiterungen unterlassen werden.
- Bit 4 — RWWSRE: Lesen-beim-Schreiben-Bereich Lesefreigabe
Da der ATmega48 keine RWW- und NRWW-Bereiche hat, verbleibt mit diesem Bit nur eine Restfunktionalität:
Wird dieses Bit während des Füllvorgangs gesetzt, wird der Puffer gelöscht.
- Bit 3 — BLBSET: Urlader-Sperrbits setzen
Beim ATmega48 können damit die Fuse- und Sperrbits gelesen werden;
er hat keine Urlader-Sperrbits. Siehe oben.
- Bit 2 — PGWRT: Seite schreiben
Wenn dieses Bit gleichzeitig mit SPMEN auf Eins gesetzt wird,
wird der nächste SPM-Befehl innerhalb von vier Taktzyklen
das Beschreiben einer Seite mit den Daten, die im temporären Puffer gespeichert sind, starten.
Die Seitenadresse wird aus dem oberen Teil des Registerpaars Z entnommen.
Die Daten in R1 und R0 werden ignoriert.
Das PGWRT-Bit wird, nachdem die Seite geschrieben wurde, automatisch gelöscht oder dann,
wenn der SPM-Befehl nicht innerhalb der vier Taktzyklen ausgeführt wurde.
Die CPU wird während des Schreibvorgangs angehalten.
- Bit 1 — PGERS: Seite löschen
Wenn dieses Bit gleichzeitig mit SPMEN auf Eins gesetzt wird,
wird der nächste SPM-Befehl innerhalb von vier Taktzyklen
das Löschen einer Seite starten.
Die Seitenadresse wird aus dem oberen Teil des Registerpaars Z entnommen.
Die Daten in R1 und R0 werden ignoriert.
Das PGERS-Bit wird automatisch gelöscht, wenn die Seite gelöscht wurde
oder wenn innerhalb der nächsten vier Taktzyklen kein SPM-Befehl ausgeführt wurde.
Die CPU wird während des Löschvorgangs angehalten.
- Bit 0 — SPMEN: Freigabe des SPM-Befehls
Dieses Bit gibt die Ausführung eines SPM-Befehls innerhalb der nächsten vier Taktzyklen frei.
Wenn es zusammen mit einem der Bits RWWSRE, BLBSET, PGWRT oder PGERS gesetzt wird,
hat der folgende SPM-Befehl eine besondere Bedeutung, wie oben beschrieben.
Wenn nur SPMEN allein auf Eins besetzt wird, wird der folgende SPM-Befehl die Werte,
die in R1:R0 stehen, in den Seitenpuffer speichern,
der durch den Registerpaar Z adressiert ist.
Dabei wird das LSB von Z ignoriert.
Das SPMEN-Bit wird automatisch gelöscht, wenn ein SPM-Befehl ausgeführt wurde,
oder spätestens nach vier Taktzyklen.
Während des Löschens und Schreibens einer Seite verbleibt das SPMEN-Bit so lange High,
bis die Operation vollständig abgeschlossen ist.
Das Schreiben anderer Werte als 0b10001, 0b01001, 0b00101, 0b00011 oder 0b00001
in die unteren fünf Bits hat keine Auswirkungen.