Hi,
ich verwende einen LPC2468 von NXP mit arm-toolchain. Ich kann Daten
über uart0 senden und empfangen. Das Empfangen würde ich, anstatt auf
den Empfangspuffer zu pollen, gerne über einen Interrupt lösen. Leider
wird die von mir angelegte Interruptroutine einfach nicht angesprungen.
Ich habe an zahlreichen Stellen die Diskussion zu diesem Thema verfolgt
und denke dass meine VIC Initialisierung und die Aktivierung des
Interrupts im uart0 in Ordnung sein müssten.
Ich vermute dass meinem Startupcode ein "Interrupt-Handler" o.ä. fehlt.
Leider konnte ich bestehende Beispielcodes nicht in mein Projekt
einbinden ohne sehr viele neue Abhängigkeiten unaufgelöst zu lassen.
Evntl. ist auch die Syntax des Funktionsprototypen für die ISR noch
nicht ganz GNU-ARM-konform.
Ob in die ISR gesprungen wird teste ich dadurch, dass ich dann sofort
eine Nachricht über uart0 zurück schicke.
Hat jemand die selbe Konfiguration schonmal zum Laufen gebracht?
Hier die wichtigsten Initialisierungsroutinen. (Die vollständigen
Quellcode-Dateien habe ich angehängt.)
1
#define IER_RBR 0x01
2
#define IER_THRE 0x02
3
#define IER_RLS 0x04
4
5
voidInitUART0()
6
{
7
PCONP|=(1<<3);// UART0 power on
8
PINSEL0|=0x00000050;// P0.2 TXD0, P0.3 RXD0
9
U0FDR=0;// Fractional divider not used
10
U0LCR=0x83;// 8 bits, no Parity, 1 Stop bit and enable access to divisor latches
11
U0DLL=97;// 9600 Baud Rate @ 15 MHz VPB Clock
12
U0DLM=0;// High divisor latch = 0
13
U0LCR=0x03;// DLAB = 0 and enable access to U0IER
14
PCLKSEL0&=0xFFFFFF7F;// clock selection for UART0
15
U0FCR=0x07;// for UART0: RX and TX FIFO reset and FIFO enable
16
}
17
18
voidUART0ISR(void)
19
{
20
SendString("Character received!\n");
21
VICVectAddr=0;// Acknowledge Interrupt
22
}
23
24
voidInitUART0Interrupt()
25
{
26
U0IER=0x00;// disable all interrupts
27
VICIntEnClr=0xFFFFFFFF;// delete all interrupts
28
VICIntSelect|=0x00000000;// select uart0 interrupt source as IRQ (not FIQ)
29
VICVectAddr0=(unsignedlong)UART0ISR;// address of the ISR
30
VICVectCntl0|=((1<<5)|6);// VIC enable and channel 6 (weißt evntl. VICVectAdr0 den uart0-interrupt zu???)
31
VICIntEnable|=(1<<6);// select uart0 in interrupt enable clear register
Testweise die folgenden Modifikationen vornehmen:
(1) in crt0.s bei msr CPSR_c, #MODE_SYS|I_BIT|F_BIT die letzten beiden
Operatoren löschen also: CPSR_c, #MODE_SYS (Kommentar zu der Zeile ist
fehlleitend aber stört erstmal nicht)
(2) vor void UART0ISR (void) {... noch einen Prototypen mit IRQ-Attribut
also
void UART0ISR (void) _attribute_ ((interrupt("IRQ")));
(Diese Attribute sollten nach Möglichkeit ohnehin vermieden werden,
besser: Assembler-Wrapper)
(3) dem Compiler zusätzlich -mapcs-frame also Option mitgeben (CFLAGS),
falls nicht schon so
(4) in Funktion UART0ISR SendString-Zeile löschen (Katze...Schwanz...)
und stattdessen eine LED ein- oder umschalten
(5) in UART0ISR vorerst zumindest per dummy die Register U0LSR und U0RBR
auslesen (...unsigned int dummy; dummy=U0LSR; dummy=U0RBR;...) später
dann die Register "richtig" auswerten (vgl. u.a. NXP Beispiele f.
LPC23xx/24xx)
Hi Martin,
vielen Dank für deine Antwort! Ich habe in den letzten Tagen schon viel
Inspiration aus deinen Beispielen geschöpft!
Die Änderung in crt.s (nicht crt0.s) habe ich vorgenommen. Den
Prototypen
habe ich ebenfalls eingebaut, allerdings konnte ich die Änderung nur im
Prototyp vornehmen, nicht in der Signatur der eigenlichen Methode, sonst
bekomme ich ein "uart.c:54: error: expected ‘,’ or ‘;’ before ‘{’ token
make: *** [uart.o] Error 1"
Meine CFLAGS im Makefile habe ich ebenfalls erweitert:
1
CFLAGS = -I./ -c -fno-common -O0 -g -mapcs-frame
Aus UART0ISR() habe ich den SendString()-Aufruf entfernt und lasse nur
noch eine LED mittels Schleife ca. 2 sec. lang aufleuchten. Andere LEDs
schalte ich in InitUART0() und InitUART0Interrupt() an, um zu sehen ob
das Programm bis dorthin ausgeführt wird.
Auch die UART0-Register lese ich in UART0ISR() aus, wie von dir
beschrieben.
Leider leuchtet meine ISR-LED noch nicht, wenn ich zum Test Zeichen auf
meinem PC in gtkterm eintippe. Die Zeichen müssten aber gesendet werden,
da ich über die selbe Art und Weise auch ein uCLinux fernsteuern kann.
Als Entwicklungsumgebung verwende ich Eclipse.
Habe ich vielleicht doch einen Wert bei der Initialisierung falsch oder
garnicht gesetzt? Fehlt mir noch irgend etwas in meinem Startupcode?
Viele Grüße,
tm
afaik möchte ARM-GCC sowas als Prototyp lesen:
void isr_UART0 ( void ) _IRQ_;
Was mir in deiner ISR noch fehlt, ist ein Löschen der noch nicht
erledigten UART-Interrupts.
Das eigentliche Problem ist aber, dass du den WDT-Interrupt auf UART0ISR
lenkst. UART0 ist VICVectAdr6.
Hi,
ich habe den Prototyp einfach mal so wie von dir gezeigt in die
Headerdatei eingebaut. Scheint er aber nicht zu mögen.
Das mit dem Zuweißen der Interruptadressen ist mir eh noch nicht ganz
klar. Das Manual ist hier nicht sehr ausführlich, leider habe ich bisher
noch nie mit dem VIC gearbeitet.
Besonders das Wirken der Register VICVectAddr6, VICVectCntrl6 und
VICVectPriority6 ist mir noch nicht ganz klar.
Besonders weil man in der lpc2468_registers.h folgende Kommentarzeile
findet:
1
//The name convention below is from previous LPC2000 family MCUs, in LPC230x, these registers are known as "VICVectPriority(x)".
2
#define VICVectCntl0 (*(volatile unsigned long *)(VIC_BASE_ADDR + 0x200))
3
#define VICVectCntl1 (*(volatile unsigned long *)(VIC_BASE_ADDR + 0x204))
4
#define VICVectCntl2 (*(volatile unsigned long *)(VIC_BASE_ADDR + 0x208))
5
#define VICVectCntl3 (*(volatile unsigned long *)(VIC_BASE_ADDR + 0x20C))
6
#define VICVectCntl4 (*(volatile unsigned long *)(VIC_BASE_ADDR + 0x210))
7
#define VICVectCntl5 (*(volatile unsigned long *)(VIC_BASE_ADDR + 0x214))
8
#define VICVectCntl6 (*(volatile unsigned long *)(VIC_BASE_ADDR + 0x218))
9
...
Und das obwohl es in der selben Datei auch einen Block mit VICVectCntl
gibt. Ich glaube aber beide zeigen auf die exakt gleichen Adressen,
richtig? Das finde ich aber verwirrend weil im Handbuch zum LPC24xx
steht:
"VICVectPriority0: Vector priority 0 register. Vector Priority Registers
0-31. Each of these registers designates the priority of the
corresponding
vectored IRQ slot."
Die VICVectCntl Register sind dagegen garnicht dokumentiert. Das sagt
mir dass die mal umbenannt wurden. Ich verstehe nur den neuen Namen
"VICVectPriority" nicht so ganz, da es ja eigentlich um die Adressen der
ISR-Routinen geht und nicht um deren Priorität.
Hallo,
deine VICVectCntl-Makros zeigen auf die Priority-Register, richtig.
VICVectPriority sagt nur, welcher Interrupt zuerst abgearbeitet wird,
wenn mehrere gleichzeitig auftauchen. Das brauchst du übrigens nur für
IRQ, nicht bei FIQ
.
AFAIK müssen alle Interrupts, die du aktivierst, auch priorisiert
werden.
Die Priority-Register fangen bei FF FF F2 00 an, die Adress-Register bei
FF FF F1 00.
Aber wie gesagt, das eigentliche Problem ist das hier:
1
VICVectAddr0=(unsignedlong)UART0ISR;// address of the ISR
Da müsste stehen
1
VICVectAddr6=(unsignedlong)UART0ISR;// address of the ISR
Zusatz:
>Besonders das Wirken der Register VICVectAddr6, VICVectCntrl6 und>VICVectPriority6 ist mir noch nicht ganz klar.
VICVectAddr sind die Register, die die Adresse der ISR enthalten. Löst
Timer0 einen Interrupt aus, dann springt der PC an die Stelle, die in
VICVectAddr4 steht.
VICVectPriority sagt etwas über die Reihenfolge der Abarbeitung.
Wenn WDT und Timer0 gleichzeitig kommen, dann wird der Interrupt zuerst
ausgeführt, der die höhere Priorität besitzt.
Beispiel: VICVectPriority0 = 31 (WDT), VICVectPriority4 = 12 (Timer0)
WDT ist höher priorisiert und wird zuerst ausgeführt.
Deine VICVectCntl-Makros sind gleichbedeutend mit den
VICVectPriority-Registern.
Hallo tm,
ich habe hier gespannt mitgelesen, da ich mich in Kürze auch mit diesem
Prozessor befassen möchte.
Wärst Du so nett und hängst hier ein Minimalprojekt für die
arm-toolchain mit ISR-Beispiel hier rein?
So mit startup etc...
Wäre Super!
Klar, kann ich machen. Ich bin gerade dabei das Projekt etwas
aufzuräumen und sauber zu implementieren. Im moment geht es zwar, ist
aber ziemlich wild. Sobald ich fertig bin werde ich ein komplettes
Beispielprojekt für meine Konfiguration veröffentlichen.
Vielleicht kann mir unter dessen jemand weiterhelfen was das Konstrukt
"1UL" bzw. "3UL" genau bedeutet, was es macht oder woher es kommt. Habe
keine Informationen dazu gefunden. Ich denke es muss irgendwie zum
C-Sprachumfang gehören... 1UL scheint ein Bitmuster der Form "...0001"
zu erzeugen und 3UL ein Bitmuster der Form "...0011". Wer weiß wo ich
dazu mehr Informationen bekomme?
Dieser Ausdruck wird nämlich sehr geschickt in einem Codeschnipsel von
Martin Thomas benutzt:
Ich habs raus: 1UL bedeutet einfach nur die Konstante 1 als unsigned
long (32 Bit), das entspricht dem Bitmuster ...0001
3UL bedeutet die Konstante 3 als unsigned long, das entspricht dem
Bitmuster ...0011
:-)
Sicherlich etwas länger, aber dafür übersichtlich.
@guest: Schau dir mal Starteasy for ARM an. Damit kann man für die
LPC-Reihe ein fertiges Musterprojekt erstellen, die meisten Interrupts
vorkonfigurieren und der Startup-Code wird auch gleich erstellt. Das
wird dann zwar als HiTOP-Projekt erstellt, aber es zählt ja sowieso nur
der Code.
Da stellt sich mir wieder gleich die Frage wo uint32_t definiert wird.
:-D Habe es schon mehrfach in Beispielprojekten gesehen konnte es aber
nie bis zu seiner Deklaration zurückverfolgen. Zu C gehört es jedenfalls
nicht, glaube ich. In meinen Projekten steht mir dieser Typ nicht zur
Verfügung.
Frank Bär schrieb:> Sicherlich etwas länger, aber dafür übersichtlich.
Welche Vorteil hat in diesem Zusammenhang die vielfache Verwendung von
uint32_t? Und warum ist hier Hex einfacher als Dezimal?
Leider habe ich mich zu früh gefreut. Meine LED blinkt zwar bei jedem
Zeichen das ich sende aber bei genauerem hinsehen habe ich festgestellt,
dass er niemals in die ISR springt, sondern komischerweise in die
InitUART0ISR!! Und nein ich habe nicht die falsche Adresse in
VICVectAdr6 geschrieben. Noch verworrener wird das ganze, wenn ich
zwecks Debugausgabe in den einzelnen Methoden ein bisschen herumspiele.
Dann macht er nach jedem empfangenen Zeichen sogar einen kompletten
Reset!
Weiß leider überhaupt nichtmehr weiter. Ich denke mir, dass ich
vielleicht doch so einen Interrupt-Wrapper brauche...? Kann es sein,
dass das Blinking-LED-Projekt von Olimex garnicht für Interrupts
ausgelegt ist und mir da noch etwas fehlt? Vor allem was das Anspringen
des richtigen Vectors angeht?
Frank Bär schrieb:> @guest: Schau dir mal Starteasy for ARM an...
Danke für den Tipp! Sieht auf den ersten Blick aus, als sei es genau das
was ich suchte.
Wird das Tool noch gepflegt? LPC17xx vermisse ich...
A. K. schrieb:> Frank Bär schrieb:>>> Sicherlich etwas länger, aber dafür übersichtlich.>> Welche Vorteil hat in diesem Zusammenhang die vielfache Verwendung von> uint32_t? Und warum ist hier Hex einfacher als Dezimal?
Weil die Bitdarstellung von 0x23 eindeutig ist, bei 35 dagegen nicht.
Mag Geschmackssache sein. Ich arbeite lieber durchweg mit Hex-Werten,
weil das auch die Darstellung ist, die sich im Debug-Modus in den
Registern wiederfindet. Die vielfache Verwendung des typecasts, weil der
ARM-GCC meiner Erfahrung nach ziemlich zickig sein kann und teilweise
völlig unklar kompiliert.
@tm: Schau mal, ob der Compiler die richtigen Sprungadressen in
VICVectAddr6 hinterlegt, eventuell hilft es, die Code-Optimierungsstufe
mal zu ändern. Der ARM-GCC hat sich da teilweise ziemlich zickig, wie
ich feststellen durfte. Manche Fehler sind in der Übersetzung begründet,
warum sie auftreten, ist mir nach langem rumprobieren immernoch so
unklar, wie am Anfang.
@Guest: Starteasy wird, soweit ich das beurteilen kann, noch gepflegt,
ja. Mit ARM-Cortex habe ich in der Toolchain noch nicht gearbeitet,
daher kann ich dir dazu wenig sagen, möglicherweise hilft es, mal den
Support von Hitex anzuschreiben.
So jetzt gehts zuverlässig! Es lassen sich allerdings bisher immer nur
acht Zeichen (exakt die Größe meines FIFO-Buffers) lesen bevor kein
Interrupt mehr ausgelöst wird. Weiß jemand einen Rat?