Forum: Mikrocontroller und Digitale Elektronik Problem mit USART beim STM32G491


von Rahul D. (rahul)


Angehängte Dateien:

Lesenswert?

Moin,
im Anhang der problematische Ausschnitt eines Programms.
Wie man vielleicht selbt erkennt, handelt es sich um einen Thread (unter 
KEIL MDK RTX) zum Kommunizieren über eine RS485-Schnittstelle.

Eigentlich geht es nur um eine der beiden "HAL_UART_Transmit_"-Zeilen.
Ich kann beliebig viele Daten empfangen, die dann von auch per MailQ an 
den Thread übertragen werden.
Dort sollen sie entweder mit einem Parser ausgewertet werden, oder falls 
dieser nicht definiert ist, einfach als Echo zurückgeschickt werden.

Das funktioniert ein Mal. Danach klappt der Empfang nicht mehr.
Ich kann aus anderen Threads Mails schicken, deren Inhalt auch jedes Mal 
versandt wird. Nur wird der Empfang dann sofort blockiert.

Wo liegt der Fehler?
Ich hatte schon alles schrittweise ein- und wieder auskommentiert - es 
blieben nur die beiden Zeilen über.
TXDMA "schalte" ich je nach Übertragungsmethode per STM32CubeMX ein oder 
aus.

Vielen Dank im Voraus!

von Harry L. (mysth)


Angehängte Dateien:

Lesenswert?

Wo ist dein Interrupt-Callback für HAL_UART_Receive_IT?

Sowas macht auch keinen Sinn:
1
while(HAL_UART_Receive_IT(usartDevice->huart, &Usart2RecvDigit, 1) == HAL_BUSY)

Die *_IT-Funktionrn werden dir nie BUSY melden.

Mir scheint, du hast das Prinzip der *_IT-Funktionen noch nicht 
verstanden.

Ich häng dir mal ein funktionierendes Beispiel für die 
UART-Kommunikation an.
Das kann man so auch unverändert mit RTOS nutzen (mach ich auch so)

: Bearbeitet durch User
von Rahul D. (rahul)


Lesenswert?

Harry L. schrieb:
> Wo ist dein Interrupt-Callback für HAL_UART_Receive_IT?

Weiter oben und funktioniert.

Harry L. schrieb:
> Die *_IT-Funktionrn werden dir nie BUSY melden.

Dann ist die Schleife ja nur überflüssig, hat aber keinen Einfluss auf 
irgendwas anderes.
Wenn man sich den Quellcode der HAL_UART_Receive_IT ansieht, kann sie 
sehr wohl HAL_BUSY zurückliefern.

Übrigens zickt auch die blocking Version "HAL_UART_Transmit(...)" 
gleichermaßen rum.

Harry L. schrieb:
> Mir scheint, du hast das Prinzip der *_IT-Funktionen noch nicht
> verstanden.

Doch, habe ich.

von Rahul D. (rahul)


Lesenswert?

So, falls sie noch jemandem fehlen sollten:
1
void USART2RxISR(UART_HandleTypeDef *huart)
2
{
3
  // ISR wird bei vollständigem Empfang der in HAL_UART_Receive_IT() angegebenen Zeichenmenge ausgeführt
4
  Usart2RecvBuffer[usartRxBufferLength[uart2Index]++] = Usart2RecvDigit;
5
  // Empfang neu starten
6
  HAL_UART_Receive_IT(&huart2, &Usart2RecvDigit, 1);
7
  timeout[uart2Index] = TIMEOUTRESETVALUE;
8
  callbackCallUsart2++;  // DEBUG
9
}
1
void USART2TxCpltCallback(UART_HandleTypeDef *huart)
2
{
3
  // ISR wird ausgeführt, wenn das TXC-Flag gesetzt wurde (der Sendepuffer wurde komplett übertragen).
4
  osSemaphoreRelease(Usart2SemaphoreId);
5
}
1
HAL_UART_RegisterCallback(DeviceStruct->Interface->UsartInterface->huart, HAL_UART_TX_COMPLETE_CB_ID, USART2TxCpltCallback);
2
HAL_UART_RegisterCallback(DeviceStruct->Interface->UsartInterface->huart, HAL_UART_RX_COMPLETE_CB_ID, USART2RxISR);

Vielleicht mache ich ein paar Kommentare zu viel, aber Cheffe sagt "50% 
des Quelltextes sind Kommentare!". ;)

: Bearbeitet durch User
von Harry L. (mysth)


Lesenswert?

Rahul D. schrieb:
> Doch, habe ich.

Nein, hast du nicht vollständig!

HAL_UART_RxCpltCallback und HAL_UART_TxCpltCallback sind bereits als 
weak-Funktion vorhanden, und weitere Callback-Funktionen zu registrieren 
ist vollkommen überflüssig.
Wichtig ist nur, direkt am Anfang zu überprüfen, ob huart zu deinem 
UART passt.

Siehe auch mein Sourcecode von oben.

von J. S. (jojos)


Lesenswert?

Harry L. schrieb:
> und weitere Callback-Funktionen zu registrieren
> ist vollkommen überflüssig.

er benutzt USE_HAL_UART_REGISTER_CALLBACKS, damit ist das ok und die 
neue, bessere Variante. Damit werden callbacks dem huart zugeordnet und 
es ist kein globaler nötig, damit auch nicht die Abfrage von welchem 
uart der call kommt.

Sonst sieht der Code eigentlich ok aus, wenn es nicht ein blödes 
Timingproblem ist.

Wieviele Token hat die Semaphore, und warum wird osSemaphoreWait da 
mehrmals direkt nacheinander aufgerufen?
EventFlags sind an der Stelle sicher einfacher.

: Bearbeitet durch User
von Rahul D. (rahul)


Lesenswert?

Harry L. schrieb:
> Siehe auch mein Sourcecode von oben.

Auf den du wohl sehr stolz bist?
Für mich sieht der aus, als wäre er "blind" von einem AVR (oder einem 
anderen 8-Bitter) portiert.
Deine putc- und puts-Routinen würde ich bspw. umgekehrt realisieren, da 
man bei HAL_UART_TRANSMIT_IT einen gewissen Overhead mitschleppt, den 
man bei deiner puts-Routine mehrfach ausführt (und sie dadurch 
eigentlich den Sinn einer non-blocking Routine verliert).
Ein putc wäre ein Spezialfall von puts, da nur ein Character übertragen 
wird.
Hast du überhaupt mein Problem verstanden?

J. S. schrieb:
> Wieviele Token hat die Semaphore, und warum wird osSemaphoreWait da
> mehrmals direkt nacheinander aufgerufen?
Das ist auch nur eine Vorsichtsmaßnahme, falls aus irgendwelchen Gründen 
doch Semaphoren aufgelaufen sein sollten. Eigentlich sollte das 
überflüssig sein.

> EventFlags sind an der Stelle sicher einfacher.
Ja, wäre eine Möglichkeit. Dazu wäre (zumindest bei Keil-RTX) die 
ThreadId in der Callback nötig. Die hängt in meinem Fall aber nicht von 
vom Thread, sondern von der Schnittstelle ab (vielleicht habe ich da 
auch noch einen Knoten im Kopf).

Das System funktioniert mit anderen Schnittstellen (I²C) einwandfrei.
Daran liegt es also nicht.
Vielleicht ist es etwas gewagt, zu sagen, dass da was am 
HAL-UART-Treiber was nicht ganz so stimmt, oder ich eben etwas dabei 
übersehen habe (Erwachsenen-ADHS lässt grüßen).

von Harry L. (mysth)


Lesenswert?

Rahul D. schrieb:
> Hast du überhaupt mein Problem verstanden?

Code lesen ist nicht so deins, oder, du bist zu arrogant, richtig hin zu 
schauen...

Das "Prinzip FIFO" kennst du?

Sorry, aber das wird mir hier zu hohl.

Viel Spass beim "frickeln"!
Im Notfall kannst du dein mangelndes Verständnis ja immer noch ST 
anlasten.

von Rahul D. (rahul)


Lesenswert?

Harry L. schrieb:
> Rahul D. schrieb:
>> Hast du überhaupt mein Problem verstanden?
>
> Code lesen ist nicht so deins, oder, du bist zu arrogant, richtig hin zu
> schauen...
Tolle Antwort...
Scheinst mein Problem aber trotzdem nicht verstanden zu haben.
>
> Das "Prinzip FIFO" kennst du?
Ja. Meine Antwort war vielleicht etwas kurz-überlegt.
Ich würde es halt anders machen.
Mache ich ja auch, indem ich eine MailQ verwende (das ist mein FIFO).

> Sorry, aber das wird mir hier zu hohl.

> Viel Spass beim "frickeln"!
ROFL
Was hat deine "Lösung" mit meinem Problem zu tun?
Vielleicht liegt das Verständnisproblem ja eher bei dir.
Wenn du dich raus- / zurückhalten möchtest: Sehr gerne.

> Im Notfall kannst du dein mangelndes Verständnis ja immer noch ST
> anlasten.
Auch ST ist nicht unfehlbar.
Ich habe oben doch meiner Meinung nach ziemlich gut den Fehler und meine 
Suche nach dem Grund beschrieben. Das scheint dich aber nicht 
interessiert zu haben. Sondern Du fingst an, dass gewisse Funktionen gar 
nicht "HAL_BUSY" liefern würden. Komisch, wenn man sich deren Quellcode 
ansieht, stellt man fest, dass sie auch ein "return HAL_BUSY;" 
enthalten.
Soviel dazu. Troll dich bitte einfach!

: Bearbeitet durch User
von Rahul D. (rahul)


Lesenswert?

Mein "Gefrickel" funktioniert.
Bei einer halbduplexen Verbindung (mit einer etwas ungewöhnlichen 
Hardware (/RE konstant auf GND)), sollte man noch den Mode umschalten; 
also entweder RX oder TX enablen, wenn man die Datenrichtung umschaltet.
Standardmäßig wird der Schnittstelletreiber vollduplex initialisiert.
Mal wieder was schön universelles "gefrickelt":
- unabhängig vom Datenprotokoll
- unabhängig von der U(S)ART-Schnittstelle
- (vermutlich) unabhängig vom STM-Controller dank HAL.
Naja, ganz unabhängig vom Controller ist es noch nicht: Die Callbacks 
sind momentan leider nicht unabhängig von der Schnittstelle (das müsste 
aber eigentlich aufgrund der dynamischen Registrierung auch möglich sein 
- wird beim nächsten Projekt vielleicht umgesetzt).

Zeit für die nächste Baustelle.

von W.S. (Gast)


Lesenswert?

Rahul D. schrieb:
> Eigentlich geht es nur um eine der beiden "HAL_UART_Transmit_"-Zeilen.

Ach nein. Es geht bei dir ganz offensichtlich darum, daß du dich nicht 
mit dem eigentlichen UART befassen willst und genau deshalb mit den 
Funktionen aus deiner HAL herumeierst. Sowas zeigt sich auch bei solchen 
Verrenkungen:

Rahul D. schrieb:
> So, falls sie noch jemandem fehlen sollten:void
> USART2RxISR(UART_HandleTypeDef *huart)...

Eine ISR mit einem Argument...

Du kämpfst die ganze Zeit mit den Seltsamkeiten der von dir benutzten 
HAL, die in Wirklichkeit keine ist, sondern lediglich eine Maßnahme, um 
Leute fest an ST zu binden, indem sie STM-spezifisches Zeug direkt in 
ihren Algorithmen verwenden.

Rahul D. schrieb:
> Mal wieder was schön universelles "gefrickelt":
> - unabhängig vom Datenprotokoll
> - unabhängig von der U(S)ART-Schnittstelle
> - (vermutlich) unabhängig vom STM-Controller dank HAL.

Wie kommst du auf sowas? Versuche mal, dein Zeugs auf einen PIC32 zu 
portieren... oder auf einen Fujitsu FR.

W.S.

von Rahul D. (rahul)


Lesenswert?

Fangen wir unten an:
W.S. schrieb:
>> - (vermutlich) unabhängig vom STM-Controller dank HAL.
>
> Wie kommst du auf sowas? Versuche mal, dein Zeugs auf einen PIC32 zu
> portieren... oder auf einen Fujitsu FR.

Diese Funktion ist vermutlich unabhängig davon, welcher 
STM32-Controller verwendet wird. Wenn man was falsch verstehen will, 
wird man schnell zumm Troll.

W.S. schrieb:
> Eine ISR mit einem Argument...
>
> Du kämpfst die ganze Zeit mit den Seltsamkeiten der von dir benutzten
> HAL, die in Wirklichkeit keine ist, sondern lediglich eine Maßnahme, um
> Leute fest an ST zu binden, indem sie STM-spezifisches Zeug direkt in
> ihren Algorithmen verwenden.

Ja, und? Warum sollten wir (als Firma) ein möglichst großes Spektrum an 
Herstellern verwenden, wenn die beiden, die wir derzeit verwenden, 
unsere Anforderungen abdecken?

W.S. schrieb:
> Ach nein. Es geht bei dir ganz offensichtlich darum, daß du dich nicht
> mit dem eigentlichen UART befassen willst und genau deshalb mit den
> Funktionen aus deiner HAL herumeierst.

Warum sollte ich mit Details beschäftigen, mit denen sich andere auch 
nicht beschäftigen (s.o. Harry's Post)?

Ich bin bei meinem Ausgangspost davon ausgegangen, dass mir jemand einen 
Hinweis geben kann, der sowas schon mal gemacht hat. Stattdessen kommen 
hier (bis auf JoJo) irgendwelche Leute, die nur rumnölen oder ihre 
"Lösung" als "das einzig Wahre" darstellen müssen.
Jetzt habe ich bewiesen, dass dem nicht so ist.
Programmiert am besten Eure arms bitte nur noch mit Mäuseklavieren und 
LED!

Edit:
Mich würde zu zu sehr interessieren, wie jemand (von den Nölis) direkt 
auf Registerebene eine universelle Funktion programmiert, die auf 
jedem 32-Bit-Controller funktioniert.

: Bearbeitet durch User
von J. S. (jojos)


Lesenswert?

W.S. ärgert sich nur das es mal wieder kein HAL Problem war. Das 
langweilt nur noch, genauso wie das HAL bashing.

Rahul D. schrieb:
> Naja, ganz unabhängig vom Controller ist es noch nicht: Die Callbacks
> sind momentan leider nicht unabhängig von der Schnittstelle (das müsste
> aber eigentlich aufgrund der dynamischen Registrierung auch möglich sein
> - wird beim nächsten Projekt vielleicht umgesetzt).

Der callback wird doch dem huart zugeordnet, und beim Aufruf auch 
mitgegeben. D.h. in deinem gezeigten Code ist doch nur das huart2 durch 
huart zu ersetzen. Und die anderen Variablen auch davon abhängig zu 
machen.
Was der HAL fehlt ist da ein UserData Pointer in den Strukturen um 
solchen cb einfacher einen Kontext mitgeben zu können.

Rahul D. schrieb:
> Mich würde zu zu sehr interessieren, wie jemand (von den Nölis) direkt
> auf Registerebene eine universelle Funktion programmiert, die auf
> jedem 32-Bit-Controller funktioniert.

Es gibt auch OS die versuchen vieles bis alles zu unterstützen, aber da 
muss man sich auch lange und tief reinarbeiten bis man das beherrscht.

: Bearbeitet durch User
von Rahul D. (rahul)


Lesenswert?

J. S. schrieb:
> Es gibt auch OS die versuchen vieles bis alles zu unterstützen, aber da
> muss man sich auch lange und tief reinarbeiten bis man das beherrscht.

Da hat man dann aber auch für jede Schnittstelle einen Treiber mit vom 
OS definierter Software-Schnittstelle.

J. S. schrieb:
> Was der HAL fehlt ist da ein UserData Pointer in den Strukturen um
> solchen cb einfacher einen Kontext mitgeben zu können.

Das fehlt nicht nur der HAL. Wäre für den Controller eine CMSIS-Library 
vorhanden (bzw. hätte ich eine gefunden), hätte es dasselbe Problem 
gegeben.

Das mit der Callback behalte ich im Hinterkopf (und den Thread in meiner 
Linksammlung).

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.