.eseg ansprechen
Hallo,
man unterscheidet ja .cseg, "Codesegment", ab Adressse hex 0x0000, wo das Programm hineingehört, wo auch alle Features und Operationen ausgeführt werden können mit der kürzesten Zugriffszeit,
dann das .dseg, welches als "Datensegment" ab Adresse 0x0060 Konstanten aufnehmen kann, die im Programm per spezielle Befehlsstrukturen (sts, lds etc) geladen und zurückgeschrieben werden können, mit fast doppelter Zugriffzeit gegenüber dem .cseg,
dann noch das .eseg, das "Epromsegment", das nach besonderen Schreib- und Leseroutinen verlangt, und in das Variable und Konstanten geschrieben werden können während des Programmverlaufes, die nach Abschalten der Betriebsspannung erhalten bleiben.
Die Schreibzyklen auf das .eseg sind aber auf ca. 100000 Zyklen begrenzt, die Lesezyklen unbegrenzt.
Programmanteile für das Epromsegment kommen in einem zweiten Flashvorgang als sogenannte *.eep- Files zur Speicherung.
Dafür ist im Studio4 eine extra Rubrik eingerichtet. Hex-Files werden hier nicht akzeptiert.
Das hatte ich auch schon mal versucht, klappt aber nicht.
Das Programm sollte evtl vorher umgeschrieben werden in AVR-ASM.
Die gängigsten Routinen sehen dann beispielsweise so aus:
PHP:
eeprom_x:
push temp ; temp auf dem Stack sichern
;in temp, sreg ; SREG sicher, muss praktisch in jeder ; ; Interruptroutine gemacht werden
;push temp
;in temp, UDR ; empfangenes Byte lesen
mov temp, min
rcall eeprom_write ; Byte im EEPROM speichern
adiw ZL:ZH, 1 ; Zeiger erhöhen
cpi ZL, low(eepromend+1) ; Vergleiche den Z-Zeiger ldi temp, high(eepromend+1) ; mit der maximalen EEPROM
; ; Adresse +1
cpc ZH, temp
brne eeprom_1 ; wenn ungleich, springen
ldi ZL, low(datenx) ; wenn gleich, Zeiger zurücksetzen ldi ZH, high(daten)
eeprom_1:
pop temp
;out sreg, temp
;pop temp ; temp wiederherstellen
ret
eeprom_write:
sbic EECR, EEWE ; prüfe, ob der letzte Schreibvorgang ; ; beendet ist
rjmp EEPROM_write ; wenn nein, nochmal prüfen
;out EEARH, ZH ; Adresse schreiben
out EEARL, ZL
out EEDR, temp ; Daten schreiben
push temp2
in temp2, sreg ; SREG sichern
push temp2
cli ; Interrupts sperren, die nächsten ; ; zwei Befehle dürfen NICHT ; ; unterbrochen werden
sbi EECR, EEMWE ; Schreiben vorbereiten
sbi EECR, EEWE ; Und los !
pop temp2
out sreg, temp2 ; SREG wiederherstellen
pop temp2
sei
ret ; hier wird der EEPROM-Inhalt definiert
;
.eseg
.org 0xFF
datenx:
.db 0
.cseg
eeprom_senden:
;ldi ZL, low(text1x) ; ersten String senden
;ldi ZH, high(text1x) ; Z-Pointer laden
ldi ZL, low(datenx)
ldi ZH, high(datenx)
rcall EEPROM_print
ret
EEPROM_print:
sbic EECR, EEWE ; prüf ob der vorherige Schreibzugriff ; ; beendet ist
rjmp EEPROM_print ; nein, nochmal prüfen
;out EEARH, ZH ; Adresse laden
out EEARL, ZL
sbi EECR, EERE ; Lesevorgang aktivieren
in r0, EEDR ; Daten in CPU Register kopieren
tst r0 ; auf 0 testen (=Stringende)
breq eep_print_end ; falls 0, Funktion beenden
rcall position2
;mov temp, r0
rcall position3
mov temp, r0
rcall hexumrechnung ; ansonsten Byte senden...
adiw ZL:ZH, 1 ; Adresse um 1 erhöhen...
rjmp EEPROM_print ; und zum Anfang der Funktion
eep_print_end:
ret
;.eseg
;text1x:
;.db "Tt", 0
;.cseg
wie immer, ohne Gewähr.
Die Idee war, Zeit- bzw. Messwerte auf LCD darzustellen und periodisch im Epromsegment abzulegen, na ja, man "müllt" sich aber dann ziemlich schnell das EEprom zu, so daß es bald nicht mehr beschreibbar ist. Daher mit äußerster Vorsicht zu genießen, nur mal ein paar Minuten laufen lassen, sozusagen als Test, ob das EEprom überhaupt ansprechbar ist.
Wenn ich Dich @Kani, richtig verstehe, möchtest Du ein "fixes" Programm im Epromsegment hinterlegen, das sozusagen wie ein ausführbarer Code läuft. Das ist aber, so verstehe ich das EEprom hier, nicht so angedacht. Ein Code muß immer in dem .cseg "Codesegment" ablaufen,
da hier und nur hier die Operationen in den Registern r16 bis r32 (oder so) ablaufen können,
das ergibt sich aus der "Havard Architektur" der Atmel AVRs, die ja alles in einem Taktzyklus erledigen, also, Laden von Werten, Ausführen von (arithmetischen) Operationen und zurückschreiben des Ergebnisses in dasselbe Register innerhalb eines Taktzyklus'. Dafür sind diese Register konstruiert, bei den anderen Speicherbereichen oberhalb von hex 0x0060 klappt das nicht. (Oder liege ich da total falsch?)
Die "Umladerei" beginnt schon bei Verwendung des .dseg:
PHP:
; hier Bytes reserviert, um
;Temporärregister einzusparen
.dseg ; Zeitschleifen-Ladewerte
.org 0x0060 ; kommen ins Datensegment
zeit_0: .BYTE 4 ; vier Bytes dafuer reservieren
.org 0x0065 ; Startfunktionsjobregister
start_0: .BYTE 1 ; Wert ins Datensegment
.cseg ; Rueckkehr ins Codesegment
.org 0x0000 ; Anfangsadresse bei Null
; hier werden die Werte geladen:
schreiben_dseg: ; Zeitschleifen-Ladewerte ins DSEG
; laden
push temp
ldi temp, 0xFF ; 4 Bytes wurden im Direktiventeil
sts zeit_0, temp ; oben im Label Zeit_0 reserviert
sts zeit_0+1, temp ; durch BYTE-Anweisung
ldi temp, 0x85
sts zeit_0+2, temp
ldi temp, 0x9F
sts zeit_0+3, temp
ldi temp, 0x01
sts start_0, temp ; ein Byte fuer Startjob reserviert
pop temp
;
; hier werden sie wieder zurückgeholt, um damit arbeiten zu können:
;
push temp ; Sicherung der Temporaerregister
push temp1 ; auf Stack
lds temp, zeit_0 ; Umladen von DSEG-Zeitkonstanten
lds temp1, zeit_0+3 ; auf Temporaerregister
;.............
Gruß von Oskar