Hallo,
beim STM32F10x heißt es im Datenblatt zum SPI für Transfers im
Master-Modus:
> The software has to follow this procedure to transmit and receive data:> 1. Enable the SPI by setting the SPE bit to 1.> 2. Write the first data item to be transmitted into the SPI_DR register> (this clears the TXE flag).> 3. Wait until TXE=1 and write the second data item to be transmitted.> Then wait until RXNE=1 and read the SPI_DR to get the first received> data item (this clears the RXNE bit). Repeat this operation for each> data item to be transmitted/received until the n–1 received data.> 4. Wait until RXNE=1 and read the last received data.> 5. Wait until TXE=1 and then wait until BSY=0 before disabling the SPI.
(Seite 710)
Das ganze ziehlt wohl auf das doppelte gepufferte Datenregister ab.
Allerdings frage ich mich, ob die Beschreibung tatsächlich etwas naiv
ist:
Man schreibt also ein Byte ("first data item") rein und das SPI beginnt
mit der Übertragung, wodurch das Pufferregister frei wird und man schon
ein Byte nachladen ("second data item") kann. Dann wartet man implizit
auf das Ende der Übertragung des ersten Bytes ("RXNE"), durch das ja
gleichzeitig auch ein Byte empfangen wurde, welches man dann lesen soll
("first received data item"), um direkt im Anschluss wieder ein Byte zum
Versand nachzuladen.
Wenn man allerdings nun ein Byte nicht rechtzeitig liest, etwa weil ein
Interrupt dazwischenkommt, dann geht dieses doch schlimmstenfalls
verloren, oder? Denn im Puffer befindet sich ja wegen der
verschachtelten Prozedur laut Datenblatt schon das nächste zu
versendende Byte. Und wenn das fertig übertragen wurde, würde das
dadurch gleichzeitig empfangene Byte wieder in den Puffer geschrieben.
Damit wäre ein Byte überschrieben und verloren.
Übersehe ich da etwas?
Ich meine, es ist ja nicht so, dass diese Problematik nicht leicht
durchschaubar wäre. Aber ich bin es eigentlich von Datenblättern anderer
Mikrocontrollerfamilien gewohnt, dass solche Sachen beschrieben werden.
Und im Datenblatt des STM32 bin ich darum etwas hin- und hergerissen:
(a) Das Datenblatt ist schon richtig so. Das heißt, ich übersehe
irgendwas.
(b) Das Datenblatt ist naiv und geht aufgrund der Komplexität nicht
auf jeden "Randfall" extra ein.
(c) Das Datenblatt ist Mist.
Fairerweise würde ich (a) annehmen wollen, aufgrund meiner Erfahrung
gehe ich aber von (c) aus.
Danke & Grüße,
K
Sven P. schrieb:> Übersehe ich da etwas?
Ja.
Zum einen gibt es ein Overflow-Flag, was anzeigt, dass Du etwas verpasst
hast.
Zum anderen lässt sich das Verpassen auf verschiedene Art und Weise
verhindern.
Zum einen kannst Du einen Interrupt mit ausreichender Priorität
aktivieren, in dem Du sofort empfangene Daten abholst.
Zum anderen kannst Du DMA nutzen, dann läuft das im Hintergrund ab.
Das steht, wie Du es gewohnt bist, im Reference Manual. Dazu noch in
thematischen Datenblättern wie z.B. für DMA richtig ausführlich.
Einfach lesen!
Doctor Snuggles schrieb:> Einfach lesen!
Mir sind die 100 anderen Optionen ja durchaus bewusst, mit denen man das
Problem umschiffen kann. Das ist aber nicht das, was ich hoffe, zu
übersehen.
Ich hoff(t)e, einen Mechanismus im UART zu übersehen, der bei exakter
Befolgung der Beschreibung im Datenblatt dafür sorgt, dass kein Byte
verlorengeht.
Oder anders gesagt, ich kann die Beschreibung im Datenblatt so nicht
nachvollziehen: Warum wird dort ein "kompliziertes" Verschachteln der
Sende-/Empfangszyklen beschrieben?
- Es ist, so wie es dort steht, nicht sicher.
- Man könnte es problemlos so umsortieren, dass es sicher ist (d.h.
nicht verschachteln, sondern immer auf das einlaufende Byte warten,
bevor nachgeladen wird). Klar, ist dann langsamer.
- Es gibt DMA.
- Es gibt Interrupts mit Prioritäten.
Was also soll diese Vorschrift?
Einen Sinn würde die Vorschrift zum Beispiel ergeben, wenn der UART das
erste empfangene Byte ins Pufferregister schiebt und das zweite dann im
SPI-Schieberegister behält. Wenn nun ein drittes Byte reinkommt, ists
natürlich wieder vorbei. Aber solange man ja nur zwei Bytes gesendet hat
(das erste plus das nachgeladene), können auch nur zwei Bytes
reinkommen. Dann könnte man in aller Ruhe das Puferregister lesen,
wodurch das Byte aus dem Schieberegister ins Pufferregister nachrückt
und so weiter.
Ich kann aber nirgends ersehen, ob das SPI so gebaut ist. Und ehrlich
gesagt bezweifle ich es auch.
Die Vorschrift ist also strenggenommen Blödsinn oder wohlwollende
Statistik a.k.a. schnell genug sein. Hat doch im Datenblatt nix verloren
sowas.
Sven P. schrieb:> Irgendwie passt das wieder einmal mehr zum desolaten Zustand des> ARM-Ökosystems :-(
Seltsam ... die ganze Welt macht SPI mit ARM-Prozessoren und
jammert nicht rum, und bei dir ist die Kacke am dampfen.
Was will uns das sagen?
Sven P. schrieb:
> Wenn man allerdings nun ein Byte nicht rechtzeitig liest, etwa weil> ein Interrupt dazwischenkommt, dann geht dieses doch schlimmstenfalls> verloren, oder?
Nur, wenn du in deinem Interrupt mehr Zeit vertrödelst, als die
Übertragung eines Bytes benötigt.
Ist das nicht egal bei SPI? Da bestimmt der Master doch auch den Takt.
Und der kann AFAIK sich während einer Übertragung ändern. Dat hat man
doch genug Zeit, das Byte abzuholen, weil der Takt erst dann generiert
wird, wenn man das nächste Zeichen sendet.
Oder sehe ich das falsch?
Sven P. schrieb:> Man schreibt also ein Byte ("first data item") rein und das SPI beginnt> mit der Übertragung, wodurch das Pufferregister frei wird und man schon> ein Byte nachladen ("second data item") kann. Dann wartet man implizit> auf das Ende der Übertragung des ersten Bytes ("RXNE"), durch das ja> gleichzeitig auch ein Byte empfangen wurde, welches man dann lesen soll> ("first received data item"), um direkt im Anschluss wieder ein Byte zum> Versand nachzuladen.
Wenn man sich die Überschrift zu Fig. 241 im RM ansieht, ist klar, warum
das so gemacht werden soll: continuous
Schreibt man nur jeweils ein Byte ins Sende-Register und wartet auf das
RXNE, liest das empfangene Byte und scheibt erst danach das nächste Byte
ins Sende-Register, gibt's zwischen den einzelnen Bytes immer ein Pause,
aber man verpasst garantiert nichts.
> Wenn man allerdings nun ein Byte nicht rechtzeitig liest, etwa weil ein> Interrupt dazwischenkommt, dann geht dieses doch schlimmstenfalls> verloren, oder? Denn im Puffer befindet sich ja wegen der
Klar. Wenn man es so macht wie im RM beschrieben (um eben KEINE Pausen
zu haben), muss man natürlich immer
(a) rechtzeitig für Nachschub sorgen und
(b) rechtzeitig die empfangenen Daten abholen ...
Ansonsten bleibt ja der einfachere Weg, wo halt kein kontinuierlicher
Transfer stattfindet.
Die Frage ist letzlich, ob die "Gegenstelle" solche Pausen verdaut oder
sich daran verschluckt.
UweBonnes schrieb:> Warum muss es den der STM32F10x sein? Den gibt gibt es schin 10 Jahre,> und ST hat einiges an der Peripherie verbessert.
Naja, er ist halt gängig. Zumindest hatte ich den Eindruck, als ich mich
vor ca. 2 Jahren damit erstmalig beschäftigt habe und nach einem
Einstiegsmodell gesucht habe.
PittyJ schrieb:> Oder sehe ich das falsch?
Ja, siehst du. In o.g. Beispiel aus dem Reference Manual ist das nächste
Byte ja schon sendebereit. Das ist ja genau das Problem.
STM Apprentice schrieb:> Seltsam ... die ganze Welt macht SPI mit ARM-Prozessoren und> jammert nicht rum, und bei dir ist die Kacke am dampfen.
Und das macht die konkrete Peripherie samt Beschreibung im STM32F103 nun
irgendwie "gut" oder "besser"?
Das ist ja ein triviales Problem hier. Mir sind, wie ich ja schon
schrieb, diverse Lösungen dafür bekannt.
Aber es ist m.M.n. ziemlich repräsentativ dafür, wie dünn das RM ist.
Irgendwie habe ich oft das Gefühl, dass Peripherie nur grob umrissen
wird und ich vieles wirklich ausprobieren muss, wenn es um Randfälle und
so geht.
Sven P. schrieb:> Wenn man allerdings nun ein Byte nicht rechtzeitig liest, etwa weil ein> Interrupt dazwischenkommt, dann geht dieses doch schlimmstenfalls> verloren, oder? Denn im Puffer befindet sich ja wegen der> verschachtelten Prozedur laut Datenblatt schon das nächste zu> versendende Byte. Und wenn das fertig übertragen wurde, würde das> dadurch gleichzeitig empfangene Byte wieder in den Puffer geschrieben.> Damit wäre ein Byte überschrieben und verloren.
Ein Paradebeispiel von "Ich hätte gerne ein Problem".
Wenn man den SPI auf max Takt betreibt und im IRQ Fibonaccis rekursiv
berechnet dann geht das verloren.
Der SPI im F103 kann maximal 18MBit, der CPU Kern kann bis zu 72MHz.
Also pro SPI CLK verspeist die CPU 4 Befehle.
Nun sind es aber 8Bit pro SPi Übertragung, also 32 Befehle.
Wird knapp wenn da nen IRQ mit Registerstacking reinpfuscht.
Aber Volldampf senden ohne DMA war noch nie eine gute IDee, mit 1-4MHz
auf dem SPI sollts keine Probleme geben.
Also b)
Und wieso wird auf einmal vom UART gefaselt wenns eigentlich um den SPI
geht?