Forum: Mikrocontroller und Digitale Elektronik STM32F411 Callback wird nicht aufgerufen


von Moot S. (mootseeker)


Lesenswert?

Hallo Zusammen,

Ich habe aktuell ein Problem mit dem USART. Ich versuche Daten über 
USART1 mit dem DMA zu empfangen und in einer Variable abzuspeichern.

Die Variabel befindet sich in einer Struktur, welche wie folgt aussieht:
1
typedef struct
2
{
3
  uint8_t mb_rx_buffer[BUFFER_MAX_LEN];
4
  uint8_t mb_tx_buffer[BUFFER_MAX_LEN];
5
  uint8_t mb_cmd_available;
6
}st_modbus;

Den DMA Starten tu ich mit der folgenden Funktion im Init:
1
state = HAL_UART_Receive_DMA(&huart1, pst_modbus->mb_rx_buffer, 100);

Im UART Callback möchte ich mir ein Flag setzten um im Code die Daten 
aus dem Buffer zu holen:
1
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
2
{
3
  st_modbus *pst_modbus = &gst_modbus;
4
5
  if(huart->Instance == USART1)
6
  {
7
    pst_modbus->mb_cmd_available = 1;
8
  }
9
}

Nun das Problem:
Ich komme nie in die Funktion. Auch wenn ich im Interrupt handler einen 
Break Point setzte kommt er nie dort durch.

Hat da jemand eine Idee was ich flasch mache?

: Bearbeitet durch User
von glaskugel betrachter (Gast)


Lesenswert?

Moot S. schrieb:
> Hat da jemand eine Idee was ich flasch mache?

Zunächst mal dass du nicht den ganzen Code zeigst. Und dann
kann man rätselraten ob du Interrupts an diversen Ecken und
Enden enablest, sonst wirst du auch keinen Interrupt-
Handler angesprungen bekommen .....

von Moot S. (mootseeker)


Lesenswert?

glaskugel betrachter schrieb:
> Zunächst mal dass du nicht den ganzen Code zeigst.

Sorry Link vergessen. Hier der Link zum Projekt:
https://github.com/MootSeeker/12273.Transportlogger/tree/master/Firmware/12273.Transportlogger

von Moot S. (mootseeker)


Lesenswert?

Was mich auch zufrieden stellen würde, wäre wenn der Interrupt 
funktionieren würde ohne DMA. Das Problem da ist, dass der IRQ-Handler 
aufgerufen wird aber der Callback nicht.

von pegel (Gast)


Lesenswert?

Wenn die cb Funktion durch viele Bedingungen nicht aufgerufen wird,
schreib eine Eigene und rufe die im IRQ-Handler auf.

Deshalb gibt es dort einen USER CODE Bereich.

Es ist keine Pflicht nur die vorgegebenen HAL Funktionen zu verwenden.

von Kevin M. (arduinolover)


Lesenswert?

Du musst neben dem DMA Interrupt auch den global Interrupt des benutzten 
USART aktivieren, sonst wird das nicht funktionieren.

von Moot S. (mootseeker)


Lesenswert?

Ich habe nun meine Callback Funktion in den Interrupt des DMA platziert.
Den Code auf Github habe ich nun geupdated.

Die Funktion wird aufgerufen, aber danach stehen keine Daten in meinem 
RX-Buffer.

von W.S. (Gast)


Lesenswert?

Moot S. schrieb:
> Die Funktion wird aufgerufen, aber danach stehen keine Daten in meinem
> RX-Buffer.

Wie bedauerlich.

Wieso kommst du nicht von selbst auf die Idee, das Ganze tatsächlich 
verstehen zu wollen oder dir ein sinnvolles Interface zwischen einem 
UART-Treiber und dem Rest der Firmware auszusuchen? Sowas gibt es ja 
seit Adam&Eva, da brauchst du es nur zu verstehen und mußt es dir nicht 
selbst ausdenken.

Und nein, ich geb dir hier keinen zum x-ten Mal wiederholten Ratschlag, 
denn dazu gibt es in diesem Forum schon genug. Da mußt du nur selbst 
ein wenig lesen.

W.S.

von JS (Gast)


Lesenswert?

W.S. schrieb:
> Und nein, ich geb dir hier keinen zum x-ten Mal wiederholten Ratschlag,

Danke. Möchte keiner mehr hören und die rants gegen STMCube/HAL erst 
recht nicht.

von JS (Gast)


Lesenswert?

der DMA kann nicht in alle Speicher schreiben, z.B hat der F4 CCM wo der 
DMA keinen Zugriff hat, liegt der RxBuffer evtl. im CCM?

von JS (Gast)


Lesenswert?

ok, der F411 hat keinen CCM, im Linkerfile gibt es auch nur die eine 
SRAM Section, das ist es also auch nicht.
Stimmen die seriellen Parameter? Die ISR macht auch eine ausführliche 
Fehlerbehandlung und evtl. werden die Daten wegen falschem Format nicht 
gespeichert. Das wäre auch eine Erklärung warum der RxComplete Callback 
nicht aufgerufen wurde. Dieser generierte HAL Code funktioniert 
mittlerweile sehr gut, typische Fehler sind nicht den kompletten Code zu 
benutzen (ISR vergessen), Callbacks in C++ Modulen ohne extern, Buffer 
im nicht für DMA zugänglichen Speicher.

von pegel (Gast)


Lesenswert?

JS schrieb:
> liegt der RxBuffer evtl. im CCM?

Nein, ist beim github Projekt im Linker Script nicht angegeben.

Wenn ich Interrupt und Variable höre, muss ich automatisch an volatile 
denken.

von Moot S. (mootseeker)


Lesenswert?

JS schrieb:
> ok, der F411 hat keinen CCM, im Linkerfile gibt es auch nur die eine
> SRAM Section, das ist es also auch nicht.
> Stimmen die seriellen Parameter? Die ISR macht auch eine ausführliche
> Fehlerbehandlung und evtl. werden die Daten wegen falschem Format nicht
> gespeichert. Das wäre auch eine Erklärung warum der RxComplete Callback
> nicht aufgerufen wurde. Dieser generierte HAL Code funktioniert
> mittlerweile sehr gut, typische Fehler sind nicht den kompletten Code zu
> benutzen (ISR vergessen), Callbacks in C++ Modulen ohne extern, Buffer
> im nicht für DMA zugänglichen Speicher.

Ja Parameter stimmen alle. Der Buffer liegt in einem Struct, auf das 
sollte der DMA mit dem Struktur Pointer zugriff haben.

pegel schrieb:
> Wenn ich Interrupt und Variable höre, muss ich automatisch an volatile
> denken.

Ja dachte ich auch mal, hatte aber nichts gebraucht, gibt nur ein 
warning:
 warning: passing argument 2 of 'HAL_UART_Receive_DMA' discards 
'volatile' qualifier from pointer target type [-Wdiscarded-qualifiers]

von Εrnst B. (ernst)


Lesenswert?

Moot S. schrieb:
> Ja dachte ich auch mal, hatte aber nichts gebraucht, gibt nur ein
> warning:

Macht ja auch keinen Sinn, die DMA-Engine schreibt das ganz an 
CPU&Compiler vorbei in den RAM, der Compiler hat also gar keine 
Möglichkeit, da über volatile&co irgendwas an der DMA-Arbeitsweise zu 
ändern.

Beim Auslesen der Daten im C-Code hingegen kann es einen Unterschied 
machen, muss aber schon ein ganz "spezielles" Konstrukt sein.
z.B. wenn man den DMA-Buffer statt Interrupt per Polling überwachen 
will.

von Kevin M. (arduinolover)


Lesenswert?

Kevin M. schrieb:
> Du musst neben dem DMA Interrupt auch den global Interrupt des benutzten
> USART aktivieren, sonst wird das nicht funktionieren.

.....

Oder hast du die mittlerweile aktiviert? War in dem Cube File jedenfalls 
nicht der Fall.

von Moot S. (mootseeker)


Lesenswert?

Kevin M. schrieb:
> Oder hast du die mittlerweile aktiviert? War in dem Cube File jedenfalls
> nicht der Fall.

Ja habe ich aktiviert. Habe auch denk Code im GitHub aktualisiert

von W.S. (Gast)


Lesenswert?

JS schrieb:
> Danke. Möchte keiner mehr hören und die rants gegen STMCube/HAL erst
> recht nicht.

Ja, das sehe ich. Um Hilfe rufen und sich zugleich die Augen und Ohren 
zuhalten. Naja, auch damit kann man den Traffic hier erhöhen, wie man 
gerade sieht.

W.S.

von Moot S. (mootseeker)


Lesenswert?

Ich konnte das Problem lösen.
Leider habe ich mich auf dem MCU etwas verlesen, anstelle von 
STM32F411RCT6 habe ich STM32F411RET6 gelesen.

Dies entdeckte ich, als mein Beispiel auf dem Nucleo mit dem RET6 
funktionierte aber auf meiner eigenen Schaltung mit dem RCT6 nicht.

Naja nun funktioniert mein vorgehen, danke für eure Vorschläge und Zeit 
:)

von Nop (Gast)


Lesenswert?

Εrnst B. schrieb:

> Macht ja auch keinen Sinn, die DMA-Engine schreibt das ganz an
> CPU&Compiler vorbei in den RAM

Und genau deswegen sollte das volatile sein, weil das dem Compiler sagt, 
daß es sich auf nicht-programmatische Weise ändern könnte.

> der Compiler hat also gar keine
> Möglichkeit, da über volatile&co irgendwas an der DMA-Arbeitsweise zu
> ändern.

Er sollte aber wissen, daß er bestimmte Optimierungen nicht machen darf.

von Εrnst B. (ernst)


Lesenswert?

Nop schrieb:
> Und genau deswegen sollte das volatile sein, weil das dem Compiler sagt,
> daß es sich auf nicht-programmatische Weise ändern könnte.

Aber nur an der Stelle, wo es ausgelesen wird, nicht da wo der Pointer 
an die DMA-Engine übertragen wird.

Und auch beim Auslesen braucht's es nur, wenn der Compiler irgendeine 
reale Möglichkeit hat den Speicherzugriff wegzuoptimieren.

Beim DMA-Complete Callback ist das nicht der Fall. Da ist der "DMA 
Complete", d.H. während dein Callback ausgeführt wird, erfolgen keine 
weiteren Schreibzugriffe an der CPU vorbei. Zum anderen erfolgt der 
Aufruf des Handlers indirekt aus der Library, insofern kann und darf 
der Compiler keinerlei Annahmen treffen, was bei Eintritt in den Handler 
im RAM steht.

Wie geschrieben, es gibt ein paar Sonder-/Grenzfälle, wo ein "volatile" 
nötig sein könnte. Aber beim 08/15 Vorgehen: DMA-Start und im 
Cplt-Handler Buffer auslesen, ist es überflüssig.

von Nop (Gast)


Lesenswert?

Εrnst B. schrieb:
> Zum anderen erfolgt der
> Aufruf des Handlers indirekt aus der Library, insofern kann und darf
> der Compiler keinerlei Annahmen treffen, was bei Eintritt in den Handler
> im RAM steht.

Doch, das darf er, denn auch wenn das eine andere translation unit ist, 
gilt der C-Standard immer noch. Die andere Frage ist, ob er denn kann - 
und das ist jedenfalls mit LTO durchaus denkbar. Jedenfalls ist es 
sauberer Stil, an solche Buffer dann auch das volatile dazuzuschreiben.

von Εrnst B. (ernst)


Lesenswert?

Nop schrieb:
> Doch, das darf er

Bei einer Nicht-Inlinebaren Funktion, die per Funktionspointer in einer 
Struct ausgeführt wird?

Selbst wenn du davon ausgehst, dass irgendein hyperintelligenter 
Compiler das in der Zukunft kann, ist "volatile" für den ganzen Buffer 
an der Stelle overkill.
Eine simple compiler barrier ( asm volatile ("" ::: "memory") ) am 
Anfang des Handlers erfüllt denselben Zweck, aber raubt dem Compiler 
nicht alle Optimierungsmöglichkeiten innerhalb des Handlers selber.
Und ändert (Stand jetzt) absolut nichts am erzeugten Maschinencode.

: Bearbeitet durch User
von Nop (Gast)


Lesenswert?

Εrnst B. schrieb:

> Bei einer Nicht-Inlinebaren Funktion, die per Funktionspointer in einer
> Struct ausgeführt wird?

Ja, darf er, weil das nach Standard keine Rolle spielt.

> Selbst wenn du davon ausgehst, dass irgendein hyperintelligenter
> Compiler das in der Zukunft kann

Das Können ist ja eine ganz andere Frage - aber es gibt einiges an 
altem, nicht konformem C-Code, der mit den damals laxeren Compilern 
lief, aber mit heutigen nicht mehr. Und eben aus solchen Erfahrungen bin 
ich da vorsichtig.

> Eine simple compiler barrier ( asm volatile ("" ::: "memory") ) am
> Anfang des Handlers erfüllt denselben Zweck

Ja, das ist für diesen Fall eine gute Idee, weil sich während des 
Handlers nichts mehr ändert.

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.