Hallo zusammen
Ich hoffe mal, dass ich nicht der erste bin, mit diesem Problem.
Arbeite mit dem STM32F4 discovery Bord und erhalte alle 50ms ein
Datenpaket per UART, das 100 Bytes lange ist. (Baudrate 460800 ca.
2.5ms)
Da dies auf 4 UART Kanälen stattfindet, möchte ich die Daten per DMA
einlesen.
Nun mein Problem
Wenn von einem Paket ein oder mehrere Bytes verloren gehen, nimmt der
DMA diese vom nächsten Paket, bis er den HAL_UART_RxCpltCallback
ausgelöst.
Wie kann ich nun sicher sein, dass die 100 Bytes von selben Paket sind
und nicht 0 bis 95 vom ersten Paket und 0 bis 4 vom zweiten?
Die Umsetzung sollte möglichst einfach und robust sein deshalb, möchte
ich nicht unbedingt eine Lösung mit Timer oder erstes Byte einzeln ein
zu lesen.
Gibt es dazu eine HAL Funktion.
Danke schon mal im Voraus
Thomas schrieb:> Arbeite mit dem STM32F4 discovery Bord und erhalte alle 50ms ein> Datenpaket per UART, das 100 Bytes lange ist. (Baudrate 460800 ca.> 2.5ms)> Da dies auf 4 UART Kanälen stattfindet, möchte ich die Daten per DMA> einlesen.
Wie schnell läßt du den µC denn takten? Die Bytes kommen so etwas mit 50
kHz herein - und das 4 mal, das heißt, pro Byte hast du insgesamt rund
500 Maschinentakte bei 100 MHz Systemtakt.
Das ließe sich bei sinnvoller Gestaltung der Interrupthandler auch noch
ohne DMA machen - aber das dürfte nicht der knackpunkt sein.
Was du tatsächlich brauchst, ist vielmehr irgend ein Protokoll, also
eine Förmlichkeit, wie deine Datenpakete auszusehen haben.
Logischerweise auch mit Prüfsummen etc.
Sonst wird das nichts.
Also denke dir mal ein Protokoll aus.
Ach ja, denke auch daran, daß serielle Daten, wenn sie denn asynchron
gesendet werden, immer mal ne Pause von zumindest einem halben Stopbit
brauchen, sonst kommt es bei fortlaufender Übertragung dann doch mal zum
Synchronisationsverlust. Da wäre es besser, nicht mit 460 kBaud zu
übertragen und dann 47 ms zu pausieren, sondern stattdessen die Baudrate
herunterzusetzen, mit 2 Stoppbit zu arbeiten und damit genügend Zeit zum
Verarbeiten zu haben.
Und wenn das in deinen Systementwurf nicht hineinpaßt, dann hast du was
verkehrt gemacht und dir ein zu enges Korsett überhelfen lassen.
W.S.
Danke für die schnellen Antworten.
Der uC läuft mit 168Mhz also maximal Speed
Danke W.S. für den Tipp mit der Baudrate.
Habe sie einmal definiert und dann nicht mehr darüber nachgedacht, dass
sie vielleicht unnötig zu schnell sind.
Das mit dem Protokoll habe ich aber noch nicht ganz verstanden.
Lese ich dann einfach 200 Bytes ein und Prüfe anhand der bekannten
Protokollstruktur von wo bis wo meine gültigen Daten sind?
Wie schon gesagt kann der DMA dir nicht garantieren das die 100
empfangen Bytes immer auch logisch nur zu einem paket gehören.
Auf einem AVR32 kann man den UART so einstellen, das er nach einer IDLE
Zeit einen Interrupt generiert wird. Dort mach ich das so das mit diesem
Interrupt das Ende des eines Packets (mit variabler Länge) erkannt wird.
Der DMA wird dann neu aufgesetzt.
Thomas schrieb:> Das mit dem Protokoll habe ich aber noch nicht ganz verstanden.
Wenn man Pakete von Daten braucht, dann muß man sich was einfallen
lassen, um deren Anfang und die korrekte Länge beim Empfänger
feststellen zu können. Das ist das A und O für jegliche Verbindung.
Stell dir vor, du schaltest deinen Empfänger irgendwann ein und er muß
aus dem Zeugs, was da so hereinströmt, seine Synchronisierung auf die
Datenpakete finden. Das selbe ist nötig, falls er mal durch irgendwas
aus dem Tritt gekommen ist und dann den Anfang des nächsten Paketes
suchen muß.
Wie du das anstellst, ist dein Problem. Wen du bei deinem Datenstrom
irgend ein Zeichen hast, was definitiv dort vorkomen DARF, dann kannst
du sowas als Synchronzeichen benutzen. Ebenso kannst du eine Art
Signatur aus mehreren Zeichen erfinden, die dir den Paketbeginn anzeigt
(Beispiel: RDS-Empfang). Du kannst aber auch UU codieren, um Zeichen
frei zu kriegen und dennoch nicht allzuviele Bits zu vergeuden.
W.S.
Thomas schrieb:> Das mit dem Protokoll habe ich aber noch nicht ganz verstanden
Das hat einen doppelten Zweck:
1. erkennen, wann ein Paket startet und endet.
2. den Erfolg der Übertragung prüfen.
zu 1 gibt es verschiedene Möglichkeiten, z.B. eindeutige Zeichen für
Anfang und Ende, bei ASCII-Daten sind dafür die Sonderzeichen STX und
ETX verwendbar, oder man schliesst jeden Record mit CR ab. Das muss
natürlich beim Empfang jedes Zeichens geprüft werden, was mit DMA
wahrscheinlich nicht geht, im Interrupt aber schon. Eine andere
Möglichkeit ist eine längere Pause zwischen den Records, wie schon
angedeutet, dann kann man erkennen, dass ein Record zu Ende ist, aber
ausserhalb der DMA-Funktion mit einem Timer. Time Interrupts sind
generell wesentlich flexibler zur Protokollverarbeitung als DMA.
zu 2 nimmt man Prüfsummen oder CRC, das ist wieder ein anderes Thema,
aber kein unwichtiges. Bei externen Übertragungen ist immer mit Fehlern
zu rechnen.
Georg
Hallo Zusammen
Danke für die Hilfe.
Ich denke jetzt habe ich eine ziemlich robuste Lösung.
Ich habe das Protokoll so angepasst, dass die ersten beiden Bytes immer
gleich sind. Als eine Art Startbedingung die ich überprüfe.
Danach überprüfe ich anhand der CRC Checksumme ob der Rest der Daten in
Ordnung ist. Sollte es also eine Vermischung der Pakete geben, wird dies
auch mit der falschen CRC erkannt.
Als zweite Massnahme wird der DMA erst 10ms nach einem DMA Callback
wider gestartet. (10m da ein Datenpaket jetzt ca. 9ms lang ist) Somit
soll der DMA wider auf die Pakete Synchronisiert werden, so dass der DMA
nicht mitten in einem Paket neu gestartet wird.
Ausserdem kann ich mit dieser Methode auch gleich erkennen, wenn nach
weiteren 50ms kein Callback aufgetreten ist, dass das Paket zu kurz war
und den DMA Neustarten.
Vielen Dank an alle für die Hilfe
Thomas
Es gibt auch einen receive-timeout, der einen interrupt auslösen kann.
Falls die Pakete garantiert in einem Rutsch übertragen werden und
zwischen Paketen garantiert eine kurze Pause ist, kann man den reveice
timeout auf z.B. 5 Zeichen einstellen, und in dem dann ausgelösten
interrupt den DMA deaktivieren, und die Verarbeitung des Pakets
anstossen. Dadurch wirds auch einfacher, nach verlorenen Zeichen wieder
auf ein frisches Paket aufzusetzen und das Protokoll zu synchronisieren.