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
Dafür musst du die Daten aufs Format parsen und dann entsprechend den DMA stoppen. Woher soll das DMA wissen wann eins deiner Pakete vollständig ist?
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.
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.