PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : ret springt nicht nach rcall befehl



freddy0815
01.12.2004, 14:42
hallo!

bin noch anfänger in sachen assembler. habe ein beispiel prog fürs übertragen über rs232 gefunden.

hier:


.NOLIST
.INCLUDE "D:\m32def.inc"
.LIST

.equ fck = 4000000
.equ baudrate = 4800

.equ baudconst = (fck / (baudrate * 16)) - 1

.def w = R19 ; Arbeitsregister
.def wi = R20 ; Interrupt-Arbeitsregister
.def rs_buf = R21 ; Buffer für empfangenes Byte
.def a_flag = R25 ; Flagregister

.equ rs_recv = 0 ; 1 = Byte empfangen - 0 = kein Byte empfangen


; Interrupt-Adressen
.cseg
.org $0000
rjmp main

.org $0007 ; RS232 Empfangsinterrupt
rjmp rs232_recv ; RS232 Behandlungsroutinge wenn etwas empfangen wird



; I/O-Port Initialisierung:
hdw_init:
ldi w, 0b11111111
out PORTD, w ; alle Pins am Port D auf 1 setzen
ldi w, 0b11111110
out DDRD, w ; Datenrichtung am Port D festlegen: 1 = Ausgang; 0 = Eingang
; Pin 1 am Port D Empfangen (= 1) RX
; Pin 2 am Port D Senden (= 0) TX


ldi w, 0b11111111
out PORTB, w
ldi w, 0b11111111
out DDRB, w


; UART Initialisierung:
uart_init:
ldi w, baudconst
out UBRRL, w ; UBRR = USART Baud Rate Register
ldi w, 0
out UBRRH, w
ldi w, 0b00011000
out UCSRB, w ; RXEN und TXEN setzen
sbi UCSRB, RXCIE ; RS232 Interrupt freigeben


; PWM Initialisierung:
pwm_init:
ldi w, 0b10000001
out TCCR1A, w
ldi w, 0
out OCR1AH, w
ldi w, 1
out OCR1AL, w
ldi w, 0b00000001
out TCCR1B, w

sei ; gibt alle Interrups frei
ret


; Behandlung für empfangene Bytes:
rs_rec_up:
cbr a_flag, 1 << rs_recv; durch '1<<' wird eine '1' n-mal nach links geschoben
; für rs_recv = 0: 0b00000001
; für rs_recv = 1: 0b00000010
; --> das erste bzw zweite Bit in a_flag wird somit gelöscht

mov w, rs_buf ; empfangenes Byte in w
out PORTB, w ; an Port B ausgeben ?(kein PWM)?
out OCR1AL, w
rcall rs_send
ret


rs_send:
sbis UCSRA, UDRE ; überprüft, ob UDRE im Register UCSRA gesetzt ist, wenn ja (UDRE=1) überspringen
; UDRE = 1 Sender frei, UDRE = 0 Sender besetzt
rjmp rs_send
out UDR, w
ret


; Interruptroutine wenn Bytes empfangen werden:
rs232_recv:
in wi, SREG ; CPU-Status
push wi ; wi in Stackpointer

in wi, UDR ; Byte vom Empfänger laden
mov rs_buf, wi ; zwischenspeichern
sbr a_flag, 1<<rs_recv ; durch '1<<' wird eine '1' n-mal nach links geschoben
; für rs_recv = 0: 0b00000001
; für rs_recv = 1: 0b00000010
; --> das erste bzw zweite Bit in a_flag wird somit gesetzt

pop wi ; Stackpointer zurück in wi
out SREG, wi ; zurück zur CPU

reti ; Return from Interrupt


main:
ldi w, RAMEND ; RAMEND: Speicherende des Chips
out SPL, w ; in Stackpointer schreiben
clr a_flag
rcall hdw_init ; Hardware Initialisierung

endlos:
sbrc a_flag, rs_recv
rcall rs_rec_up ; wenn was empfangen wurde dann...
rjmp endlos ; sonst warten

die komentare sind von mir. können also auch falsch sein ;-)

geht man das prog schritt für schritt durch, springt er hier 'rcall hdw_init' in den initialisierungsteil. am ende von 'pwm_init:' steht ein 'ret'. an dieser stelle springt er aber dann nicht zurück zum 'rcall hdw_init' bzw in die endlosschleife, sondern springt ganz an den anfang zu: '.org $0000 rjmp main'

woran liegt das?

wird in 'main:' der stackpointer falsch beschrieben? was genau bedeutet denn RAMEND?

danke mal für eure geduld wenn ihr bis zum schluss gelesen habt! \:D/

freddy0815

AlexAtRobo
01.12.2004, 14:56
Hallo,

ich vermute, du liegst schon mal nicht schlecht.
m32def.inc ist ein ATMEGA32 oder irre ich mich? Dieser hat sicher mehr als 255 Bytes Ram. Deswegen muss nicht nur spl sondern auch sph gesetzt werden.
RamEnd ist eine Konstante die die Speichergröße enthält. Du kannst ja mal die m32def.inc aufmachen, da solltest du es finden. Der Stackpointer wird normalerweise immer auf das Ende des Rams gesetzt, da er decrementiert.
Ich habe leider meine Tools nicht bei mir sonst könnte ichs dir jetzt genauer sagen.

lg

Alex

freddy0815
01.12.2004, 15:04
vielen dank für der tipp!!

jetzt gehts. habe den sph auch gesetzt:

ldi w, HIGH(RAMEND)
out SPH, w
ldi w, LOW(RAMEND)
out SPL, w

und ich bin in meiner schleife drin :-)

danke
freddy

freddy0815
01.12.2004, 15:21
aber eins vielleicht noch. wie kann ich im debugg-modus manuell n interrupt auslösen?
in meinem fall isses n zeichen im UART-empfangspuffer.

freddy

AlexAtRobo
01.12.2004, 15:25
Du musst einfach das entsprechende Flag setzen. Lad dir das PDF vom ATMEGA32 oder was auch immer runter. Da steht drinnen, welches bit in welchem Register für das Auslösen der Interruptroutine verantwortlich ist.
Das entsprechende Bit setzt du dann einfach im Debugmodus, und die Interrupt Routine wird ausgelöst.

lg
Alex

freddy0815
01.12.2004, 16:00
wenn ichs richtig gefunden habe, isses das RXC bit im UCSRA register. wenn ich in meinem prog in der endlosschleife bin und das rxc setze, springt er zwar woanders hin, aber nicht in die eigentlich interrupt-routine.

genaugesagt springt er in die 'pwm_init:' unterfunktion in die zeile 'out OCR1AH, w'

weiss aber nicht warum. stöber mal durch die atmega32-pdfs. vielleicht wartet mich da ja die erlösung...

freddy0815

AlexAtRobo
01.12.2004, 16:22
Hm, wollt mir grad die Doku zum Mega 32 runterladen, aber atmel.com scheint für mich nicht erreichbar zu sein. Nur so ein Verdacht ins blaue hinein: Hast du kontrolliert, ob $0007 wirklich der Interrupt einsprungpunkt ist? Mir scheint, das das daran liegt. Ich bin mir jetzt auch nicht ganz sicher, aber vermutlich legt der Compiler das Programm dann ab $0008 rein. Dadruch kann es eben zu diesen lustigen effekten kommen.
Mein Vorschlag: Setz einfach mal alle Interrupteinsprungpunkte mit reti.
Dann siehst du besser, wo er landet. Keine Ahnung wieviele Interrupt Quellen es beim Mega 32 gibt.

.cseg
.org $0000
rjmp main
reti ; Kommt an Adr. 1
reti ; Kommt an Adr. 2
reti ; Kommt an Adr. 3
reti ; etc
reti
reti
reti
reti
reti
reti
reti
reti
reti
reti
reti
reti
reti
reti
reti
reti
reti
reti
reti
reti
reti ; Ich hab nur soviele gemacht, weil ich nicht weiß, was es beim mega32 alles gibt. Dadurch deckst du sicher den ganzen einsprungraum ab.
main:

Alles klar?

lg

Alex

AlexAtRobo
01.12.2004, 16:27
Kleine Frage noch nebenbei: War das Beispiel mit dem Mega 32 oder hast du selbst probiert es zu portieren? (Sph fehlte, Einsprungpunkt vermutlich falsch...). Dann tu ich mir auch gleich leichter, zu erkennen, woran du eventuell scheiterst...

lg

Alex

01.12.2004, 17:02
also ich hab nen atmega32. aber das programm is von nem kleineren kopiert. deswegen fehlte zb sph. kann dir jetzt leider nicht sagen welcher, da ich nicht mehr im labor bin. das mit reti werd ich versuchen. und mich dann spätestens nächste woche wieder melden! (wenn ichs dann ausprobiert hab)

mfg
freddy

und danke für deine mühe!!

freddy0815
03.12.2004, 10:13
es lag an der interrupt adresse. hatte noch $0007 drin statt $01A.
war auch noch n relikt ausm alten prog, das übrigens für ein at90s2313 geschrieben war.

gruß
freddy