Hallo Ich versuche einen ADUC7000 (ARM7) zu programmieren. Im Moment hänge ich an den Uart-Funktionen. Ich habe ein FIFO im SRam zum Senden und Empfangen angelegt. Wenn Daten gesendet werden sollen, landen diese im FIFO. So bald das Uart Senderegister leer ist, wird ein IRQ ausgelöst. In der IRQ-Funktion wird ein Byte aus dem FIFO ins Senderegister kopiert. Wenn Daten in das FIFO schneller geschrieben werden, als die Daten über die IRQ-Funktion gesendet werden können, wird eine Statusvariable auf 2 gesetzt, damit im Programm erkannt werden kann, dass gewartet werden muss, bis wieder Platz im Puffer ist. Das funktioniert fast. Dies ist meine Sendefunktion: char UartWrite (char *ptr, char wait) { // Sende String ueber uart, Wenn wait==1, wird gewartet, bis der String vollstaendig // gesendet werden konnte. Soll nicht ewartet werden und der TX-Puffer laeuft ueber, wird die Position des Zeichen im // String zurueckgegeben, die nicht mehr gesendet werden konnte char *origptr = ptr; char CharSent; while (*ptr!='\0') { CharSent = UartPutChar (*ptr); // Uebergebe einzelnes Zeichen an Sendefunktion ptr++; if (CharSent==0) { // Puffer ist voll. Warte oder gebe Position des letzten gesendeten Zeichen zurueck if (wait){ while (uarttxbufferstatus==2) { int bla1 = 7; int bla2 = 80; } // Warte bis Platz in TX-Puffer ist } else return *ptr; // Gebe Position des noch zu sendenden Zeichen aus } } return *origptr; // Gebe Pointer auf String zurueck, wenn alles gesendet wurde. } Was ich nicht ganz verstehe ist, dass der Code so funktioniert. Ich musste in die inntere while-Schleife Variablen definieren. Eigentlich hätte folgender Code gereicht: while (uarttxbufferstatus==2) { } // Warte bis Platz in TX-Puffer ist Das Problem ist, dass dann der IRQ nicht mehr ausgelöst wird. Hat einer von euch eine Idee wieso? Beim Empfangen von Zeichen habe ich ebenfalls IRQ-Probleme. So bald Daten im Empfangsregister liegen, wird ein IRQ ausgelöst. Die Daten werden dann in einen FIFO kopiert. Einzelne Zeichen werden mit der Funktion UartRXGet() empfangen: char UartGetChar(void) { // Lese Zeichen aus Empfangspuffer char RETURN = 0; if (uartrxbufferstatus!=0) { // Zeichen in Empfangsringspeicher RETURN = uartrxbuffer[readuartrxbuffer]; readuartrxbuffer++; // Aendere Position im Empfangsringspeicher readuartrxbuffer %= sizeof(uartrxbuffer); if (uartrxbufferstatus==2) uartrxbufferstatus = 1; if (writeuarttxbuffer == readuarttxbuffer) { // Empfangspuffer ist nun leer, setzte auf 0 zurueck uartrxbufferstatus = 0; } } return RETURN; // Gebe 0 zurueck, wenn kein Zeichen empfangen wurde } char UartRXGet(void) { // Warte bis Zeichen empfangen wurde und gebe dieses aus char ReturnChar = 0; while (!ReturnChar) { ReturnChar = UartGetChar(); UartIrq(); // Warum muss hier diese Funktion aufgerufen werden? } return ReturnChar; } Hier habe ich ein ähnliches Problem. Der IRQ wird nicht immer ausgelöst. Mein Programm hängt ewig in der while-Schleife fest. Desshalb habe ich in die while-Schleife meine IRQ-Funktion für den Uart eingefügt. So funktioniert der Code dann, aber ich weiß nicht wieso. Dies ist meine IRQ-Funktion: void UartIrq (void) { if (COMSTA0 & 0x01) { // Zeichen in RX Puffer if (uartrxbufferstatus!=2) { // Es ist noch Platz im Puffer uartrxbuffer[writeuartrxbuffer] = COMRX; writeuartrxbuffer++; // Aendere Position im Empfangsringspeicher writeuartrxbuffer %= sizeof(uartrxbuffer);; if (writeuartrxbuffer == readuartrxbuffer) { // Sendepuffer ist nun voll -> Gebe als Fehler 0 zurueck uartrxbufferstatus=2; // Puffer ist voll } else uartrxbufferstatus = 1; // Im Puffer liegen nun Daten } else { // Ueberschreibe aeltesten Wert in Puffer, damit das aelteste Zeichen verloren geht uartrxbuffer[writeuartrxbuffer] = COMRX; writeuartrxbuffer++; // Aendere Position im Empfangsringspeicher writeuartrxbuffer %= sizeof(uartrxbuffer);; readuartrxbuffer++; // Aendere Position im Empfangsringspeicher. Leseposition muss ebenfalls geaendert werden readuartrxbuffer %= sizeof(uartrxbuffer);; } } if (COMSTA0 & 0x40) { // TX Puffer leer. if (uarttxbufferstatus!=0) { // Zeichen in Senderingspeicher COMTX = uarttxbuffer[readuarttxbuffer]; // Sende Zeichen readuarttxbuffer++; // Aendere Position im Senderingspeicher readuarttxbuffer %= sizeof(uarttxbuffer); if (readuarttxbuffer==writeuarttxbuffer) { // Puffer ist nun leer COMIEN0 = 0x01; // Schalte TX-IRQ ab, Senderingspeicher leer. uarttxbufferstatus = 0; // Setzte Status = 0, also keine Daten mehr in Puffer } else uarttxbufferstatus = 1; // Puffer kann nicht mehr voll sein, da ein Element gesendet wurde } if (uarttxbufferstatus==0) { // Keine Zeichen in Puffer, Schalte IRQ ab. COMIEN0 = 0x01; } } } void IRQ_Function (void) { if (IRQSIG & UART_BIT) { // Uart UartIrq(); // Zeichen wurde empfangen } } Ich habe versucht herauszufinden, warum der IRQ nicht ausgelöst wird. Für den Uart gibt es die Statusregister COMSTA0 und COMIEN0. In COMIEN0 wird eingestellt, ob ein volles RX oder ein leeres TX Register einen IRQ auslöst. Mit COMSTA0 kann abgefragt werden, ob RX voll oder TX leer ist. Ich habe in Eclipse das Programm an den entsprechenden Stellen angehalten und die Register COMSTA0 und COMIEN0 angeschaut. Laut diesen Registern müsste ein IRQ ausgelöst werden. Ich kenne mich mit der Materie noch nicht so gut aus. Hat einer von euch einen Tip für mich, wie ich weitermachen könnte? Ich habe mir überlegt die Register abzufragen, in denen gespeichert wird, ob sich die CPU gerade im Interrupt Mode befindet. DAs könnte ein Grund sein, warum kein IRQ mehr ausgelöst wird. Ich habe nur leider keine Ahnung, wie man so etwas machen könnte. Bis dann, Tilo
Spurious and Surprise Interrupts berücksichtigt? http://water.cse.unsw.edu.au/esdk/lpc2/spurious-irq.html
Neine habe ich nicht. Ich wusste nicht einmal, dass es so etwas gibt. Ich habe den Text durchgelesen aber noch nicht verstanden, worum es genau geht. Da werde ich mich noch ein wenig reinhängen müssen.
Ich bins nochmal. Also ich habe versucht den Text zu verstehen. Der ARM7 hat eine Piepline, die abgearbeitet wird. Erst wenn die Pipeline abgearbeitet ist, wird er IRQ ausgeführt. Wenn nun einer der Befehle in der Pipeline den IRQ abschaltet, wird er trotzdem ausgeführt? Jedenfalls habe ich den Text so verstanden, dass genau dies ein "surprise interrupt" ist. Müsste in diesem Fall die IRQ-Funktion zu oft aufgerufen werden? spurious interrupts: Zitat aus deinem Link: "On page 2-2 it states VIC does not handle interrupt sources with transient behaviour. An interrupt exhibits transient behaviour if it is asserted and then deasserted before the software can clear the interrupt source." Das ganze verstehe ich auf deutsch so, dass ein IRQ nicht abgearbeitet wird, wenn der IRQ gesetzt und gelöscht wurde, bevor die IRQ-Quelle zurückgesetzt werden konnte. Was bedeutet das in meinem Fall? Ich habe eine Vermutung: So bald keine Daten mehr im FIFO liegen, soll der TX-Empty IRQ abgeschaltet werden. Der RX-Full IRQ soll aber an bleiben. Hierfür setzte ich das entsprechende Register COMIEN0 in der IRQ-Funktion auf 0x01. Nun vergeht zwischen "Schiebe letzte Daten in TX-Senderegister" und deaktiviere TX-Empty IRQ ein wenig Zeit. Während dieser Zeit kann es sein, dass das TX-Senderegister wieder leer ist und das entsprechende Bit in COMSTA0 gesetzt ist, also bereits in der IRQ-Funktion der nächste IRQ ausgelöst wird. Setze ich nun COMIEN0=0x1, würde dies einen "spurious interrupt" auslösen. Da der Uart nur eine Interruptquelle darstellt, egal was am Uart den IRQ ausgelöst hat, reagiert der Interruptcontroller gar nicht mehr auf den Uart. Was haltet ihr von der Vermutung? Vielen Dank, Tilo
Das Thema Spurious Interrupts ist in diesem Kontext schnell abgehandelt, denn m.W. hat der ADUC7000 keinen Interrupt-Controller an Bord. Und ohne den gibt es die nicht, jedenfalls nicht in der beschriebenen Form. Suprise Interrupts wirken sich unangenehm auf FIRQs aus. Wenn man die nicht benutzt, kann man auch dieses Thema vorerst auf Halde legen. Quelltexte bindet man besser mit den vorgesehene Tags ein, dann bleiben sie einigermassen lesbar.
Danke Andreas. Ich wollte den Quelltext mit
1 | und |
einbinden, so wie fast überall. Sind die Tags hier anders? Irgend welche anderen Ideen?
Sperr die Augen auf und lies nach. Es steht direkt auf dieser Seite drauf.
Arg, Sorry. Ich brauche dringend eine neue Brille. Ich hab überall nachgesehen nur nicht dort, wo es offensichtlich ist. Ich denke gerade viel zu kompliziert. Also nochmal den entsprechenden Code unten angehängt. Den ersten Beitrag kann ich leider nicht mehr editieren.
1 | char UartPutChar (char ch) { |
2 | char RETURN; |
3 | if (uarttxbufferstatus!=2) { // Puffer ist nicht voll |
4 | uarttxbuffer[writeuarttxbuffer] = ch; // Schreibe Zeichen in Sendepuffer |
5 | writeuarttxbuffer++; |
6 | writeuarttxbuffer %= sizeof(uarttxbuffer); |
7 | uarttxbufferstatus = 1; |
8 | if (writeuarttxbuffer == readuarttxbuffer) { // Sendepuffer ist nun voll -> Gebe als Fehler 0 zurueck |
9 | uarttxbufferstatus=2; |
10 | RETURN = 0; // Puffer voll |
11 | }
|
12 | else RETURN = 1; // Alles OK |
13 | }
|
14 | else RETURN = 0; // Puffer voll |
15 | COMIEN0 = 0x03; // Aktiviere TX-Interrupt |
16 | return RETURN; |
17 | }
|
18 | |
19 | char UartGetChar(void) { // Lese Zeichen aus Empfangspuffer |
20 | char RETURN = 0; |
21 | if (uartrxbufferstatus!=0) { // Zeichen in Empfangsringspeicher |
22 | RETURN = uartrxbuffer[readuartrxbuffer]; |
23 | readuartrxbuffer++; // Aendere Position im Empfangsringspeicher |
24 | readuartrxbuffer %= sizeof(uartrxbuffer); |
25 | if (uartrxbufferstatus==2) uartrxbufferstatus = 1; |
26 | if (writeuarttxbuffer == readuarttxbuffer) { // Empfangspuffer ist nun leer, setzte auf 0 zurueck |
27 | uartrxbufferstatus = 0; |
28 | }
|
29 | }
|
30 | return RETURN; // Gebe 0 zurueck, wenn kein Zeichen empfangen wurde |
31 | }
|
32 | |
33 | char UartRXGet(void) { // Warte bis Zeichen empfangen wurde und gebe dieses aus |
34 | char ReturnChar = 0; |
35 | while (!ReturnChar) { |
36 | ReturnChar = UartGetChar(); |
37 | UartIrq(); // Warum muss hier diese Funktion aufgerufen werden? |
38 | }
|
39 | return ReturnChar; |
40 | }
|
41 | |
42 | void UartIrq (void) { |
43 | if (COMSTA0 & 0x01) { // Zeichen in RX Puffer |
44 | if (uartrxbufferstatus!=2) { // Es ist noch Platz im Puffer |
45 | uartrxbuffer[writeuartrxbuffer] = COMRX; |
46 | writeuartrxbuffer++; // Aendere Position im Empfangsringspeicher |
47 | writeuartrxbuffer %= sizeof(uartrxbuffer);; |
48 | if (writeuartrxbuffer == readuartrxbuffer) { // Sendepuffer ist nun voll -> Gebe als Fehler 0 zurueck |
49 | uartrxbufferstatus=2; // Puffer ist voll |
50 | }
|
51 | else
|
52 | uartrxbufferstatus = 1; // Im Puffer liegen nun Daten |
53 | }
|
54 | else { // Ueberschreibe aeltesten Wert in Puffer, damit das aelteste Zeichen verloren geht |
55 | uartrxbuffer[writeuartrxbuffer] = COMRX; |
56 | writeuartrxbuffer++; // Aendere Position im Empfangsringspeicher |
57 | writeuartrxbuffer %= sizeof(uartrxbuffer);; |
58 | readuartrxbuffer++; // Aendere Position im Empfangsringspeicher. Leseposition muss ebenfalls geaendert werden |
59 | readuartrxbuffer %= sizeof(uartrxbuffer);; |
60 | }
|
61 | }
|
62 | if (COMSTA0 & 0x40) { // TX Puffer leer. |
63 | if (uarttxbufferstatus!=0) { // Zeichen in Senderingspeicher |
64 | COMTX = uarttxbuffer[readuarttxbuffer]; // Sende Zeichen |
65 | readuarttxbuffer++; // Aendere Position im Senderingspeicher |
66 | readuarttxbuffer %= sizeof(uarttxbuffer); |
67 | if (readuarttxbuffer==writeuarttxbuffer) { // Puffer ist nun leer |
68 | COMIEN0 = 0x01; // Schalte TX-IRQ ab, Senderingspeicher leer. |
69 | uarttxbufferstatus = 0; // Setzte Status = 0, also keine Daten mehr in Puffer |
70 | }
|
71 | else
|
72 | uarttxbufferstatus = 1; // Puffer kann nicht mehr voll sein, da ein Element gesendet wurde |
73 | }
|
74 | if (uarttxbufferstatus==0) { // Keine Zeichen in Puffer, Schalte IRQ ab. |
75 | COMIEN0 = 0x01; |
76 | }
|
77 | }
|
78 | |
79 | }
|
80 | |
81 | char UartWrite (char *ptr, char wait) { // Sende String ueber uart, Wenn wait==1, wird gewartet, bis der String vollstaendig |
82 | // gesendet werden konnte. Soll nicht ewartet werden und der TX-Puffer laeuft ueber, wird die Position des Zeichen im
|
83 | // String zurueckgegeben, die nicht mehr gesendet werden konnte
|
84 | char *origptr = ptr; |
85 | char CharSent; |
86 | while (*ptr!='\0') { |
87 | CharSent = UartPutChar (*ptr); // Uebergebe einzelnes Zeichen an Sendefunktion |
88 | ptr++; |
89 | if (CharSent==0) { // Puffer ist voll. Warte oder gebe Position des letzten gesendeten Zeichen zurueck |
90 | if (wait){ |
91 | while (uarttxbufferstatus==2) { |
92 | int bla1 = 7; |
93 | int bla2 = 80; |
94 | } // Warte bis Platz in TX-Puffer ist |
95 | }
|
96 | else
|
97 | return *ptr; // Gebe Position des noch zu sendenden Zeichen aus |
98 | }
|
99 | }
|
100 | return *origptr; // Gebe Pointer auf String zurueck, wenn alles gesendet wurde. |
101 | }
|
Wie bereits oben geschrieben mein Code hängt an 2 Stellen. 1. Wenn in UartRXGet() UartIrq() auskommentiert ist 2. Wenn in UartWrite() die innere while-Schleife leer ist.
@ Tilo Lutz (katagia) >Arg, Sorry. Ich brauche dringend eine neue Brille. Ich hab überall >nachgesehen nur nicht dort, wo es offensichtlich ist. Un doch nur die Hälfte gelesen :-( Solche langen Quelltexte gehören in den Anhang! Als *.c Dateien. Könnte kaum einfacher sein. MFG Falk
Naja, das hängt davon ab, was man unter lang versteht. Ich fand den noch recht kurz.
Du solltest dir mal in den Get/Put Routinen Zeile für Zeile überlegen, was passiert, wenn exakt in/nach dieser Zeile ein UART-Interrupt erfolgt. Dann wirst du vielleicht darauf kommen, dass es fatal ist, wenn direkt nach dem Test der Statusvariablen aber vor dem übrigen Code der Interrupt erfolgt und sich der Status ändert. Fachwort dafür: "race condition". Einfachste Abhilfe: Um den entsprechenden Code in den Get/Put-Routinen herum den jeweiligen UART-Interrupt zeitweilig abschalten.
Danke für den Hinweis. Ich habe den Code angepasst. Leider funktioniert es immer noch nicht. Beim Empfangen von Daten hängt das Programm immer noch in UartRXGet(). In der Funktion werden folgende Register in lokalen Variablen gesichert: int bla1 = COMIEN0; int bla2 = COMSTA0; int bla3 = IRQEN; int bla4 = IRQSIG; Wenn das Programm "hängt" halt es über JTAG in Eclipse an und debugge schrittweise. In COMATA0 ist der Urart IRQ aktiviert, wenn RX-Register voll oder TX-Register leer ist. Laut den Variablen ist IQRSIG gesetzt und ein IRQ sollte ausgelöst werden. Es sollte also zumindest die IRQ-Routine ausgeführt werden. Wenn ein Haltepunkt in der IRQ-Routine gesetzt wird, wird dieser nie erreicht. Woran kann das liegen? Wo kann ich weitere Informationen zu diesem Thema finden? Bei Analog selbst scheint es da nicht viel zu geben. Bei ARM bin ich gerade am suchen, habe aber bisher noch nichts gefunden. Ich habe das Projekt vollständig angehängt.
Ich habe das Problem gefunden! Im Programm aktiviere ich bei Bedarf den IRQ für das RX-Register. Wenn dieses voll ist, wird ein IRQ ausgelöst. Ist das Register schon voll und ich aktiviere den IRQ, wird dieser nicht ausgelöst. Die Lösung war, nach dem aktivieren des IRQ die IRQ Funktion 1x auszuführen.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.