Hallo Zusammen, ich möchte mit einem STM32F207 unter Nutzung der STM32 HAL "Datenpakete" verschiedener Länge empfangen. Zwischen einzelnen Dazenpaketen liegt eine zeitliche Pause im Millisekundenbereich. Da ich den receive complete Interrupt für eine feste Anzahl an Bytes einstellen kann, bekomme ich nicht mit, wenn ein kürzeres Datenpaket eintrifft. Bei einigen Cortex M0 gibt es ja den receive timeout Interrupt, der sich dafür nutzen lässt. Leider hat das der oben genannte Controller nicht. Welche Möglichkeiten habe ich, das Ende eines Datenpakets (Sendepause) zu erkennen und dann den FIFO auszulesen? Jedes Byte einzeln auslesen kann ja auch nicht die Lösung des Problems sein. Vielen Dank für eure Antworten im Voraus!
Dann solltest du nur 1 Byte von HAL_UART_Receive_IT anfordern.
1 | HAL_UART_Receive_IT(hcomport, &rxbuf, 1); |
Ich häng dir mal einen funktionierenden Beispielcode an.
:
Bearbeitet durch User
Harry L. schrieb: > Dann solltest du nur 1 Byte von HAL_UART_Receive_IT anfordern. Aber das ist ja genau das, was ich nicht mehr machen wollte, weil der Prozessor ja bei jedem Byte die ISR ausführen muss und das Byte einzeln abholt. Der FIFO wird ja dann auch nicht verwendet. Wenn ich Daten mit hohen Baudraten bei mehreren UARTs empfange, dann ist mein Prozessor ja nur noch damit beschäftigt, die einzelnen Bytes abzuholen. Gibt es keine elegantere Lösung?
Alexander K. schrieb: > Aber das ist ja genau das, was ich nicht mehr machen wollte, weil der > Prozessor ja bei jedem Byte die ISR ausführen muss Geht aber nicht anders, wenn du nicht genau weist, wie viele Bytes du zu erwarten hast. Ein UART ist aus Sicht der CPU schnarchlahm. Ausserdem ist die ISR-Ausführungszeit gemessen an der Gesamtzeit lächerlich, wenn die nur sporadisch aufgerufen wird - das ist absolut nicht der Rede wert und kann trotzdem jederzeit duch höher priorisierte Interrups unterbrochen werden. Wenn du die Zeit nicht hast, bist du bereits sehr vel früher (bei der Auswahl der Hardware) falsch abgebogen.
:
Bearbeitet durch User
Alexander K. schrieb: > Leider hat das der oben genannte Controller nicht. Alexander K. schrieb: > Aber das ist ja genau das, was ich nicht mehr machen wollte, weil der > Prozessor ja bei jedem Byte die ISR ausführen muss und das Byte einzeln > abholt. Wasch mich, aber mach mich nicht nass. Wenn Du auch selber programmieren kannst (ohne HAL versteht sich), dann lese die FIFOs (FIFI?), immer wenn sie überlaufen und zusätzlich im Millisekundenraster. Das spart ISR-Aufrufe und verpasst keine kleinen Blöcke.
> Bei einigen Cortex M0 gibt es ja den receive timeout Interrupt, der sich > dafür nutzen lässt. Leider hat das der oben genannte Controller nicht. > [...] Welche Möglichkeiten habe ich, das Ende eines Datenpakets > (Sendepause) zu erkennen und dann den FIFO auszulesen? Zunächst mal: Ich kann dem RefManual auf die schnelle nirgendwo entnehmen, dass der F207 eine USART-FIFO hat, wenn du also nicht DMA nutzt, wird da bei jedem Byte ein Interrupt generiert, was bei deinem Anwendungsszenario (???) wahrscheinlich keinen signifikanten Overhead erzeugt und völlig OK ist. Wenn du dafür doch noch DMA nutzen willst, müsstest du dir diesen IDLE-Interrupt mit einem Timer selbst generieren: Der Timer sollte nach nicht weniger als
1 | (Bufferlänge/2 + 1) * (10bit/(bit/s)) |
überlaufen, damit du erkennst wenn es eine Pause gibt, ohne fälschlicherweise das Paketende zu detektieren während der Buffer noch gefüllt wird. Bei einem 16 Byte Buffer und 115200 bit/s mit je einem Start- und Stop-Bit wären das also ~782us. Das funktioniert aber nur wenn diese berechnete Zeit zuverlässig kleiner als der Mindestabstand der Datenpakete ist. Wenn ein Paket doch mal schneller reinkommt hast du ein Problem, dann werden die Pakete als fälschlich zusammenhängend erkannt. Stell den Timer also so ein, dass er nach der gewünschten IDLE-Zeit (Länger als es dauert den halben Buffer zu füllen und weniger als die Paketabstände) einen Overflow-Interrupt generiert, welchen du als Anlass nehmen kannst das Datenpaket als beendet zu sehen. Den Zähler des Timers setzt du einfach bei jedem Transfer-(Half)-Complete-Interrupt zurück und wertest sofort den Buffer aus, in den DMA-Registern steht wie weit der zu diesem Zeitpunkt schon gefüllt ist. Dieses komplizierte Vorgehen lohnt sich aber ehrlich gesagt nicht für deinen Anwendungsfall, außer du hast riesige Pakete und sendest mit unüblich hohen Datenraten. Nimm lieber die einfache Lösung mit RX-Interrupts pro Byte ;)
Hab jetzt nicht alles genau gelesen, aber wenn Du sowieso "Datenpakete" hast, warum dann nicht einen Header fixer Länge davorspannen (u.a.) mit einem Längenfeld. Dann Header empfangen und Empfang des Datenfelds entsprechend programmieren. Das geht dann auch mit DMA, wenn Du willst.
Alexander K. schrieb: > Zwischen einzelnen Dazenpaketen liegt > eine zeitliche Pause im Millisekundenbereich. In dem Fall funktioniert vielleicht der IDLE-Interrupt?
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.