Forum: Mikrocontroller und Digitale Elektronik STM32 UART Datenempfang Verständnisfrage


von Alexander K. (alexander_43)


Lesenswert?

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!

von Harry L. (mysth)


Angehängte Dateien:

Lesenswert?

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
von Alexander K. (alexander_43)


Lesenswert?

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?

von Harry L. (mysth)


Lesenswert?

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
von Lottomann (Gast)


Lesenswert?

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.

von Florian S. (vatterger)


Lesenswert?

> 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 ;)

von Keine Ursache! (Gast)


Lesenswert?

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.

von Bauform B. (bauformb)


Lesenswert?

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
Noch kein Account? Hier anmelden.