Hallo!
Problem: an die UARTs gesendete Zeichen werden verschluckt
Aufbau: ATmega2560, UART1: GPS-Empfänger, UART2: ich (Hyperterminal),
jeweils interruptgesteuert, ISR saukurz
Symptom: ATmega antwortet fleissig auf meine Eingabe übers Terminal.
Wenn jedoch der GPS-Empfänger seine sekündlichen Quark abgibt, werden
Zeichen, die ich ("gleichzeitig") per HT gesendet habe, teilweise
verschluckt (kommen jedenfalls nicht im ATmega an).
Vermutung: zwei Interrupts kollidieren, einer davon wird "wegignoriert"
Frage: wie elegant lösen?
Gruß: Simon
chick schrieb:> Wie kommst Du auf diese Vermutung? Und wie soll das denn gehen?
Stelle mir vor, dass, während die eine ISR gerade ihren Dienst
aufgenommen hat, die andere dazwischenfunkt und die erstere abbrechen
muss.
Wie das dann gehen soll: gar nicht. Merk ich ja bei mir. :)
Dünne gerade meine ISR aus....
Ausdünnen ist der ganz falsche Ansatz. Luafzeiten bleiben immer, wenn
auch sehr kurz.
Infomier Dich lieber was der Prozessor wirklich macht, wenn zwei
Interrupts auftauchen. Vermuten hat in der E-Technik nix verloren, es
gibt Datenblätter, Tutorials, Applikationen. Da wird doch wohl was zu
finden sein.
Würd Dich gern beraten, kann mich aber nur bei den PICs aus.
Simon schrieb:> chick schrieb:>> Wie kommst Du auf diese Vermutung? Und wie soll das denn gehen?>> Stelle mir vor, dass, während die eine ISR gerade ihren Dienst> aufgenommen hat, die andere dazwischenfunkt und die erstere abbrechen> muss.
Nicht beim AVR in einer ISR Standardkonfiguration.
Das Auftreten des zweiten Interrupt-Auslösers wird registriert und die
ISR wird angestossen, wenn die erste fertig abgearbeitet wurde.
In einer UART dauert das Übertragen eines Zeichens wesentlich länger als
das Abarbeiten der zugehörigen ISR (normalerweise. Wenn man sich an die
Regel hält: nur das in einer ISR machen, was unbedingt notwendig ist -
nicht mehr), so dasss das überhaupt kein Problem sein dürfte.
Und wie sieht das beim Senden aus?
Wenn der Controller ans Terminal Daten (Kursorpositionierungs- und
Anzeigestrings) schickt und dabei das GPS seinen Senf abgibt, kommt es
vor, dass Zeichen auf dem Terminal dargestellt werden, die eigentlich
als Steuerzeichen verstanden und nicht angezeigt werden sollen.
Nimmt die ISR des Empfangens auch Rücksicht und wartet, dass das Senden
eines Zeichend abgeschlossen ist?
Simon schrieb:> Und wie sieht das beim Senden aus?
JEDE ISR wird komplett abgeschlossen, ehe die nächste arbeiten kann.
Egal ob Timer, ADC, UART, Pinchange, externer Interrupt, etc. etc.
Wenn eine ISR aufgerufen wird, werden die Interrupts global gesperrt und
mit dem Ende einer ISR werden sie wieder freigegeben.
(Es sei denn du pfuscht da rein und machst in der ISR selber einen
sei(), was in den meisten Fällen eine ganz schlechte Idee ist)
@ Simon (Gast)
>Vermutung: zwei Interrupts kollidieren, einer davon wird "wegignoriert"
Eher nicht, ich tippe auf schlechte, blockierende Programmierung,
vielleicht sogar mit Delays, bähh.
>Frage: wie elegant lösen?
Siehe Interrupt und Multitasking.
MfG
Falk
Falk Brunner schrieb:> @ Simon (Gast)>>>Vermutung: zwei Interrupts kollidieren, einer davon wird "wegignoriert">> Eher nicht, ich tippe auf schlechte, blockierende Programmierung,> vielleicht sogar mit Delays, bähh.
Das denke ich auch.
Alleine der Terminus
> Dünne gerade meine ISR aus....
In einer UART ISR gibt es normalerweise nicht viel zum ausdünnen:
Zeichen aus UDR holen und ab damit in den Ringbuffer.
Eventuell noch ein Flag setzen, dass ein \r oder \n reinkam, dann
braucht die Hauptschleife sich nicht dauernd das letzte empfangene
Zeichen ansehen.
Aber summa summarum nichts was wesentich länger als 40 oder 50 CPU Takte
dauert und damit für die restliche Funktion der UART ziemlich
uninteressant.
Hi!
Falls du ein Oszi hast: Beim Eintritt in die ISR einen unbenutzten Pin
auf HIGH setzen und beim Verlassen der ISR auf LOW. Idealerweise für
jede ISR einen eigenen Pin. Oszilloskope mit 16 Digitalkanäle sind echt
eine tolle Erfindung!
Gruß
PP
Wie groß ist dein Empfangs-Buffer für den GPS-UART und wie viele Zeichen
sendet der GPS-Empfänger maximal?
Wenn der Buffer zu klein ist wird der AVR im Normalfall aktiv warten und
so werden auch nicht die Bytes von zweiten UART abgeholt.
Diesmal ist mein Kopf am Glühen, ich suche einen Denkfehler:
Ich verwende die o.g. ISR und in der main folgende Schleife:
while(1)
{
send_GSM ("at"); //sende an GSM-Modul "at" (gefolgt von <CR>)
if(uart1_str_complete == 1) //wenn die ISR einen vollständigen String
hat
{
uart2_puts (uart1_string); //ans Terminal senden
uart1_str_complete = 0; //und von vorn
}
Das Modul antwortet auch artig mit "at<CR><CR><LF>OK<CR><LF>".
Mein Programm "sieht darin aber nur den String "at" und nicht das (viel
wichtigere) "OK".
Sieht jemand meinen Fehler?
Simon schrieb:> Sieht jemand meinen Fehler?
Du sendest zuerst und stellst dann erst uart1_str_complete auf 0. Das
hat zur Konsequenz, daß deine ISR alle während dieses Sendevorgangs
ankommenden Zeichen ignoriert, da sie nichts tut, wenn
usart1_str_complete 0 ist.
Simon schrieb:> Sieht jemand meinen Fehler?
Ja.
Mal dir auf, was da wann in welcher Reihenfolge passiert, dann kommst du
auch dahinter. Das ist mal eine gute Übung zum Thema "zwei Sachen
gleichzeitig durchführen".
Oliver
Du hast es dir nicht aufgemalt. Das war nur der eine Fehler, den zweiten
musst du noch suchen.
Man sollte auch kopierte Sourcen verstehen, bevor man sie verwendet,
selbst (oder gerade) wenn sie aus Tutorials stammen.
Oliver
Lautmalerei der ISR:
Zeichen reingeholt.
Wenn
noch Platz,
und kein LF
und kein CR
und mehr als ein Zeichen Platz
denn Zeichen anfügen
und hochzählen.
Ansonsten
letztes Zeichen NUL
und String fertig melden
und Zähler zurücksetzen.
Malung der Schleife:
Wenn
ein String vollständig, dann
Zähler nullen
String senden
von vorn.
Falsch verstanden?
Mals dir richtig auf. Du hast 2 Uarts, auf denen gleichzeitig etwas
passiert. Und gleichzeitig heisst wirklich gleichzeitig. Du hast aber
ein Programm, welches nur eine Sache gleichzeitig machen kann.
Überleg dir, was mit UDR, nextchar, und vor allem in uart1_string
passiert.
Oliver
Oliver schrieb:> Das ist mal eine gute Übung zum Thema "zwei Sachen> gleichzeitig durchführen".
Wo (zum Teufel, Entschuldigung) werden in diesem Miniprogramm zwei Dinge
gleichzeitig gemacht?!
Also:
während mit UART2 gerade mal gesendet wird flattern in der ISR der UART1
fleissig Zeichen rein.
Das sollte doch gehen (lt. K-H Buchegger wartet ein Interrupt auf den
anderen).
Mglw. ist der eine String ja schon wieder fertig während der andere noch
gar nicht fertig gesendet ist- ist es das?
Simon schrieb:> Mglw. ist der eine String ja schon wieder fertig während der andere noch> gar nicht fertig gesendet ist- ist es das?interessiertnachfrag
Falls: was tun? Interrupts abschschalten für kurze Zeit?
Nein. sichr nicht. Es sollte doch moeglich sein, zwei Interrupts
parallel laufen zu lassen. Solange die verwendeten Variablen unabhaenig
sind, sollten sich die beiden Interrupts nicht stoeren. Jeder Interupt
hat seinen eigenen Buffer und seine eigenen Variablen dazu.
Simon schrieb:> Lautmalerei der ISR:
[ ... textuelle Beschreibung eines Algorithmus ]
Wikipedia:
<< Die Onomatopoesie (auch Onomatopöie, von griech. ὄνομα: ónoma:
„Name“, und ποίησις: poíēsis: hier „Erschaffung, Herstellung“, folglich
ὀνοματοποιεῖν: onomatopoiein: „einen Namen prägen, benennen“), deutsch
Lautmalerei, Tonmalerei, Schallwort, ist die Nachahmung eines
Naturlautes oder eines sonstigen außersprachlichen akustischen Phänomens
durch die klanglich als ähnlich empfundene Lautgestalt eines
sprachlichen Ausdrucks >>
müßtest du die laut-gemalerte ISR dann nicht als .wav oder .mp3 Datei
anhängen, und sich das anhören wie die Piepstöne von einer C64
Datasette?
Wegstaben Verbuchsler schrieb:> müßtest du die laut-gemalerte ISR dann nicht als .wav oder .mp3 Datei> anhängen, und sich das anhören wie die Piepstöne von einer C64> Datasette?
Das erinnert mich an das erste Lied, was ich je auf einem PC gehört
habe,als nämlich -nach sehrsehr langer Ladezeit- das 1541-II C64-Floppy
tatsächlich Karma Chameleon vibrierte.
Gut, habe ich halt nicht lautgemalt sondern meine Malung aufgeschrieben.
Also... ich stehe wirklich auf dem Schlauch. Vermutlich reichen meine
Kenntnisse nicht aus, den Fehler zu erkennen.
Wäre arg dankbar wenn mir jemand den Fehler zeigen würde. Habe gemalt
und geschrieben und komme stets aufs gleiche hinaus: alles supi.
Würde jemand an einer Frage aus meinem Fachgebiet verzweifeln, ich würde
sie ihm auch irgendwann sagen.
Herzlichst- Simon
Die beiden UART laufen in Hardware völlig unabhängig von deinem
Programm, und empfangen un senden passiert da gleichzeitig.
Die zugehörigen ISR's sind kurz genug (vermutlich, du zeigst ja nie den
ganzen Code), daß die abwechselnd die beiden UARTS bedienen können. Aber
was passiert mit den Daten?
Oliver
Damit es noch etwas klarer wird:
Simon schrieb:> während mit UART2 gerade mal gesendet wird flattern in der ISR der UART1> fleissig Zeichen rein.> Das sollte doch gehen (lt. K-H Buchegger wartet ein Interrupt auf den> anderen).
Das geht, aber wo flattern die Daten hin?
Und wie sehen diese aus?
Wie viele Strings kann dein Programm zur weiteren Verarbeitung
abspeichern?
Was kann hier alles passierern:
> uart2_puts (uart1_string); //ans Terminal senden
wenn gleichzeitig dein GPS sendet?
Was passiert, wenn, wie in deinem GPS-String, mehrere CFs/LFs
nacheinander kommen?
Fragen über Fragen ;)
Oliver
Nur mal kurz um die Dimensionen klarzustellen:
uC = schnell
UART = langsam
GPS = langsamer
User = am langsamsten
Kurz: da ist ein Fehler im weitgehend unbekannten Programm. So ein paar
nach und nach auftretende UART Interrupts steckt jeder uC locker weg...
Simon schrieb:> Wäre arg dankbar wenn mir jemand den Fehler zeigen würde.
Die Fehlerursache ist, dass du den Parser zur Hälfte in die ISR gepackt
hast. Für eine exakte Analyse wäre arg hilfreich, wenn du dein aktuelles
Programm zeigen würdest...
Gibts nen Kochrezept um die vielen Fragen zu umkochen? In etwa, den
kompletten String, sobald er fertig ist, zu kopieren und mit der Kopie
weiterzuarbeiten damit die ISR das Original neu beschreiben kann?
War so meine Idee..
@ Simon (Gast)
>Mist, hätte natürlich die uart2_puts und uart2_putc sein sollen.
Lies mal was über Netiquette!!!
Man poste IMMER VOLLSTÄNDIGEN Originalquellcode, NIEMALS was schnell
hingeschriebenes!
send_GSM("at");//sende an GSM-Modul "at" (gefolgt von <CR>)
4
5
if(uart1_str_complete==1)//wenn die ISR einen vollständigen String
6
hat
7
{
8
uart2_puts(uart1_string);//ans Terminal senden
9
uart1_str_complete=0;//und von vorn
10
}
uart1_str_complete ist eigentlich ein etwas fälschlicher Name.
Eigentlich sollte das uart1_line_complete heissen.
Und immer schön drann denken:
Die ISR meldet dir, wenn eine ZEILE fertig übertragen wurde. Auf den
String "AT\n" antwortet das Modem aber mit 2 Zeilen!
Und zu dem Zeitpunkt, an dem du das erste mal "AT" zum Modem schickst,
kann es durchaus eine Zeitlang dauern, bis das Modem seinerseits mit dem
"AT\nOK\n" antwortet. Was macht dein Programm in der Zwischenzeit?
Und auch drann denken: Ein uart2_puts braucht seine Zeit, bis er etwas
ausgegeben hat. Zb. das "AT" welches in der ertsen Antwortzeile des
Modems kommt. Du gibst dieses AT aus, aber in der Zwischenzeit überträgt
das Modem schon die zweite Zeile der Antwort, das "OK", welches in
welchen Variablen abgelegt wird? (werden würde, wenn uart1_str_complete
richtig stehen würde)
Du willst Dinge 'gleichzeitig' machen?
Gut. Dann musst du aber in deinem Programm an jeder einzelnen Stelle
berücksichtigen und bedenken, was in den jeweils anderen Programmpfaden
alles passieren könnte. Im Moment tust du das nicht. Deine Denkweise
geht immer noch seriell: Zuerst passiert das, dann passiert das.
Simon schrieb:> Gibts nen Kochrezept um die vielen Fragen zu umkochen? In etwa, den> kompletten String, sobald er fertig ist, zu kopieren und mit der Kopie> weiterzuarbeiten damit die ISR das Original neu beschreiben kann?> War so meine Idee..
Das wäre zb gar keine sooo schlechte Idee. (Auch wenn chick das anders
sieht)
Karl Heinz Buchegger schrieb:> Auf den> String "AT\n" antwortet das Modem aber mit 2 Zeilen!
Nee. Viel schlimmer...
Das Modem antwortet
> "at<CR><CR><LF>OK<CR><LF>".
Das ergibt in seinem Programm 5 Zeilen, wovon 3 ziemlich kurz sind...
Oliver
Sitz leider grad nicht am "Arbeitsplatz" (sondern im Schafstall) und
kanns nicht testen, aber sollte ich denn in die ISR eine Abfrage
einbauen, ob eine vermeintlich fertige String-Zeile nur aus CR bzw LF
besteht und diese verwerfen? Ist es das?
Überlass alle Auswertungen dem Hauptprogramm. Da dein GPS ja nun auch
noch andere Antworten schicken kann, und dein Programm irgendwann einmal
mehr machen wird, als die empfangenen Strings einfach wieder zu senden,
brauchst du ein Konzept, um eine unbekannte Anzahl von Strings empfangen
und für die weitere Bearbeitung Speichern zu können.
du
@ Simon (Gast)
>einbauen, ob eine vermeintlich fertige String-Zeile nur aus CR bzw LF>besteht und diese verwerfen? Ist es das?
Nein, das ist nur eine kleine Verbesserung. Dein Problem ist u.a. das
blockiernde Senden der String. Während dieser Zeit ist deine CPU tot für
alles andere. Lösung? Strings kopieren und mit TX-ISR senden. Oder
gleich ein FIFO nutzen.
MFG
Falk
Simon schrieb:> Das Modul antwortet auch artig mit "at<CR><CR><LF>OK<CR><LF>".
Du hast ECHO eingeschaltet, deshalb "siehst" Du alles alles, was Du
sendest, nochmal als Echo.
Ich nehme "at<CR><CR><LF>OK<CR><LF>" mal auseinander:
Du sendest at<CR>
Du siehst: at<CR> # das ist das Echo
Du siehst: <CR><LF> # das ist der Zeilenvorschub, vom Modem
generiert.
Du siehst: OK<CR><LF> # das ist die Antwort OK mit erneutem
Zeilenvorschub
Du würdest Dir das Leben einfacher machen, wenn Du das Echo abschaltest.
Das ist nur sinnvoll bei Terminal-Verbindungen, damit der Mensch, der da
rumtippt, auch sieht, was er tippt. Bei rechnergesteuerten Anwendungen
ist das nicht sehr sinnvoll. Bei Modems kann man das echo mit ATE0<CR>
abstellen.
Am besten speicherst Du diese Einstellung im Modem ab. Die Antworten
reduzieren sich dann auf das wesentliche, nämlich das, was du auch
auswerten willst.
Gruß,
Frank
Falk Brunner schrieb:> Dein Problem ist u.a. das> blockiernde Senden der String. Während dieser Zeit ist deine CPU tot für> alles andere.
Na ja, ganz tot nicht. Die Receive-ISR kann schon, wenn sie dran ist.
Und das reicht in der Regel, um in einen Ringpuffer zu schreiben.
Oliver