Hallo zusammen,
ich versuche mit dem UART1 des STM32F0C8 ein kleines Protokoll zu bauen,
dass 4 Bytes empfängt. Dazu werden vier Bytes von mir ausgelesen und in
ein Array geschrieben. Falls ein Byte zu viel ankommt und nicht gelesen
wird, wird ja das RXNE (Rx not empty) Flag gesetzt und falls dann noch
eins dazukommt und das nicht gelesene überschreiben will das ORE
(overrun error) Flag.
Nur irgendwie kann ich die Flags nicht abfragen, bzw der µC springt
nicht in die RXNE-Abfrage.
Meine Funktion sieht wie folgt aus:
__HAL_UART_CLEAR_PEFLAG(&huart1);// clears RXNE // hier anhalten zeigt das gesetzte RXNE flag, in der if oben springt der µC nicht rein
41
// dismiss the RxBuffer
42
for(i=0;i<=3;i++){aRxBuf[i]=0xFF;}
43
}
44
45
}
Wenn ich 5 Bytes sende (mit falscher Parity) springt der µC nach Erhalt
in den Breakpoint vom UART_FLAG_PE. In der Registern sieht man auch,
dass das RXNE gesetzt ist, nur hätte er schon oben in die RXNE-Abfrage
springen sollen, oder nicht?
Weiß jemand weiter?
HAL_UART_Receive(&huart1, aRxBuf, 4, wTimeout)
wartet, bis 4 Bytes empfangen wurden (falls es kein TO gibt) und kommt
dann SOFORT zurück. Falls ein 5. Byte gesendet wird, dann kommt dies
erst viel später als Deine RXNE-Abfrage an.
Ausnahme:
Zwischen die Zeilen
funkt ein ISR oder Taskwechsel, der länger dauert als 10/fBaud.
Für die ORE-Abfrage gilt sinngemäss das Gleiche.
Wenn Du einen Breakpoint setzt, dann siehst Du wahrscheinlich die Flags,
weil die UART-Register nach dem Breakpoint erst mit Verzögerung
eingelesen werden.
Viele Grüße, Stefan
pxc schrieb:> ich versuche mit dem UART1 des STM32F0C8 ein kleines Protokoll zu bauen,> dass 4 Bytes empfängt.
Du schreibst wirr.
Du kannst mit einem Stück Peripherie kein Protokoll bauen. Grundsätzlich
nicht. Stattdessen solltest du dich hinsetzen mit einem Blatt Papier und
Stift und dir überlegen, wie du eine geordnete Kommunikation zwischen
zwei voneinander völlig unabhängigen Geräten zuwege bekommst -
unabhängig vom Medium dazwischen. Bedenke, daß du niemals einfach nur
starr darauf beharren kannst, eine bestimmte Anzahl von Zeichen zu einem
bestimmten Zeitpunkt zu erhalten. Die Gegenstelle und das
zwischenliegende Kabel führen nämlich ein Eigenleben. Und die Art des
Zeichentransportes ist asynchron.
Also denk dir z.B.aus, daß dein Protokoll mit einem bestimmten Code
eingeleitet wird, dann z.B. deine 4 bytes in Form von 8 Hex-zeichen
(0..9, A..F) übertragen wird und dann ein Endekenner gesendet wird.
Alternativ eine Prüfsumme. So etwas ist ein Protokoll. Natürlich kannst
du es auch anders gestalten, z.B. UU encoded oder sonstwie. Aber aus
jedem Zeichen solltest du erkennen können, ob es ein gültiges Zeichen
ist und wo ein Blockanfang ist.
W.S.
@ W.S.
Ist mir schon klar, das ganze "Protokoll" läuft schon und von den 4
Bytes ist eins das Startbyte und eins das Stoppbyte. Das Erkennen von
Zusatzbytes die sich evtuell durch Störungen einschleichen könnten
sollte nur noch ein nettes Sicherheitsfeature sein, damit das
4-Byte-Frame dann verworfen wird und die Übertragung nochmal wiederholt
wird.
@Stefan K.
>und kommt dann SOFORT zurück. Falls ein 5. Byte gesendet wird, dann kommt>dies erst viel später als Deine RXNE-Abfrage an.
Das würde es zumindest erklären. Die Funktion läuft eigentlich nur in
der Initialisierungsphase und diese ist bis auf den SysTick komplett
uninterrupted, ein paar ms Delay nach dem Receive von 4 Bytes würden
nicht wehtun, weil die Gegenstelle dann eh erstmal darauf wartet was der
µC mit den Empfangenen Bytes macht. Fällt dir vielleicht noch eine
andere/bessere Möglichkeit ein?
Ich benutze diese Bibliotheken nicht, daher blicke ich auch nicht ganz
dahinter, was die einzelnen Funktionen genau bewerkstelligen.
Wie Stefan bereits geschrieben hat, wartete dein Programm ja nicht
darauf, dass noch ein Byte kommt. Es ist sehr unwahrscheinlich, dass
genau zu dem Zeitpunkt deiner Abrage ein Byte eingetrudelt ist.
pxc schrieb:> VOID vGetUARTData(USIGN8* aRxBuf, USIGN16 wDataLength, USIGN8* aErrorTx,> USIGN16 wTimeout){
Soll das die ISR des UART sein?
Falls ja wird bei einem Interrupt direkt zu Beginn mit
pxc schrieb:> __HAL_UART_FLUSH_DRREGISTER(&huart1);
wohl das Datenregister geleert und RXNE damit zurückgesetzt.
Falls das eine normale Funktion ist, könntest du nach deinen ersten 4
Byte auf ein 5. warten (Polling):
@ Dominik B.
Ne, ist keine ISR. Einfach nur eine Funktion, die nach dem wegsenden von
Daten aufgerufen wird um auf die Antwort zu warten.
Das mit FLUSH_DRREGISTER... ist natürlich fehl am Platz dort, danke für
den Hinweis!
pxc schrieb:> Das mit FLUSH_DRREGISTER...
Mit diesem Aufruf löscht Du alle ggf. vorher empfangenen Daten. Ob das
Sinn macht, musst Du selbst entscheiden.
Dein Problem ist, dass PC und mc zueinander asynchron laufen. Das muss
Dein Protokoll-Aufbau berücksichtigen, wenn er robust sein soll.
Auch wenn es von der Effizienz nicht optimal ist, benutze ich deshalb
gerne ein ASCII-Protokoll. Ein Datensatz oder Befehl in eine Zeile, mit
CR abgeschlossen. Das hat den Vorteil, dass die EndeKennung einer msg
(hier: CR) nicht in den Msg-Daten vorkommen kann, anders als bei vielen
Binärprotokollen. Weiterer Vorteil: auf PC-Seite reicht fürs Erste ein
Terminal für die Kommunikation.
Viele Grüße, Stefan
P.S.:
> // gives the uart shift register some time to receive an additional> byte> HAL_Delay(3);
Sowas funktioniert zwar fürs Erste, ist aber auf Dauer eine Fussangel,
z.B. wenn später einmal die Baudrate geändert wird. Besser ist es, wenn
das Protokoll komplett timingunabhängig von beiden Seiten ist.
@ Stefan K.
>Ob das Sinn macht, musst Du selbst entscheiden.
Macht es nicht, da hat wohl der Morgenkaffee noch gefehlt. Habs schon
wieder rausgenommen. Bzw. vor das Transmit gepackt, damit beim Receiven
auf jeden Fall nichts im RDR steht:
1
while(RxBuffer-Frames!=soundso){
2
flushRDR
3
BefehlmC->PC
4
warteaufAntwortmitvGetUARTData(...)
5
}
Da fällt mir grad noch auf, dass auch im Timeout-Fall der Rx
sicherheitshalber zurückgesetzt werden sollte...aber danke nochmal für
den Hinweis warum es in erster Linie nicht so hinhaute wie ich wollte :)