STM32-code behaves weird

Gast #7342949
Lesenswert?

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:

1
if (bufferPos<bufferSize)
2
{
3
   if (HAL_UART_Transmit(&huart2,&feedback_buffer[bufferPos],1,0)==HAL_OK)
4
   {
5
      bufferPos++;
6
   }
7
}
8
else bufferPos=0;

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?

#7342961
Lesenswert?

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.

#7342999
Lesenswert?

Wenn ich mir den Code von HAL_UART_Transmit ansehe (kurz gegoogelt, https://www.disca.upv.es/aperles/arm_cortex_m3/llibre/st/STM32F439xx_User_Manual/stm32f4xx__hal__uart_8c_source.html )

dann macht der (bei Bufferlänge 1) im Wesentlichen:

1
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.

Gast #7343044
Lesenswert?

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.

#7343572
Lesenswert?

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.

Gast #7352846
Lesenswert?

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.

Gast #7355775
Lesenswert?

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.

Gast #7355799
Lesenswert?

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.

#7387701
Lesenswert?

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!

Entschuldigung aber das ist Unsinn. Höhere Baudraten gehen ohne DMA gar nicht vernünftig, außer man macht mit der MCU nichts anderes.

Man muss allerdings wissen wie das mit dem DMA funktioniert. Der DMA macht den Transfer vom RAM zum Peripheral, d.h. wenn der DMA Done interrupt kommt, ist er mit dem Transfer fertig, das heißt nicht dass der UART fertig ist mit dem Senden.

Damit das sauber funktioniert muss in der DMA Done ISR gecheckt werden, ob der UART mit dem Senden fertig ist, wenn nicht muss der TXC Interrupt enabled werden und erst wenn der fertig gekommen ist, ist die Übertragung beendet.

Bei dem STM Microcontroller den ich verwendet haben (STM32WLE) kommt noch dazu, dass er nach dem Aufwachen aus dem Step2 Mode seine Peripheral Registerwerte für den UART und den DMA „vergessen“ hat und diese nach dem wake-up wieder hergestellt werden müssen.

Gruß Andreas

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren