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-spihttp://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
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.
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
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
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.
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.
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