Hallo,
ich habe hier ein seltsames Problem mit STM32-Code innerhalb der
STM32CubeIDE. Der Code selbst ist mit CubeMX erzeugt. Ein Beispiel für
die Probleme:
HAL_UART_Transmit() ist eine von CubeMX erzeugte Funktion zum Senden von
Daten via UART, die Verbindung zur MCU ist mit Hilfe eines Segger JLink
hergestellt.
Mein Problem: wenn ich den Code laufen lasse oder über die Funktion
HAL_UART_Transmit() hinweg steppe, dann liefert die einen Rückgabewert
!=HAL_OK zurück, sie schlägt also fehl.
Wenn ich jetzt allerdings per Singlestepping in die Funktion hineingehe,
um nachzusehen, wo das Problem liegt, dann klappt dort drin alles
problemlos und es wird HAL_OK zurückgegeben.
Ähnlich seltsames Verhalten findet sich auch an anderen Stellen. An den
Compileroptimierungen habe ich schon herumgedreht, das ändert nichts.
Irgend eine Idee, was hier schiefläuft?
Der letzte Parameter (Timeout) ist 0. Damit wartet die Funktion nicht,
bis der UART bereit ist. Das Senden des ersten Zeichens klappt, beim
zweiten oder dritten Zeichen ist der UART-Sendebuffer noch voll und das
Senden schlägt fehl. Wenn du im Einzelschritt durchgehst, ist genug Zeit
zwischen den Aufrufen um das Zeichen zu senden.
Die Idee ist ja auch, dass er eben nicht wartet - wenn der UART beim
Aufruf schon bereit ist, soll gesendet werden, wenn nicht, eben erst
beim nächsten Durchlauf...
Ist huart->gState == HAL_UART_STATE_READY? Wenn nicht, dann mit Fehler abbrechen
2
huart->gState == busy
3
warten mit dem Timeout, bis das TXE-Flag des UART (Transmitter empty) gesetzt wird. Wenn Timeout, dann mit Fehler abbrechen
4
Zeichen in UART schreiben
5
huart->gState == ready
6
fertig
Beim Wiederholten raschen Aufruf hintereinander mit Timeout 0 ist aber
der Transmitter nicht empty, weil das vorhergehende Zeichen noch drin
ist. Damit setzt die Funktion zwar huart->gState auf busy, aber nie mehr
auf ready und alle künftigen Aufrufe schlagen fehl. Irgendwie nicht ganz
ausgegoren, ich denke Timeout sollte mindestens die zu erwartende
Übertragungszeit eines Zeichens sein.
Shinner schrieb:> Die Idee ist ja auch, dass er eben nicht wartet - wenn der UART beim> Aufruf schon bereit ist, soll gesendet werden, wenn nicht, eben erst> beim nächsten Durchlauf...
HAL_UART_Transmit ist blocking und wird immer warten, bis sie fertig mit
senden ist. Da Die Funktion davon ausgeht das sie immer fertig ist, wenn
sie am Ende ankommt, geht sie natürlich beim Aufruf davon aus das etwas
nicht stimmt wenn die Peripherie noch Busy ist oder wenn sie intern in
einen Timeout läuft.
Wenn du nicht willst das die Funktion wartet nutze HAL_UART_Transmit_IT
und mache das Handling selbst. Oder noch einfacher nutze einen DMA, dann
musst du dich gar nicht mit den einzelnen Zeichen rumschlagen.
Guest schrieb:> Oder noch einfacher nutze einen DMA, dann> musst du dich gar nicht mit den einzelnen Zeichen rumschlagen.
DMA ist für UART maximal ungeeignet, da i.d.R. nicht klar ist, wie viele
Zeichen noch folgen.
Sowas macht man via Interrupt - ohne Wenn und Aber!
Harry L. schrieb:> DMA ist für UART maximal ungeeignet, da i.d.R. nicht klar ist, wie viele> Zeichen noch folgen.
Ääääh : Er sendet ! Wenn jemand weiss, wie viele Zeichen gesendet
werden, dann er.
Und übrigens : die DMA von STM32 beherrscht Ringpuffer.
FOp schrieb:> Und übrigens : die DMA von STM32 beherrscht Ringpuffer.
Jaja...alle Jahre wieder kommt das Thema auf, und irgendwelche Noobs
behaupten, daß das mit DMA ja alles sooo viel besser ginge - nur
wirklich funktionierenden Code, der auch noch effizienter läuft als die
Interrupt-Methode hat man nie gesehen....langweilt einfach nur noch.
Beim Senden grosser Datenblöcke "kann" man DMA nutzen, aber beim
Empfangen? - besser nicht!
UART ist nun mal -aus Sicht eines modernen µC- so schnarchlahm, daß DMA
praktisch keine messbaren Vorteile bietet; dafür aber im Handling
erhebliche Nachteile hat.
Harry L. schrieb:> Beim Senden grosser Datenblöcke "kann" man DMA nutzen, aber beim> Empfangen? - besser nicht!
Da outet sich jemand der nicht programmieren kann :)
Harry L. schrieb:> Sowas macht man via Interrupt - ohne Wenn und Aber!
Du rufst vergeblich - jedenfalls in diesem Forum.
Ich hab das den Leuten schon seit Urzeiten gesagt und auch mal einen
passenden Lowlevel-Treiber für die STM32 gepostet. Es nützt nix.
Allenfalls wird man deshalb angepöbelt. Die Leute, die hier nach Hilfe
rufen, WOLLEN es genau so, wie sie es posten und wie es eben nicht geht.
W.S.
Kevin M. schrieb:> Da outet sich jemand der nicht programmieren kann
Wie gerade eben gesagt: jeder Hinweis darauf, wie es geht und was man
lieber bleiben lassen sollte, wird mit Pöbeln beantwortet.
W.S.
UART Daten mit DMA empfangen ist maximal umständlich und bringt
keinen Vorteil. Die Daten müssen ja sowieso "geholt" werden. Ob
aus dem DMA Buffer oder aus dem UART-Register ist wohl nicht
kriegsentscheidend. Dabei dürfte der Verwaltungsaufwand bei
DMA sogar noch grösser sein als das Interrupt-Handling beim
normalen Empfangen. DMA bringt beim Empfangen schon deswegen
nichts weil die Daten meist deutlich langsamer daherkommen als
der Controller fähig ist Daten zu verarbeiten.
Shinner schrieb:> Ein Beispiel für die Probleme:
Wir haben dich ja schon an anderer Stelle mit skurrilen
Problemen und Beratungsresistenz bzw. Faulheit erlebt.
Vielleicht geht das jetzt hier weiter .... wenn ich schon
von den Problemen höre. Ein Beispiel, es kommen noch
viele solche?
(Beitrag "STM32 empfängt keine SPDIF-Daten")
Bei schnellen Datenraten und mehreren UARTs gleichzeitig kanns mit
Interrupt schon eng werden. Empfang per DMA in einen Ringpuffer ist kein
Problem, und Senden der Antwort per DMA ist auch "fire and forget", da
gibts nicht viel zu verwalten. UART kann bei Empfangspause auch
Interrupt auslösen wenn man darauf reagieren will/muss. Spart jede Menge
an ISR enter/exit, das ist nicht gratis. Netto hat man mehr CPU Zeit für
andere Dinge zur Verfügung.
Du wirst doch nicht W.S. kritisieren wollen, der alleine weiß, wie es
geht.
Mir fielen diverse Varianten ein, wie man DMA auch beim Empfangen per
UART nutzen kann. Das kann mal sinnvoll sein und mal nicht. Aber wie
gesagt, es gibt Forenteilnehmer, die einfach immer Recht haben. W.S.
gehört dazu.
Shinner schrieb:> Die Idee ist ja auch, dass er eben nicht wartet - wenn der UART beim> Aufruf schon bereit ist, soll gesendet werden, wenn nicht, eben erst> beim nächsten Durchlauf...
Dann ist de Fehlercode ja von dir gewollt.