Forum: Mikrocontroller und Digitale Elektronik Wie Stm32 SPI-DMA Kommunikation zw. 2 Boards (CubeMX)?


von SPI-Neuling (Gast)


Angehängte Dateien:

Lesenswert?

Hallo zusammen :)

Ich arbeite mich zur Zeit in die Konfiguration der STM32 Mikrocontroller 
mit der ST Software CubeMX ein.

Bis jetzt gelang mir die Inbetriebnahme von Timer, ADC und DAC auch sehr 
problemlos.

Daher wollte ich jetzt ein STM32F4 Discovery Board via SPI mit einem 
STM32F0 Discovery Board verbinden und die Kommunikation via DMA ablaufen 
lassen.
Leider stehe ich hier vor einem Problem und weiß nicht recht wieso es 
nicht funktioniert.

Kurz zum Setup:
Das F4 Board wurde so konfiguriert, dass SPI im Full-Duplex-Master Modus 
betrieben wird. Weiterhin habe ich an den Pusbutton ein Interrupt gelegt 
in dessen ISR ein trigger Bit gesetzt wird.
Die Konfiguration des SPI und des DMA sind dem angehängten Bild 
F4_Cubesettings.png zu entnehmen. Alle anderen Einstellungen habe ich 
auf den Defaultwerten von CubeMX gelassen.

Das F0 Board wurde als Full-Duplex-Slave initialisiert. Hier wurde 
lediglich SPI und DMA aktiviert. Einstellungen sind dem Bild 
F0_Cubesettings.png zu entnehmen.

Um zu gucken wie man generell SPI über DMA einstellt habe ich mir 
weiterhin diese beiden Tutorials durchgelesen:
http://blacbird.de/tutorial-stm32-cubemx-spi
http://microtechnics.ru/en/stm32cube-spi-and-dma-example/

Anschließend habe ich probiert einen ähnlichen Code zu schreiben und 
habe die beiden Boards verbunden (jeweils MISO Board 1 mit MOSI Board 2 
und vice versa sowie die SCLK Pins).

Die main-Routinen der beiden Boards sehen dabei wie folgt aus:

SPI Master Board F4:
1
 /* USER CODE BEGIN 2 */
2
3
  //Array für zu sendende Daten
4
  uint8_t data[2];
5
  data[0] = (uint8_t) 5;
6
  data[1] = (uint8_t) 10;
7
8
9
  /* USER CODE END 2 */
10
11
  /* Infinite loop */
12
  /* USER CODE BEGIN WHILE */
13
  while (1)
14
  {
15
  /* USER CODE END WHILE */
16
          //Pin zur Visualisierung des Betriebs
17
    HAL_GPIO_TogglePin(GPIOD,GPIO_PIN_14);
18
19
    if(trigger == 1)
20
    {
21
      HAL_SPI_Transmit_DMA(&hspi1,data,(uint16_t) 2);
22
      trigger = 0;
23
      HAL_GPIO_TogglePin(GPIOD,GPIO_PIN_13);
24
    }
25
  /* USER CODE BEGIN 3 */
26
  }
27
  /* USER CODE END 3 */

SPI Slave Board F0
1
 /* USER CODE BEGIN 2 */
2
3
  //Array für die empfangenen Daten
4
  uint8_t rec[2];
5
  rec[0] = (uint8_t) 10;
6
  rec[1] = (uint8_t) 20;
7
8
  //Variablen fürs Tracing
9
  view = rec[0];
10
  view2 = rec[1];
11
  /* USER CODE END 2 */
12
13
  /* Infinite loop */
14
  /* USER CODE BEGIN WHILE */
15
  while (1)
16
  {
17
  /* USER CODE END WHILE */
18
19
  /* USER CODE BEGIN 3 */
20
21
    HAL_Delay(250);
22
    HAL_SPI_Receive_DMA(&hspi1,rec,2);
23
    view3 = rec[0];
24
    view4 = rec[1];
25
    if (view3==5)
26
    {
27
      HAL_GPIO_WritePin(GPIOC,GPIO_PIN_7,GPIO_PIN_SET);
28
    }
29
    HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_8);
30
  }
31
  /* USER CODE END 3 */

Die Variablen view sind dabei global deklariert und dienen dem tracing 
via STM-Studio.

In den jeweiligen SPI Callback-Funktionen
void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi)
void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi)
wird eine der LEDs getoggelt um zu sehen ob eine Übertragung 
stattgefunden hat.

Jetzt zu meinem Problem:
Auf der Sender-Seite sieht der ganze Vorgang erfolgreich aus.
Auf der Empfänger-Seite hingegen, erhalte ich nach der ersten 
Übertragung für rec[0] und rec[1] nur die Werte 0xFF.
Die Ergebnisse für den Start des Programms sowie nach der ersten 
Transmit-Aktion des Masters sind in Bild tracing.png dargestellt.

Es kommt mir so vor als würde irgend ein SPI Buffer voll laufen, doch 
leider kann ich diesbezüglich nichts ausfindig machen.
Da ich mit der HAL-Library auch noch nicht so versiert bin und weiterhin 
mit SPI auch noch nicht viel gemacht habe, fällt mir das Suchen auch 
doppelt schwer.

Daher meine Frage:
Hat jemand einer Vermutung woran es beim Empfang scheitern könnte 
(vermutlich übersehe ich etwas fundamentales)?
Ich lade bei Bedarf gerne auch weitere Codezeilen oder die 
CubeMX-Projekte hoch.

Und kann mir jemand erklären wie genau die 
HAL_SPI_Receive_DMA(&hspi1,rec,2) Funktion arbeitet?
Liest sie einfach nach Aufruf den SPI-Empfangsbuffer aus und schreibt 
das Ergebnis in den übergebenen Speicherbereich oder wartet sie so lange 
im Hintergrund, bis der Master eine Kommunikation beginnt.
Falls ersteres, wie wird dann genau bestimmt wann die 
Completion-Callback-Funktion aufgerufen wird.

Ich wäre wirklich sehr dankbar wenn mir jemand etwas Licht ins dunkel 
bringen könnte. Alle Beispiele die ich finde für CubeMX und SPI-DMA 
behandeln das Board meist nur als Sender und nicht auch als Empfänger,

Schon mal vielen Dank vorab,

Viele Grüße
SPI-Neuling

von Gerald M. (gerald_m17)


Lesenswert?

SPI-Neuling schrieb:
> (jeweils MISO Board 1 mit MOSI Board 2 und vice versa sowie die SCLK
> Pins).

MISO heißt: "Master In Slave Out"
Da steckt schon im Namen dass MISO an MISO angeschlossen werden muss. 
Nicht wie bei UART.

Habe mehr von deinem Text nicht gelesen, falls du darauf schon Bezug 
genommen hast.

von SPI-Neuling (Gast)


Lesenswert?

Hallo und vielen Dank für die Antwort :)

Oh man das war es tatsächlich, irgendwas muss ich da mächtig 
durcheinander geworfen haben, ist mir jetzt fast schon peinlich extra 
einen Beitrag hier aufgemacht zu haben :(

Aber vielen Dank für den Hinweis... ich werde in Zukunft genauer 
Nachlesen :)

Noch einen schönen Abend,

SPI-Neuling

von SPI-Neuling (Gast)


Lesenswert?

Hallo zusammen :)

Ich bin doch noch auf ein Problem gestoßen...

Nachdem ich die Leitungen richtig verbunden hatte funktionierte alles 
einwandfrei.

Jetzt wollte ich allerdings nicht nur Daten an das Slave-Board senden, 
sondern auch eine Antwort synchron erhalten.
Daher änderte ich auf beiden Boards die jeweiligen Transmit- bzw. 
Receive-Funktion zu der HAL_SPI_TransmitReceive_DMA(&hspi1,data,rec,2) - 
Funktion.

Diese scheint allerdings nicht so zu funktionieren wie ich dachte.

Während auf dem Slave Board, jedes mal wenn ich eine Transaktion über 
den Button (Master Board) auslöse, die Daten korrekt empfangen werden, 
erhalte ich auf dem Master Board im Empfangsarray nur den Wert 0.

Verringere ich die Zeit in der die TransmitReceive-Funktion auf dem 
Slave-Board ausgeführt wird von 250ms auf 25ms, erhalte ich zwar einen 
Wert != 0 allerdings, für beide gesendeten Bytes den gleichen Wert 
(unterschiedliche werden gesendet).

Lösche ich die Wartezeit komplett, erhalte ich für beide gesendeten 
Bytes des Slave Boards die korrekten Werte.

Ich hätte jetzt vermutet, dass auch bei der TransmitReceive-Funktion auf 
dem Slave-Board so lang gewartet wird, bis der Master die Kommunikation 
auslöst.

Könnte mir jemand erläutern wieso sich dieses Verhalten einstellt?

Code des Slave Boards:
1
 /* USER CODE BEGIN WHILE */
2
  while (1)
3
  {
4
          //Bei 250ms wird vom Master nur 0,0 empfangen, bei 25ms nur 9,9
5
          // und ohne das Delay werden korrekt die 9,7 empfangen.
6
    HAL_Delay(25);
7
    data[0] = (uint8_t) 9;
8
    data[1] = (uint8_t) 7;
9
    HAL_SPI_TransmitReceive_DMA(&hspi1,data,rec,2);
10
    view3 = rec[0];
11
    view4 = rec[1];
12
    view = data[0];
13
    view2 = data[1];
14
    if (view3==5)
15
    {
16
      HAL_GPIO_WritePin(GPIOC,GPIO_PIN_7,GPIO_PIN_SET);
17
    }
18
    HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_8);
19
  }
Code des Master Boards:
1
while (1)
2
  {
3
     HAL_GPIO_TogglePin(GPIOD,GPIO_PIN_14);
4
5
    if(trigger == 1)
6
    {
7
      HAL_SPI_TransmitReceive_DMA(&hspi1,data,rec,2);
8
      trigger = 0;
9
      HAL_GPIO_TogglePin(GPIOD,GPIO_PIN_13);
10
      view = rec[0];
11
      view2 = rec[1];
12
    }
13
  }

Es würde mich freuen wenn mir hier noch jemand weiterhelfen könnte :)

Viele Grüße
SPI-Neuling

von Darth Moan (Gast)


Lesenswert?

Moi,

SPI-Neuling schrieb:
> Lösche ich die Wartezeit komplett, erhalte ich für beide gesendeten
> Bytes des Slave Boards die korrekten Werte.

Ueberrascht dich das wirklich?
(Ich meine das nicht boese.)
Der Master ist nunmal der Master. Er bestimmt, wann gesendet wird.
Der Slave muss genau dann antworten, wenn de Mater sein Daten
"rausclockt". Das Delay im Slave bewirkt, dass der Slave in dieser
zeit nichts empfangen kann. Und somit auch nicht antworten kann.
Der Slave muss immer auf die SPI lauschen. Staendig.
Es sei denn si haben ausgemacht, das nur zu ganz bestimmten zeiten
kommuniziert wird. Dazu muessen aber beide synchronisiert werden.

von Darth Moan (Gast)


Lesenswert?

Also ich gehe jetzt natuerlich davon aus, dass der Slave die SPI auch
als Slave konfiguriert. Sonst sollte es aber schwer sein, ueberhaupt
was korrektes zu empfangen, aber man weiss ja nie. Zufaelle gibts,
die gibts eigentlich gar nicht.

von SPI-Neuling (Gast)


Lesenswert?

Hallo und danke für die Antwort :)

Zuerst, ja SPI ist auf dem Slave-Board auch als Slave konfiguriert.

Das Prinzip hatte ich auch so verstanden. Ich dachte allerdings, dass 
bedingt durch DMA quasi intern ein Interrupt abläuft wenn der Master die 
Kommunikation herstellt.

Ich konnte das Projekt jetzt auch weitestgehend zum laufen bekommen.
Einer der Fehler war, dass der Taster nicht entprellt war und mehrere 
SPI-Anfragen geschickt hat, der Slave allerdings noch, wie du 
geschrieben hattest, sich im Delay befand und deshalb nicht antworten 
konnte.

Habe die TransmitReceive-Funktion jetzt in das TxRxCmplt. Callback des 
Slaves gepackt. Jetzt krieg ich auch immer die richtige Antwort wenn ich 
beim Master eine Kommunikation veranlasse.

Also Danke nochmals für den Hinweis :)

VG
SPI-Neuling

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.