Hallo,
ich schreibe seit einiger Zeit an einem Programm für mein Olimex Board
LPC-L2294. Es werdem dem MC per Ethernet in Paketen CAN-Nachrichten
geschickt, diese im Speicher abgelegt und nach und nach auf den Bus
versendet. Das funktioniert sehr gut.
Außerdem sollen aber auch CAN-Nachrichten vom Bus empfangen werden. Und
hier liegt das Problem.
Beim Debuggen, habe ich festgestellt, dass bei der ersten erhaltenen
CAN-Nachricht, der Interrupt richtig angezogen und die Service-Routine
aufgerufen wird. Dann aber wird die Routine scheinbar nicht mal bis zum
Ende abgearbeitet. Stattdessen wird ein Dummy-Service-Routine
void UNDEF_Routine (void)
{
//while (1) ;
}
aufgerufen. Was danach so richtig passiert kann ich nicht
nachvollziehen. Das Programm scheint dann normal weiter zu laufen. Das
Ende der Receive-Interrupt-Service-Routine wird aber nie erreicht.
Also um das mal ein wenig zu konkretisieren:
Im StartupCode wird folgendes angegeben (Habe ich aus einem
Beispielprogramm übernommen, und bisher auch keine Probleme damit
gehabt):
_vectors: ldr PC, Reset_Addr
ldr PC, Undef_Addr
ldr PC, SWI_Addr
ldr PC, PAbt_Addr
ldr PC, DAbt_Addr
nop /* Reserved Vector (holds Philips ISP checksum) */
ldr PC, [PC,#-0xFF0] /* see page 71 of "Insiders
Guide to the Philips ARM7-Based Microcontrollers" by Trevor Martin */
ldr PC, FIQ_Addr
Reset_Addr: .word Reset_Handler /* defined in this module below
*/
Undef_Addr: .word UNDEF_Routine /* defined in main.c */
SWI_Addr: .word SWI_Routine /* defined in main.c */
PAbt_Addr: .word UNDEF_Routine /* defined in main.c */
DAbt_Addr: .word UNDEF_Routine /* defined in main.c */
/*IRQ_Addr: .word IRQ_Routine /* defined in main.c */
FIQ_Addr: .word FIQ_Routine /* defined in main.c */
.word 0 /* rounds the vectors and ISR addresses to
64 bytes total */
Da ist eben auch die oben erwähnte Dummmy-Routine mit dabei. Leider habe
ich nicht so ganz deren Sinn verstanden. Kann mir das jemand erklären?
Der Receive-Interrupt ist wie folgt konfiguriert (Bsp. Kanal 1):
void init_can1Rx_interrupt(void)
{
CAN1IER = 0x1; //Enable CAN1 Receive-interrupt
VICIntSelect &= 0xfbffffff; // CAN1 Rx IRQ
VICVectAddr4 = (unsigned int)IRQ_CAN1Rx;
VICVectCntl4 = 0x3A; // Enable vectored interrupt CAN1 Rx.
VICIntEnable = 0x4000000;
CAN1GSR = 0;
}
In der Routine selbst wird hauptsächlich die Nachricht aus dem
Receivebuffer gelesen und soll im Speicher abgelegt werden (Das wird
aber schon nicht mehr gemacht, dass Auslesen jedoch schon).
Hat jemand eine Idee wo das Problem liegen könnte? Warum springt er in
diese UNDEF-Routine?
Werden noch weitere Infos benötigt, poste ich die gerne auf Anfrage
nach.
Danke vorab für eure Hilfe!
Gruß,
Norman
Was genau macht den der IRQ-Handler?
Ich hatte den auskommentiert, da das ja auch nur eine Dummy-Routine war
(nach meinem Verständnis, und beim Vectored Interruptcontroller ja die
Adresse der entsprechenden Service-Routine angegeben wird und diese ja
dann auch angesprungen werden soll). Wozu wird diese Dummy-Routine dann
noch gebraucht? Und kann das was mit meinem Problem zu tun haben?
Welcher Code wird denn noch benötigt?
Gruß,
Norman
An diese Stelle der Sprungleiste springt die CPU wenn ein Interrupt
aufläuft. Und davon, dass du das auskommentierst, weiss sie nichts und
springt trotzdem dorthin. Und erwischt dann eben das, was nun dort
steht, also den FIQ Handler.
Es gibt von Hitex einen Wälzer über NXPs ARM7er, den man sich auch
runterladen kann (zur Strafe allerdings ohne Inhaltsverzeichnis). Könnte
sich für dich lohnen, da mal reinzusehen.
Ok danke, da kann ich ja mal reinschauen.
Aber mich wurdert trotzdem schon, dass er dann nicht in die FIQ-Routine
springt, sondern in die UNDEF-Routine. Und wieso tut er das überhaupt,
wenn er doch schon in der richtigen Routine ist?
Irgendwie werde ich das Gefühl nicht los, dass dieser Thread gleich in
eine längere Anfänger-Vorlesung in das Wesen der Interrupt-Verarbeitung
von ARM7 Prozessoren ausartet.
Norman M. wrote:
> Aber mich wurdert trotzdem schon, dass er dann nicht in die FIQ-Routine> springt, sondern in die UNDEF-Routine.
Möglicherweise macht er erst das eine, dann das andere. Nach UNDEF läuft
er hier beispielsweise, wenn er auf eine Adresse zugreift, an der sich
nichts befindet. Warum er das vielleicht tut ist deinen Schnipseln nicht
zu entnehmen.
Naja ich habe mich ja schon mit der Thematik anhand des User-Manuals
beschäftigt. Mit den Timer-Interrupt klappt ja auch alles und das sind
auch IRQs.
Nur das Problem hier verstehe ich nicht. In dem pdf lese ich gerade
mal...
Ich dache mehr an den kompletten Startup-Code.
Du solltest am Anfang eines nicht funktionierenden Handler mal eine LED
einschalten, oder sowas in der Art. Denn dass du letztlich im UNDEF
landest, heisst nicht dass du gleich dort landest. Evtl. landest du wie
schon erwähnt über Umweg dort.
Ok, danke für den Tipp, das könnte man mal ausprobieren. Leider kann ich
das erst wieder am WE richtig probieren, weil ich hier den CAN nicht
testen kann.
Der Startup-Code sieht wie folgt aus:
/*
************************************************************************
***************************************
crt.s STARTUP ASSEMBLY CODE
-----------------------
Module includes the interrupt vectors and start-up code.
************************************************************************
*************************************** */
/* Stack Sizes */
.set UND_STACK_SIZE, 0x00000004 /* stack for "undefined instruction"
interrupts is 4 bytes */
.set ABT_STACK_SIZE, 0x00000004 /* stack for "abort" interrupts is 4
bytes */
.set FIQ_STACK_SIZE, 0x00000004 /* stack for "FIQ" interrupts is 4
bytes */
.set IRQ_STACK_SIZE, 0X00000100 /* stack for "IRQ" normal interrupts
is 4 bytes */
.set SVC_STACK_SIZE, 0x00000014 /* stack for "SVC" supervisor mode
is 4 bytes */
/* Standard definitions of Mode bits and Interrupt (I & F) flags in PSRs
(program status registers) */
.set MODE_USR, 0x10 /* Normal User Mode
*/
.set MODE_FIQ, 0x11 /* FIQ Processing Fast Interrupts
Mode */
.set MODE_IRQ, 0x12 /* IRQ Processing Standard
Interrupts Mode */
.set MODE_SVC, 0x13 /* Supervisor Processing Software
Interrupts Mode */
.set MODE_ABT, 0x17 /* Abort Processing memory Faults
Mode */
.set MODE_UND, 0x1B /* Undefined Processing Undefined
Instructions Mode */
.set MODE_SYS, 0x1F /* System Running Priviledged
Operating System Tasks Mode */
.set I_BIT, 0x80 /* when I bit is set, IRQ is
disabled (program status registers) */
.set F_BIT, 0x40 /* when F bit is set, FIQ is
disabled (program status registers) */
/*Interrupt global enablen*/
/*.set I_BIT, 0x00 when I bit is set, IRQ is
disabled (program status registers) */
/*.set F_BIT, 0x00 when F bit is set, FIQ is
disabled (program status registers) */
.text
.arm
.global Reset_Handler
.global _startup
.func _startup
_startup:
# Exception Vectors
_vectors: ldr PC, Reset_Addr
ldr PC, Undef_Addr
ldr PC, SWI_Addr
ldr PC, PAbt_Addr
ldr PC, DAbt_Addr
nop /* Reserved Vector (holds Philips ISP
checksum) */
ldr PC, [PC,#-0xFF0] /* see page 71 of "Insiders
Guide to the Philips ARM7-Based Microcontrollers" by Trevor Martin */
ldr PC, FIQ_Addr
Reset_Addr: .word Reset_Handler /* defined in this module below
*/
Undef_Addr: .word UNDEF_Routine /* defined in main.c */
SWI_Addr: .word SWI_Routine /* defined in main.c */
PAbt_Addr: .word UNDEF_Routine /* defined in main.c */
DAbt_Addr: .word UNDEF_Routine /* defined in main.c */
/*IRQ_Addr: .word IRQ_Routine /* defined in main.c */
FIQ_Addr: .word FIQ_Routine /* defined in main.c */
.word 0 /* rounds the vectors and ISR
addresses to 64 bytes total */
# Reset Handler
Reset_Handler:
/* Setup a stack for each mode - note that this only sets up a
usable stack
for User mode. Also each mode is setup with interrupts
initially disabled. */
ldr r0, =_stack_end
msr CPSR_c, #MODE_UND|I_BIT|F_BIT /* Undefined Instruction
Mode */
mov sp, r0
sub r0, r0, #UND_STACK_SIZE
msr CPSR_c, #MODE_ABT|I_BIT|F_BIT /* Abort Mode */
mov sp, r0
sub r0, r0, #ABT_STACK_SIZE
msr CPSR_c, #MODE_FIQ|I_BIT|F_BIT /* FIQ Mode */
mov sp, r0
sub r0, r0, #FIQ_STACK_SIZE
msr CPSR_c, #MODE_IRQ|I_BIT|F_BIT /* IRQ Mode */
mov sp, r0
sub r0, r0, #IRQ_STACK_SIZE
msr CPSR_c, #MODE_SVC|I_BIT|F_BIT /* Supervisor Mode */
mov sp, r0
sub r0, r0, #SVC_STACK_SIZE
msr CPSR_c, #MODE_SYS|I_BIT|F_BIT /* User Mode */
mov sp, r0
/* copy .data section (Copy from ROM to RAM) */
ldr R1, =_etext
ldr R2, =_data
ldr R3, =_edata
1: cmp R2, R3
ldrlo R0, [R1], #4
strlo R0, [R2], #4
blo 1b
/* Clear .bss section (Zero init) */
mov R0, #0
ldr R1, =_bss_start
ldr R2, =_bss_end
2: cmp R1, R2
strlo R0, [R1], #4
blo 2b
/* Enter the C code */
b main
.endfunc
.end
Ok, sorry, ich hatte die Sprungleiste und die Vektorleiste verwechselt.
Die auskommentierte IRQ_routine geht hier in Ordnung, weil sowieso nicht
verwendet.
Ist dein CAN IRQ Handler eigentlich vom Funktionstyp ein IRQ Handler?
Als normale C Funktion kann das so nicht funktionieren.
Ja, ist es.
Dann ist also klassisches Debugging angesagt. Entweder mit JTAG. Oder
mit der beschriebenen LED sehen, wie weit er im Handler kommt.
Mit Debugger ist es etwas leichter. Denn idealerweise hat man als UNDEF
Handler eine Totschleife, und wenn man dort landet, dann zeigt R14 an wo
es gekracht hat.
Ich hatte schon mal so etwas ähnliches wie oben beschrieben ausprobiert.
Er kommt noch bis vor die memmoves. Aber danach kommt er nicht mehr an.
Ich hatte aber nicht zwischen den memmoves probiert.
Na also, das ist doch schon dicht dran.
Allerdings komme ich mir etwas verarscht vor. Du bist also selber schon
soweit, dass es offenbar an spezifischen Teilen der Speicherverarbeitung
deines Codes liegt. Daraufhin postest du eine Frage, die nur 2 Schnipsel
über die Interrupt-Verarbeitung im Allgemeinen enthält. Wie stellst du
dir das eigentlich vor?
Ich will hier ganz bestimmt niemanden verarschen... ;)
Das Problem ist, dass ich leider nicht über die memmoves schrittweise
debuggen kann, da er da irgendwie das memmove angeblich nicht findet.
Dieses Problem habei ich bei jedem memmove in meinem Programm.
Dadurch kann ich leider den weiteren verlauf nicht mehr nachvollziehen
und sehe halt nur, dass ich plötzlich in der UNDEF-Routine bin.
Aber die memmoves schaue ich mir auf jeden Fall nochmal genauer an. Du
hattest ja oben schonmal geschrieben, dass es sein kann, dass auf
Speicher zugegriffen wird, wo nix steht. Vielleicht habe ich da
tatsächlich noch einen Fehler drin.
Also sorry, die frage ging vielleicht etwas falsch los, ich wusste es
einfach nur nicht besser. War einfach ratlos...