Hallo zusammen,
über RS232 (bzw. UART) schicken zwei Platinen je Daten mit 100 Hz
(4Byte) an eine dritte Platine (alle STM32M0+ Kerne).
Um die CPU zu entlasten möchte ich für das ganze die DMA zur Hilfe
nehmen. Dabei kommte es leider dazu, dass des öfteren Daten dem falschen
Controller zugeordnet werden, was ich mir nicht erklären kann (Siehe
Bild).
Im meinem Programm auf dem Controller, der von beiden Controllern
empfängt, identifiziere ich die Daten anhand einer mitgesendeten ID (
Nachricht = ID + 3Byte Variablenwert). Die Auswertung geschieht im
HAL_UART_RxCpltCallback() und sieht so aus:
In der SMP_HandleTypeDef sind Informationen zur UART-Schnittstelle, tx-,
rx-Puffer, etc. hinterlegt.
Eventuell ist das zu viel Arbeit für den Interrupt? Eine Alternatividee
wäre es eventuell die Daten erstmal in einen Ringpuffer zwischen zu
lagern und dann außerhalb des Interrupts abzuarbeiten.
Bin sehr dankbar für Tips :)
Frage schrieb:> Hallo zusammen,>> über RS232 (bzw. UART) schicken zwei Platinen je Daten mit 100 Hz> (4Byte) an eine dritte Platine (alle STM32M0+ Kerne).>> Um die CPU zu entlasten möchte
Im Ernst? Die langeweilen sich zumindest bezüglich des UARTs zu TODE!
> ich für das ganze die DMA zur Hilfe> nehmen.
Kann man machen, ist hier aber akademischer Overkill!
> Eventuell ist das zu viel Arbeit für den Interrupt?
Snowflake-CPU? Das bissl Kram ist lächerlich, erst recht für einen 32Bit
ARM.
> Eine Alternatividee> wäre es eventuell die Daten erstmal in einen Ringpuffer zwischen zu> lagern und dann außerhalb des Interrupts abzuarbeiten.
Und das akdemische Konzept noch mehr aufblasen und noch ineffizienter
werden. Na dann mal los!
> Bin sehr dankbar für Tips :)
Ich kenn mich mit STM32 nicht aus, kann dir also im Detail nicht helfen.
Aber nehmen wir mal an, DMA wäre für diese Aufgabe sinnvoll. Da gibt es
zunächst das Problem der Synchronisation. Spich, wie sorgt man dafür,
daß die DMA immer ein komplettes Datenpaket empfängt und speichert. Und
wie schafft man es, falls sie sich "verschluckt" hat, wieder auf den
Anfang des Datenpakets zu synchronisieren? Wenn man das gescheit gelöst
hat, ist die Auswertung der Nachricht trivial. Ich vermute Ein Problem
bei der Synchronisation.
Du kannst es auch anders angehen. Schreib erstmal Software, die den UART
nur per CPU bedient. Auch dort muss man synchronisieren, wenn gleich
etwas anders. Dann kannst du den Verbrauch an CPU-Leistung messen. Und
DANN kannst du vielleicht entscheiden, es doch per DMA zu machen.
Ich verstehe nicht wie zwei Platinen nach den gleiche UART senden
konnen. Normalerweise ist das immer ein sender und ein empfanger. Konnen
die beide gleichzeitig senden ? Dan gibt doch mull ?
Vergiss die Kombination "UART<->DMA" besser ganz schnell wieder!
Die Sau wird hier regelmäßig durchs Forum getrieben, und das Ergebnis
ist jedesmal das Selbe:
Es macht einfach in 99,9% aller Fälle keinen Sinn.
Das läuft immer gleichermaßen ab: jemand behauptet, er könne das alles
mit DMA viel besser, und sobald der Code fertig sei, würde der
veröffentlicht...gesehen hat man davon bisher noch nie etwas...
Da du HAL nutzt, schau dir den Code im Anhang an!
Der funktioniert mit Interrupts, ist erprobt, läuft einfach problemlos,
und sollte sich leicht für deine Bedürfnisse anpassen lassen.
FIFOs sind auch gleich dabei....
Die CPU-Last, die sowas verursacht, ist so gering, daß du die getrost
vernachlässigen kannst.
Jan H. schrieb:> Ich verstehe nicht wie zwei Platinen nach den gleiche UART senden> konnen.
Das sagt keiner. Sie senden an den gleichen Prozessor. Der hat aber
sicher 2 UARTs zum empfangen.
Ein empfangsuart oder zwei?
Was sagen die Bilder?
100hz heißt 2x4 Byte alle 10ms?
Mit 9,6 oder 115,2k?
Wer ruft die Funktion auf, woher weißt Du, was schief läuft?
p.s.:
Sind deine bitmanipulationen nicht sehr verwirrend?
Falk B. schrieb:> Das sagt keiner. Sie senden an den gleichen Prozessor. Der hat aber> sicher 2 UARTs zum empfangen.
Das mag sein, aber der TO hat ja noch ganz andere Ungereimtheiten in
petto. Siehe das:
Frage schrieb:> Dabei kommte es leider dazu, dass des öfteren Daten dem falschen> Controller zugeordnet werden, was ich mir nicht erklären kann
Wenn die Daten an zwei separate UARTs gehen, dann kann es keine falschen
Zuordnungen geben, es sei denn, der TO hat noch ganz andere Schnitzer
gemacht.
W.S.
Jan H. schrieb:> Ich verstehe nicht wie zwei Platinen nach den gleiche UART senden> konnen. Normalerweise ist das immer ein sender und ein empfanger. Konnen> die beide gleichzeitig senden ? Dan gibt doch mull ?
Wie schon angemerkt senden die beiden Controller jeweils über einen
UART.
A. S. schrieb:> Ein empfangsuart oder zwei?>> Was sagen die Bilder?>> 100hz heißt 2x4 Byte alle 10ms?>
Wie gesagt zwei UARTs. Exakt die Controller senden alle 10 ms je 4 Bytes
(wünschenswert wären idealerweise 1KHz, allerdings nicht zwingend
nötig).
> Mit 9,6 oder 115,2k?>
Die UARTs laufen mit 500kbaud.
> Wer ruft die Funktion auf, woher weißt Du, was schief läuft?
Die Funkton wird wie gesagt im HAL_UART_RxCpltCallback() aufgerufen,
also im Interrupt. Was genau schief läuft weiß ich leider noch nicht. Im
Debugger beim empfangenden Controller sehe ich eben genau das was im
Bild zu sehen ist, d.h. immer wieder falsche Werte die ankommen/gelesen
werden. Teilweise werden Werte anscheinend vertauscht. Ich vermute auch,
dass es an der Synchronisation der DMA hapert. Mir mangels allerdings
leider an Erfahrung bei den STM32 DMAs. Eine ausführliche, hilfreiche
Aplication Note von ST hab ich leider auch noch nicht gefunden.
>> p.s.:> Sind deine bitmanipulationen nicht sehr verwirrend?
Die bitmaniupulationen sind notwendig, da die 16Bit Variablen in 3Bytes
mit jeweiligen Bit-Identifier ankommen.
Ich werde mich wohl von der Idee UART und DMA verabschieden und die
UARTs mit Interrupts auslesen. Das DMA bei der Paketgröße (4Byte) ein
Overkill ist sehe ich ein. Meine Idee war es die CPU soweit wie möglich
zu entlasten und zu verhindern, dass ständig irgendwelche Interrupts in
das Hauptprogramm grätschen.
Harry L. schrieb:> Da du HAL nutzt, schau dir den Code im Anhang an!
Danke für den Anhang! :)
Gerald M. schrieb:> Bei UART, vor allem bei so hohen Frequenzen, immer einen CRC> mitschicken.> Bei 4Byte/10ms wird der Controller durch den DMA nicht merklich> entlastet.
Wie würde ich das dann anstellen? Ich weiß, dass die STM32er hardware
CRC unterstützen, hab damit aber noch keine Erfahrung gesammelt. Das
würden dann 4Byte mehr pro Paket bedeuten oder?
Der CRC kann so lang sein wie du willst (ok, bei der Hardwareunit vom
STM32 7, 8, 16 oder 32 Bit). 4 Byte wären natürlich völlig übertrieben,
da kannst du ja gleich die Nachricht zwei mal hintereinander schicken.
Du musst die Unit nicht nehmen, sondern kannst das auch einmal "per
Hand" rechnen. Das musst du ja sowieso, da ja der Sender den CRC
mitsenden muss.
Frage schrieb:> Wie würde ich das dann anstellen? Ich weiß, dass die STM32er hardware> CRC unterstützen, hab damit aber noch keine Erfahrung gesammelt. Das> würden dann 4Byte mehr pro Paket bedeuten oder?
Ohje! Für 4 Byte Daten eine 4 Byte CRC? Man kann es auch übertreiben!
Die CRC ist nicht zwingend, wenn die Verbindung zwischen den Boards
mechanisch und elektrisch robust ist. Ist ja keine Flugzeugsteuerung.
Ein UART hat keine exorbitante Bitfehlerrate, auch nicht bei 500kbit/s.
Wozu eigentlich so hoch? Bei 4Bytes/10ms dauert das gerade mal 80us,
dann sind 9,12ms Pause, also "gigantische" 0,8% Auslastung deiner
UART-Verbindung. Ist das sinnvoll? Ist das nötig? selbst 50kbit/s würden
nur 8% Auslastung ergeben.
Wenn man denn WIRKLICH eine CRC nutzen will, reichen bei 4 Bytes
Nutzdaten eine 8 Bit CRC. Die kann man mit der CPU berechnen. Ein
passendes Polynom bzw. die Funktion dafür gibt es u.a. bei Onewire.
Beitrag "Re: Onewire + DS18x20 Library"
Die CRC für Arme ist ein einfaches Paritätsbyte, dessen Berechnung ist
einfach und schnell. Damit fängt man auch ausreichend viele Bitfehler
ausreichend gut ab, wenn man nicht gerade zum Mars fliegen will.
Parity = d[0] ^ d[1] ^ d[2] ^ d[3];
Gerald M. schrieb:> Der CRC kann so lang sein wie du willst (ok, bei der Hardwareunit vom> STM32 7, 8, 16 oder 32 Bit). 4 Byte wären natürlich völlig übertrieben,> da kannst du ja gleich die Nachricht zwei mal hintereinander schicken.>> Du musst die Unit nicht nehmen, sondern kannst das auch einmal "per> Hand" rechnen. Das musst du ja sowieso, da ja der Sender den CRC> mitsenden muss.
Ah, okay ich dachte HW CRC funktioniert beim STM32 nur mit 32bit. Dann
lese ich mich da mal ein. Zwingend nötig ist das allerdings glaube ich
nicht wirklich. Die Controller trennen nur kurze Kabel und besondere
Störeinflüsse sehe ich jetzt auch nicht im Labor.
Falk B. schrieb:> Wozu eigentlich so hoch? Bei 4Bytes/10ms dauert das gerade mal 80us,> dann sind 9,12ms Pause, also "gigantische" 0,8% Auslastung deiner> UART-Verbindung. Ist das sinnvoll? Ist das nötig? selbst 50kbit/s würden> nur 8% Auslastung ergeben.
Bei 1KHz wäre es dann ja schon wieder etwas anderes. Definitiv nicht
ausgelastet aber zwecks Puffer und da ja auch die Verbindung keinen
nennenswerten Umwelteinflüssen ausgesetzt ist sollte das ja ohne Proble
hinhauen.
Falk B. schrieb:> Beitrag "Re: Onewire + DS18x20 Library"
Danke für den Link!
Falk B. schrieb:> Die CRC für Arme ist ein einfaches Paritätsbyte, dessen Berechnung ist> einfach und schnell. Damit fängt man auch ausreichend viele Bitfehler> ausreichend gut ab, wenn man nicht gerade zum Mars fliegen will.>> Parity = d[0] ^ d[1] ^ d[2] ^ d[3];
Wäre auch eine Idee aber ich denke ich werde mich mal mit CRC vertraut
machen und etwas neues lernen. Vielen Dank also schonmal für die vielen
Anregungen.
Frage schrieb:> Falk B. schrieb:>> Wozu eigentlich so hoch? Bei 4Bytes/10ms dauert das gerade mal 80us,>> dann sind 9,12ms Pause, also "gigantische" 0,8% Auslastung deiner>> UART-Verbindung. Ist das sinnvoll? Ist das nötig? selbst 50kbit/s würden>> nur 8% Auslastung ergeben.>> Bei 1KHz wäre es dann ja schon wieder etwas anderes. Definitiv nicht> ausgelastet aber zwecks Puffer und da ja auch die Verbindung keinen> nennenswerten Umwelteinflüssen ausgesetzt ist sollte das ja ohne Proble> hinhauen.
Bei hohen Bitraten kommen die Interrupts (einer pro Byte) ohne DMA aber
deutlich schneller hintereinander. Wenn dann die ISR vom Byte noch nicht
fertig ist wenn Byte+1 kommt geht unter Umständen ein Byte verloren. Da
muss man auch aufpassen wann man den Empfang des Bytes bestätigt und
damit den Interrupt wieder freigibt. Am Anfang der ISR ist meistens
besser als am Ende. Unabhängig von der UART ISR kann auch eine andere
ISR mit gleicher oder höherer Priorität zu verlorenen Bytes führen wenn
diese länger läuft als eine Bytezeit auf der Leitung.
Matthias
Kann es sein das beide UARTs gleichzeitig senden ? An 500 kbaud bedeutet
das schon das sie nur 1µs ISR Zeit zu verpassen ist (2*500 kbaud =
1Mbaud). Wen die takt von µ dan 48 MHz (soll so etwas sien für M0 core),
haben sie nur 48 takten für den gesamte ISR. Sollte knapp sein... Haben
sie schon versucht mit ein niedrige baudrate ?
Jan H. schrieb:> An 500 kbaud bedeutet> das schon das sie nur 1µs ISR Zeit zu verpassen ist (2*500 kbaud => 1Mbaud).
Vollkommener Blödsinn!
Die Interrupts kommen pro Zeichen und nicht pro Bit.
Jan H. schrieb:> Kann es sein das beide UARTs gleichzeitig senden ? An 500 kbaud bedeutet> das schon das sie nur 1µs ISR Zeit zu verpassen ist (2*500 kbaud => 1Mbaud).
Mein Gott, was für Koniferen(tm) hier im Forum!
Zum Erstem sind 500kb/s = 2 us/Bit und zweitens wird ein Byte vom UART
in Hardware empfangen, was im Normalfall 10 Bits hat, hier 20us. Und
drittens haben praktisch alle UARTs einen Empfangspuffer, oft auch mehr,
also ein Mini-FIFO. Da können je nach CPU 1-3 Bytes gespeichert
werden, bevor es zum Datenverlust kommt.
> Wen die takt von µ dan 48 MHz (soll so etwas sien für M0 core),> haben sie nur 48 takten für den gesamte ISR. Sollte knapp sein...
Dyskalkulie ist heilbar . . .
20us sind bei 48 MHz satte 960 Takte, damit kann man schon EINGES
anfangen, wenn man nicht mehrere Millisekunden in höherpriorisierten
Interrupts vertrödelt.
Falk B. schrieb:> 20us sind bei 48 MHz satte 960 Takte, damit kann man schon EINGES> anfangen, wenn man nicht mehrere Millisekunden in höherpriorisierten> Interrupts vertrödelt.
Ja, aber die zwei uart konnen zusammen kommen, dan sind nur noch 480
takte da. Und den puffer ist 1..3 bytes, da wirden pro UART schon 4
bytes gesendet. Oder ist das auch miscalculiert ?
Jan H. schrieb:> Ja, aber die zwei uart konnen zusammen kommen, dan sind nur noch 480> takte da.
Vollkommen egal. Selbst wenn von beiden UARTs ein Interrupt ansteht, so
wird erst einer und sofort nach dessen Ende der andere bearbeitet. Wenn
man es clever macht, könnte man sogar in einer ISR beide Puffer prüfen
so ggf. ein paar Dutzend Takte für den 2. ISR-Aufruf sparen.
> Und den puffer ist 1..3 bytes, da wirden pro UART schon 4> bytes gesendet. Oder ist das auch miscalculiert ?
Wie meinen der Herr?
Aus den STM32 F0 Ref :
Universal synchronous asynchronous receiver transmitter (USART) RM0360
606/779 DocID025023 Rev 4
Overrun error
An overrun error occurs when a character is received when RXNE has not
been reset. Data
can not be transferred from the shift register to the RDR register until
the RXNE bit is
cleared.
USART_RDR is performed.
The shift register will be overwritten. After that point, any data
received during overrun
is lost.
An interrupt is generated if either the RXNEIE bit is set or EIE bit
is set.
Scheinbar hat den F0 nur ein byte receive buffer. Wen da 4 bytes nachein
ander kommen, dan ist den puffer doch schnell "verschwunden". Aber das
sind hier alle reine "Glaskugel" forschlage, wir wissen den Takt nich
und auch den type µ nicht.
Jan H. schrieb:> Scheinbar hat den F0 nur ein byte receive buffer. Wen da 4 bytes nachein> ander kommen, dan ist den puffer doch schnell "verschwunden".
Schneller als im Abstand von 20us (bei 500k/8N1) werden die nie
reinkommen.
Jan H. schrieb:> Scheinbar hat den F0 nur ein byte receive buffer. Wen da 4 bytes nachein> ander kommen, dan ist den puffer doch schnell "verschwunden". Aber das> sind hier alle reine "Glaskugel" forschlage, wir wissen den Takt nich> und auch den type µ nicht.
Es ist ein mit 64 MHz taktender STM32G081KB.
Μαtthias W. schrieb:> Bei hohen Bitraten kommen die Interrupts (einer pro Byte) ohne DMA aber> deutlich schneller hintereinander. Wenn dann die ISR vom Byte noch nicht> fertig ist wenn Byte+1 kommt geht unter Umständen ein Byte verloren. Da> muss man auch aufpassen wann man den Empfang des Bytes bestätigt und> damit den Interrupt wieder freigibt. Am Anfang der ISR ist meistens> besser als am Ende. Unabhängig von der UART ISR kann auch eine andere> ISR mit gleicher oder höherer Priorität zu verlorenen Bytes führen wenn> diese länger läuft als eine Bytezeit auf der Leitung.
Mein Ansatz wäre im IT das Byte erstmal nur zwischenzuspeichern. Sobald
von einem UARTs 4Byte (+ CRC/Parity) empfangen wurden, würde ich dann
evtl. einen IT triggern in dem die Daten ausgewertet werden. Dieser
würde dann eine niedrigere Prirität als die empfangs Interrupts haben.
Sollte am anderen UART also ein weiteres Byte ankommen, würde das
trotzdem empfangen.
Weil die beiden UARTs ja vollkommen unsynchron senden, könnte es sonst
glaube ich dazu kommen, dass bei ungünstigen Timing vielleicht mal ein
Byte verschluckt wird, wie du ja angesprochen hast.
Frage schrieb:> Mein Ansatz wäre im IT das Byte erstmal nur zwischenzuspeichern.
Was soll ein IT sein? Die 1001 selbstgestrickt Abkürzung für einen
Interrupt?
> Sobald> von einem UARTs 4Byte (+ CRC/Parity) empfangen wurden, würde ich dann> evtl. einen IT triggern in dem die Daten ausgewertet werden.
Wozu braucht man dafür einen 2. Interrupt? Ein Flag setzen reicht,
welches dann irgendwann von einer Statemachine in der Hauptschleife
bearbeitet wird.
> Dieser> würde dann eine niedrigere Prirität als die empfangs Interrupts haben.> Sollte am anderen UART also ein weiteres Byte ankommen, würde das> trotzdem empfangen.> Weil die beiden UARTs ja vollkommen unsynchron senden, könnte es sonst> glaube ich dazu kommen, dass bei ungünstigen Timing vielleicht mal ein> Byte verschluckt wird, wie du ja angesprochen hast.
Das einzige was da ungünstig sein muss ist dein Programmierkonzept. Ja,
man braucht ein Pufferkonzept. Sein es ein einfacher Puffer in einem
Array oder ein echter FIFO, wenn gleich der hier vielleicht etwas
Overkill ist. Prinzipiell gelten auch hier die wesentlichen
Anforderungen an eine ISR, siehe Interrupt.
Falk B. schrieb:> Was soll ein IT sein? Die 1001 selbstgestrickt Abkürzung für einen> Interrupt?
Genau, ein Interrupt ist gemeint. Dass das keine geläufige Abkürzung ist
war mir nicht bewusst.
Falk B. schrieb:> Wozu braucht man dafür einen 2. Interrupt? Ein Flag setzen reicht,> welches dann irgendwann von einer Statemachine in der Hauptschleife> bearbeitet wird.
Habe ich mich auch schon von verabschiedet.
Falk B. schrieb:> Das einzige was da ungünstig sein muss ist dein Programmierkonzept.
Daran versuche ich ja zu arbeiten. Ich tappe hier wie gesagt in
unbekannten Gebiet. Es gibt bei weitem nicht für alles Beispielcode und
da mir die nötige Erfahrung fehlt, ist es eben learning-by-doing wenn
ich es selber mache.