PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Fehler in AVR Studio???



Lektor
20.06.2007, 20:43
Hallo,
ich habe den AVR Studio 4.12 SP4 und dort versuche ich das Beschreiben des internen EEPROMS eines Mega8's zu simulieren.

Die zu beschreibende Adresse wähle ich nach jedem Schreibzugriff so:

inc r22
out EEARL,r22

das scheint aber nicht so richtig zu funktionieren. r22 wird zwar inkrementiert, aber der Wert aus r22 wird nicht in EEARL geschrieben. Das mit dem out habe ich aus dem mikrocontroller.net Tutorial. mov funktioniert leider auch nicht ohne Fehlermeldung.

wenn ich EEARL manuell inkrementiere, dann funktioniert die Simulation, nur selber funktioniert dieses out EEARL,r22 nicht.

Ist das jetzt ein Fehler im Simulator? Im Programm? Kann ich davon ausgehen, dass es auf einem µC richtig läuft?

Ich verstehe auf jeden Fall nicht, warum dieser out Befehl nicht durchgeführt wird und rechne mit einem Simulatorfehler.

Rofo88
20.06.2007, 20:53
Hast Du im Simulator auch den richtigen AVR drinn (Alt+O)?

Bei mir funzt das einwandfrei.

MfG

Lektor
20.06.2007, 20:55
ATmega8

Flash Size: 8192 bytes
Eeprom Size: 512 bytes
Internal SRAM Size: 1024 bytes
IO Size: 64 bytes

4MHz


liegt wohl nicht an der Geschwindigkeit. Welche Version hast denn vom AVR Studio?

Danke schonmal fürs nachschauen.

Rofo88
20.06.2007, 21:03
Version 4.13 Build 528

Aber obs daran liegt?

wkrug
20.06.2007, 21:37
Beschreibst DU auch das EEARH ?
Vieleicht wird die Adresse erst übernommen wenn beide Register in der richtigen Reihenfolge beschrieben sind - Schau mal ins Code Beispiel.

Lektor
20.06.2007, 21:51
also ich habe es mal mit dem EEARH beschreiben ausprobiert:
out EEARH,r21
inc r22
out EEARL,r22

hat aber auch nicht funktioniert. Die neuste Version des AVR Studios habe ich mir auch runtergeladen, aber irgendwie startet der Installer nicht. Werde es mal morgen ausprobieren; heute habe ich den Nerv nicht dazu. :)

wkrug
20.06.2007, 23:21
Also diese Routine funzt bei mir im Simulator ohne Probleme und schreibt den Wert 0x55 auf EEPROM Adresse 0x0020.


EEPROM_write:
sbic EECR,EEWE
rjmp EEPROM_write
ldi temp,0x00
out EEARH,temp
ldi temp,0x20
out EEARL,temp
ldi temp,0x55
out EEDR,temp
sbi EECR,EEMWE
sbi EECR,EEWE
Hab Studio Version 4.12 Service Pack 4
Built 498

Lektor
21.06.2007, 11:44
puhh, dass war ein Theater heute. Also nachdem ich gestern den Fehler hatte, wollte ich mir die neuste Version dieses Programms installieren. Datei heruntergeladen und in der Zwischenzeit das alte AVR Studio deinstalliert. Hast gleich ne neue Version, dann löscht du mal die alten Installationsdateien. Wollte die neue Version installieren....ging nicht; drei Sekunden Sanduhr und nichts weiter. Ok, vielleicht ist die Datei defekt, habe sie dann nochmal dreimal heruntergeladen und ausprobiert. Ging nicht. Ok, dann installierst du halt wieder die alte Version. Heruntergeladen, versucht zu installieren, ging auch nicht. Dann erstmal gegoogelt und einen Forumslink gefunden, wo auf einem Beitrag einer von Atmel geantwortet hat. Habe also die Anweisungen befolgt und paar Verzeichnisse und Registrierungseinträge gelöscht, ging dann auch noch nicht. Und ganz unten im Beitrag stand dann, dass man die Dateien mit dem Explorer herunterladen soll und dann ging das Installieren auch. Merkwürdig, aber durch dieses Theater habe ich wieder drei Stunden verloren.

So, jetzt zum Eigentlichen.
@wkrug: so habe ich es auch, nur wollte ich beim nächsten Durchlauf von EEPROM_write die 0x55 auf die nächste Adresse schreiben (EEARL=0x21), was ich mit dem Inkrementierbefehl gemacht habe, nur dann ändert sich der Wert in EEARL nicht, wenn ich ihn dann mit out übergebe. In temp hat er dann inkrementiert, nur mit out wird nicht EEARL auf 0x21 geschrieben.


loop:
;--------DEIN CODE----------
EEPROM_write:
sbic EECR,EEWE
rjmp EEPROM_write
ldi temp2,0x00
out EEARH,temp
ldi temp,0x20
out EEARL,temp
ldi temp1,0x55
out EEDR,temp
sbi EECR,EEMWE
sbi EECR,EEWE
;--------------/DEIN CODE----------
inc temp
out EEARL,temp
rjmp loop

Also für mich war es logisch, dass wenn man den EEARL inkrementiert, er dann den Wert auf die nächste Adresse schreibt. Nur mit dem out ändert sich der Wert in EEARL nicht.


hier mal der gesamte Code meines bisherigen Programms. Leider nicht so übersichtlich, wie ich es mir gewünscht hätte....


.include "m8def.inc"

.def temp = r16
.def temp1= r17
.def temp2= r18
.def temp3= r19
.def adhigh=r20
.def eepromh=r21
.def eeproml=r22
.equ CLOCK = 4000000 ; externer Oszi, weil sonst USART nicht funktioniert
.equ BAUD = 9600
.equ UBRRVAL = CLOCK/(BAUD*16)-1

.org 0x00
rjmp reset

.org URXCaddr
rjmp int_rxc
;//////////////////Initialisierung/////////
reset: ; Stackpointer initialisieren
ldi temp, LOW(RAMEND)
out SPL, temp
ldi temp, HIGH(RAMEND)
out SPH, temp
;---------------Uart---------------------
; Baudrate einstellen
ldi temp, LOW(UBRRVAL)
out UBRRL, temp
ldi temp, HIGH(UBRRVAL)
out UBRRH, temp

; Frame-Format: 8 Bit
ldi temp, (1<<URSEL)|(3<<UCSZ0);|(0<<USBS);|(1<<UMSEL)
;URSEL muss 1 sein, wenn UCSRC beschrieben wird.
;UCSZ0 = 3 entspricht 011 binär und setzt Datenbreite auf 8Bits
out UCSRC, temp

sbi UCSRB, RXCIE ; Interrupt bei Empfang
sbi UCSRB, RXEN ; RX (Empfang) aktivieren

sei ; Interrupts global aktivieren

;--------------/Uart----------------------

;--------------ADC------------------------
; ADC initialisieren:
ldi temp, (1<<REFS0) | (5<<MUX0) | (1<<ADLAR) ; REFS=1 entspricht interne Referenzspannung 5V; MUX wählt ADC5 Pin28 PC5 aus ;ADLAR=1 bei 8bit reicht ADCH
out ADMUX, temp
ldi temp, (1<<ADEN) | (7<<ADPS0); ADEN ADC Enable (anschalten); ADPS 111 entspricht Divisionsfaktor 128
out ADCSRA, temp
;--------------/ADC-----------------------


;-------EEPROM----------------------------
ldi r21,0x00 ; High-Adresse im EEPROM laden
out EEARH, r21 ; und ins EEARH schreiben
ldi r22, 0x00 ; Low-Adresse im EEPROM laden
out EEARL, r22 ; und ins EEARL schreiben
;-------/EEPROM----------------------------

;//////////////////Initialisierung ENDE/////////
loop:
; rcall threeminutes ;nach drei Minuten den ADC Wert einlesen

;--------------ADC Wert einlesen------------
sample_adc:
sbi ADCSRA, ADSC ; den ADC starten

wait_adc:
sbic ADCSRA, ADSC ; wenn der ADC fertig ist, wird dieses Bit gelöscht
rjmp wait_adc

in adhigh, ADCH ; High Byte des ADC in adhigh speichern

;--------------/ADC Wert einlesen------------
;--------------...und in EEPROM schreiben----

EEPROM_write:
cli ;Interrupts vorsichtshalber ausschalten

sbic EECR,EEWE ; Vorherigen Schreibvorgang abwarten
rjmp EEPROM_write

out EEDR,adhigh ; Daten ins EEPROM-Datenregister
sbi EECR,EEMWE ; Schreiben vorbereiten
sbi EECR,EEWE ; muss innerhalb von 4 Zyklen geschrieben werden, deswegen Interrupts aus.
sei ;Interrupts wieder einschalten
inc r22
out EEARL,r22
sei

;--------------/...und in EEPROM schreiben----
rjmp loop

int_rxc: ; wenn vom PC etwas empfangen wird, dann wird Interrupt ausgelöst und hierher gesprungen
push temp ; temp auf dem Stack sichern
in temp, UDR ; empfangenes Byte von UDR in temp speichern
BREQ 1 ;wenn eine 1 übertragen wurde, dann sollen die Werte aus dem EEPROM an den PC gesendet werden.
rcall DatenSenden
BREQ 2 ;wenn eine 2 gesendet wird, dann soll EEPROM gelöscht werden
rcall DatenLoeschen
pop temp ; temp wiederherstellen
reti




sbi UCSRB,TXEN ; TX aktivieren


ldi temp, 0xAA


DatenSenden:
ret
DatenLoeschen:
ret




serout:
sbis UCSRA,UDRE ; Warten bis UDR für das nächste
; Byte bereit ist
rjmp serout
out UDR, temp
ret ; zurück zum Hauptprogramm





;threeminutes:
; =============================
; delay loop generator
; 720000000 cycles:
; -----------------------------
; delaying 49939965 cycles:
ldi R17, $FF
WGLOOP0: ldi R18, $FF
WGLOOP1: ldi R19, $FF
WGLOOP2: dec R19
brne WGLOOP2
dec R18
brne WGLOOP1
dec R17
brne WGLOOP0
; -----------------------------
; delaying 49939965 cycles:
ldi R17, $FF
WGLOOP3: ldi R18, $FF
WGLOOP4: ldi R19, $FF
WGLOOP5: dec R19
brne WGLOOP5
dec R18
brne WGLOOP4
dec R17
brne WGLOOP3
; -----------------------------
; delaying 49939965 cycles:
ldi R17, $FF
WGLOOP6: ldi R18, $FF
WGLOOP7: ldi R19, $FF
WGLOOP8: dec R19
brne WGLOOP8
dec R18
brne WGLOOP7
dec R17
brne WGLOOP6
; -----------------------------
; delaying 49939965 cycles:
ldi R17, $FF
WGLOOP9: ldi R18, $FF
WGLOOP10: ldi R19, $FF
WGLOOP11: dec R19
brne WGLOOP11
dec R18
brne WGLOOP10
dec R17
brne WGLOOP9
; -----------------------------
; delaying 49939965 cycles:
ldi R17, $FF
WGLOOP12: ldi R18, $FF
WGLOOP13: ldi R19, $FF
WGLOOP14: dec R19
brne WGLOOP14
dec R18
brne WGLOOP13
dec R17
brne WGLOOP12
; -----------------------------
; delaying 49939965 cycles:
ldi R17, $FF
WGLOOP15: ldi R18, $FF
WGLOOP16: ldi R19, $FF
WGLOOP17: dec R19
brne WGLOOP17
dec R18
brne WGLOOP16
dec R17
brne WGLOOP15
; -----------------------------
; delaying 49939965 cycles:
ldi R17, $FF
WGLOOP18: ldi R18, $FF
WGLOOP19: ldi R19, $FF
WGLOOP20: dec R19
brne WGLOOP20
dec R18
brne WGLOOP19
dec R17
brne WGLOOP18
; -----------------------------
; delaying 49939965 cycles:
ldi R17, $FF
WGLOOP21: ldi R18, $FF
WGLOOP22: ldi R19, $FF
WGLOOP23: dec R19
brne WGLOOP23
dec R18
brne WGLOOP22
dec R17
brne WGLOOP21
; -----------------------------
; delaying 49939965 cycles:
ldi R17, $FF
WGLOOP24: ldi R18, $FF
WGLOOP25: ldi R19, $FF
WGLOOP26: dec R19
brne WGLOOP26
dec R18
brne WGLOOP25
dec R17
brne WGLOOP24
; -----------------------------
; delaying 49939965 cycles:
ldi R17, $FF
WGLOOP27: ldi R18, $FF
WGLOOP28: ldi R19, $FF
WGLOOP29: dec R19
brne WGLOOP29
dec R18
brne WGLOOP28
dec R17
brne WGLOOP27
; -----------------------------
; delaying 49939965 cycles:
ldi R17, $FF
WGLOOP30: ldi R18, $FF
WGLOOP31: ldi R19, $FF
WGLOOP32: dec R19
brne WGLOOP32
dec R18
brne WGLOOP31
dec R17
brne WGLOOP30
; -----------------------------
; delaying 49939965 cycles:
ldi R17, $FF
WGLOOP33: ldi R18, $FF
WGLOOP34: ldi R19, $FF
WGLOOP35: dec R19
brne WGLOOP35
dec R18
brne WGLOOP34
dec R17
brne WGLOOP33
; -----------------------------
; delaying 49939965 cycles:
ldi R17, $FF
WGLOOP36: ldi R18, $FF
WGLOOP37: ldi R19, $FF
WGLOOP38: dec R19
brne WGLOOP38
dec R18
brne WGLOOP37
dec R17
brne WGLOOP36
; -----------------------------
; delaying 49939965 cycles:
ldi R17, $FF
WGLOOP39: ldi R18, $FF
WGLOOP40: ldi R19, $FF
WGLOOP41: dec R19
brne WGLOOP41
dec R18
brne WGLOOP40
dec R17
brne WGLOOP39
; -----------------------------
; delaying 20840484 cycles:
ldi R17, $C4
WGLOOP42: ldi R18, $B3
WGLOOP43: ldi R19, $C5
WGLOOP44: dec R19
brne WGLOOP44
dec R18
brne WGLOOP43
dec R17
brne WGLOOP42
; -----------------------------
; delaying 6 cycles:
ldi R17, $02
WGLOOP45: dec R17
brne WGLOOP45
; =============================

ret

.eseg ; EEPROM-Segment aktivieren
daten:
.db 0b00000000

Lektor
21.06.2007, 14:20
so, habe mich nach einer längeren Pause erstmal wieder dran gesetzt und intensiv analysiert. Dabei ist mir aufgefallen, dass es einen Unterschied machte, wo ich dieses Inkrementieren durchgeführt habe und da fing ich dann genauer an zu suchen.
Es lag daran, dass ich direkt nach dem Schreiben den neuen Speicherort festlegen wollte und das ging nicht, weil dieses EEWE Bit noch auf 1 war. Habe also eine Abfrageschleife eingeführt und jetzt funktioniert es wie ich es mir vorgestellt habe. Bei jedem Durchlauf schreibt er den Wert des A/D Wandlers auf die nächste Speicherstelle. Genauso wollte ich es haben.

Aber danke für eure Bemühungen.



der korrekte Code sieht jetzt so aus (die Angabe des Speicherbeginns habe ich weggelassen)



EEPROM_write:
cli ;Interrupts vorsichtshalber ausschalten

sbic EECR,EEWE ; Vorherigen Schreibvorgang abwarten
rjmp EEPROM_write

out EEDR,adhigh ; Daten ins EEPROM-Datenregister
sbi EECR,EEMWE ; Schreiben vorbereiten
sbi EECR,EEWE ; muss innerhalb von 4 Zyklen geschrieben werden, deswegen Interrupts aus.
EEWEfrei:
sbic EECR,EEWE ; Vorherigen Schreibvorgang abwarten
rjmp EEWEfrei
inc r22
out EEARL,r22
sei ;Interrupts wieder einschalten

;--------------/...und in EEPROM schreiben----
rjmp loop

wkrug
21.06.2007, 16:29
..... dann war das eigentlich kein Fehler im AVR Studio, sondern in deinem Programm und Studio hat richtig reagiert.

Lektor
21.06.2007, 16:44
genauso war es leider. :(
Habe mir das Thema nicht besonders konzentriert in der Doku durchgelesen und nur ein Tutorial für meine Bedürfnisse angepasst.
Aber ich lerne aus Fehlern. :)

Wenn ich jetzt immer dieses EEWE Bit abfragen muss (beim Schreiben/Lesen des EEPROMS und beim Bestimmen der Speicheradresse), macht es dann Sinn, diese Abfrage über rcall laufen zu lassen?

wkrug
22.06.2007, 20:32
Wenn ich jetzt immer dieses EEWE Bit abfragen muss (beim Schreiben/Lesen des EEPROMS und beim Bestimmen der Speicheradresse), macht es dann Sinn, diese Abfrage über rcall laufen zu lassen?
Man könnte das schon über rcall machen, das löschen des EEWE Bits dauert ja nur ein paar Takte.
Schreib doch einfach ein EEPROM schreib und ein lese Programm und ruf diese Unterprogramme mit vorbelegten Werten in bestimmten Registern auf.
Dann kannst Du diese Routinen im gesamten Programm verwenden.

Beispiel
r16=EEPROMADRESSE low
r17=EEPROMADRESSE high
r18=EEPROMDATEN
call EEPROMWRITE