PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : mehrere CALLs im interrupt



T.J.
05.05.2008, 23:28
Hallo, ich habe ein Problem mit zu vielen Calls im Interrupt.

Mein Programm ist so gestrickt, dass im Mainloop nix läuft (außer ne LED blinken) und in der ISR eine Nachricht per Uart gesendet wird.

Wenn ich nun nur 1byte sende (2 calls hintereinander) funktioniert es dauerhaft. Wenn ich aber einen Frame aus 6 bytes senden will (so soll die Funktion sein) viele calls und operationen, dann führt er das einmal korrekt aus aber bekommt danach kein Interrupt vom CAN mehr rein. Andere Interrupts gehen danach trotzdem. Er hängt sich auch nicht auf.

was muss ich da beachten? wieso kann ich nicht so viele calls machen wie ich will?



;Global Interrupt Vektor
ORG 0x0008
goto Isr
;************************************************* *****************************
; Start des Hauptprogramms *
;************************************************* *****************************
;
Main:
ORG 0x0100
rcall Init
MainLoop:
bcf LATC,5
bcf LATC,4
movlw 0x44
movwf xms
call wxms ;kurz warten
goto MainLoop
;
;************************************************* *****************************
; Initialisierung *
;************************************************* *****************************
Init:
; 8MHz als interne Frequenz
movlw 0x70
movwf OSCCON
; Portdirektionen definieren
movlw 0x08
movwf TRISB
movlw 0x8F
movwf TRISC
clrf LATC
; Schnittstellenkonfigurationen
rcall canInit
rcall uartInit
; Interrupts konfigurieren
bsf INTCON, 7 ; Global Int aktivieren
bsf INTCON, 6 ; Peripherie Int aktivieren
bsf PIE3, 0 ; Interrupt fuer RXB0 aktivieren
bsf PIE1, 5 ; Interrupt fuer EUSART receive aktivieren
return
;
Isr:
btfss PIR3, 0 ; CAN-Nachricht empfangen?
goto uartInt ; nein!
canInt:
bsf LATC,5
;CAN Nachricht nach UART senden
call canRecMsg
movf canIDL,w
xorlw 0x02
btfss STATUS,Z
goto nloadcanmsg
loadcanmsg:
movlw 0xFF
movwf uartsMsg
call uartSendMsg
; movf canIDL,w
; iorlw 0x80
; movwf uartsMsg
; call uartSendMsg
; movf canIDH,w
; andlw 0xF0
; iorlw 0x09
; swapf WREG
; movwf uartsMsg
; call uartSendMsg
; movf canIDH,w
; andlw 0x0F
; iorlw 0xA0
; movwf uartsMsg
; call uartSendMsg
; movf canDLC,w
; iorlw 0xC0
; movwf uartsMsg
; call uartSendMsg
; movf canDLC,w
; btfsc STATUS,Z
; goto nloadcanmsg
; movwf tempvar
; movf canMsg0,w
; andlw 0xF0
; swapf WREG
; movwf uartsMsg
; call uartSendMsg
; movf canMsg0,w
; andlw 0x0F
; movwf uartsMsg
; call uartSendMsg
; decf tempvar
; btfsc STATUS,Z
; goto nloadcanmsg
; movf canMsg1,w
; andlw 0xF0
; swapf WREG
; movwf uartsMsg
; call uartSendMsg
; movf canMsg1,w
; andlw 0x0F
; movwf uartsMsg
; call uartSendMsg
; decf tempvar
; btfsc STATUS,Z
; goto nloadcanmsg
; movf canMsg2,w
; andlw 0xF0
; swapf WREG
; movwf uartsMsg
; call uartSendMsg
; movf canMsg2,w
; andlw 0x0F
; movwf uartsMsg
; call uartSendMsg
; decf tempvar
; btfsc STATUS,Z
; goto nloadcanmsg
; movf canMsg3,w
; andlw 0xF0
; swapf WREG
; movwf uartsMsg
; call uartSendMsg
; movf canMsg3,w
; andlw 0x0F
; movwf uartsMsg
; call uartSendMsg
; decf tempvar
; btfsc STATUS,Z
; goto nloadcanmsg
; movf canMsg4,w
; andlw 0xF0
; swapf WREG
; movwf uartsMsg
; call uartSendMsg
; movf canMsg4,w
; andlw 0x0F
; movwf uartsMsg
; call uartSendMsg
; decf tempvar
; btfsc STATUS,Z
; goto nloadcanmsg
; movf canMsg5,w
; andlw 0xF0
; swapf WREG
; movwf uartsMsg
; call uartSendMsg
; movf canMsg5,w
; andlw 0x0F
; movwf uartsMsg
; call uartSendMsg
; decf tempvar
; btfsc STATUS,Z
; goto nloadcanmsg
; movf canMsg6,w
; andlw 0xF0
; swapf WREG
; movwf uartsMsg
; call uartSendMsg
; movf canMsg6,w
; andlw 0x0F
; movwf uartsMsg
; call uartSendMsg
; decf tempvar
; btfsc STATUS,Z
; goto nloadcanmsg
; movf canMsg7,w
; andlw 0xF0
; swapf WREG
; movwf uartsMsg
; call uartSendMsg
; movf canMsg7,w
; andlw 0x0F
; movwf uartsMsg
; call uartSendMsg
nloadcanmsg:
bcf PIR3,0
bra EndIsr
uartInt:
bsf LATC,4
;UART Nachricht nach CAN senden
call uartRecMsg
EndIsr:
retfie FAST

Enrock
06.05.2008, 08:01
Guten Morgen,

also es wäre noch ganz net zu wissen, um welchen PIC es sich handelt. Dann wäre es noch gut, wenn ich den kompletten Code hätte. So könnte man nachvollziehen, wo du überall hin springst.
Dann wird jedesmal wenn du eine Sprungmarke callst die Rücksprungandresse im Stack gespeichert. Der Stack ist nicht unendlich groß und irgendwann gibt es dann einen überlauf und du weiß nicht mehr was der PIC macht. Wenn du mit Call in eine Routine springst solltest du auch mit return wieder zurück gehen und dann erst mit goto in diedie nächste Routine callen. Ich weiß das ist nicht immer möglich und sinnvoll, also muss man sich mit dem Datenblatt und dem Stack beschäftigen.

Hier mal einen Auszug auf dem Datenblatt des 16F87XA

The PIC16F87XA family has an 8-level deep x 13-bit
wide hardware stack. The stack space is not part of
either program or data space and the stack pointer is not
readable or writable. The PC is PUSHed onto the stack
when a CALL instruction is executed, or an interrupt
causes a branch. The stack is POP’ed in the event of a
RETURN, RETLW or a RETFIE instruction execution.
PCLATH is not affected by a PUSH or POP operation.
The stack operates as a circular buffer. This means that
after the stack has been PUSHed eight times, the ninth
push overwrites the value that was stored from the first
push. The tenth push overwrites the second push (and
so on).

In diesem Sinne
Gruß

T.J.
06.05.2008, 09:11
Ich verwende den PIC18F2685. An den Stack habe ich auch schon gedacht, nur das Programm läuft danach weiter außer dass kein CAN Interrupt mehr kommt. Uartinterrupt funzt trotzdem noch. Die Stacktiefe ist ja wichtig wenn ich mehrere Calls hintereinander aufrufe ohne zurückzuspringen, also rekursiv. Richtig? Wenn ich also eine Funktion recht oft aufrufe sollte das im Stack nicht viel brauchen.

Gibt es eine Zeitbeschränkung für die ISR? Hier mal mein Code. Danke für die Hilfe!

PICture
06.05.2008, 10:02
Hallo T.J.!

Wenn ein Interrupt ausgelöst wird, muß ein Interrupt-Flag (IF) des Auslösers gelöscht werden, weil so lange das IF gesetzt ist, kann dieser Interrupt nicht mehr ausgelöst werden.

Allgemain sollte die ISR vor dem nächstem möglichem Interrupt schon beendet werden.

MfG

T.J.
06.05.2008, 10:16
Stimmt, danke ;)
Leider liegt es daran nicht, denn das wird am Ende des Interrupts gemacht. Es sei denn, es gibt Einen Grund dass der Prozessor diesen Befehl bei meinem Code nicht ausführt.
Aber aufgrund deines Tipps habe ich das eben mal getestet indem ich das Flag manuell per Taster löschen kann, trotzdem wird der Int nur einmal ausgeführt solange mehr als 2 funktionen aufgerufen werden (call). :(

PICture
06.05.2008, 10:39
In deiner ISR habe ich die Löschung des IFs nicht gesehen (übersehen?).

MfG

T.J.
06.05.2008, 10:42
Ganz unten, bcf PIR3,0

aber ich habs ich habs! Ich trottel hatte beim Auslesen der CAN botschaft dem CAN Modul gesagt ok, kannst neue Message empfangen. Dann jedoch habe ich ja im Interrupt erst die Nachricht zum PC gesendet bevor ich den Interrupt wieder aktivere. Das hat dem CAN Modul wohl nicht gefallen. Danke für deine Hilfe! Ich komm immer erst drauf, wenn ich n Thread aufgemacht habe :(

PICture
06.05.2008, 10:51
Ich habe dir gar nicht helfen können. Der Programmentwickler findet seine Fehler am schnellsten, braucht aber manchmal einen kleinen Anstoß. :)

Viel Erfolg weiterhin!

MfG