Die SPI-Kommunikation zwischen STM32F4 und Rasberry Pi produziert Müll

Ich versuche, eine SPI-Kommunikation zwischen einem RPi (als MASTER) und einem STM32F410 (als SLAVE, auf einem Nucleo-Board) herzustellen. Mein PoC ist einfach, ich sende 8 Bytes vom Rpi und drucke sie mit dem UART-over-USB auf dem Nucleo aus. Hier ist der Sendecode (in Python), der auf dem Rasberry Pi läuft:

spi = spidev.SpiDev()
spi.open(0, 0)
spi.max_speed_hz = 8000000
to_send = [1,2,3,4,5,6,7,8]
#spi.writebytes(to_send)
spi.xfer(to_send)

und der Empfangscode auf dem STM32:

while(1) {
    memset(buf, 0, BRAIN_COM_BUF_SIZE);
    HAL_SPI_Receive(&hspi5, (uint8_t*)&buf, BRAIN_COM_BUF_SIZE, HAL_MAX_DELAY);
    sprintf((char*) dbg_buffer, "[%d][%d][%d][%d][%d][%d][%d][%d]\r\n", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);
    HAL_UART_Transmit(&huart2, dbg_buffer, strlen((char const*) dbg_buffer), 1000);
}

und mein SPI-Initialisierungscode (generiert von CubeMX):

/* SPI5 init function */
void MX_SPI5_Init(void)
{

  hspi5.Instance = SPI5;
  hspi5.Init.Mode = SPI_MODE_SLAVE;
  hspi5.Init.Direction = SPI_DIRECTION_2LINES;
  hspi5.Init.DataSize = SPI_DATASIZE_8BIT;
  hspi5.Init.CLKPolarity = SPI_POLARITY_LOW;
  hspi5.Init.CLKPhase = SPI_PHASE_1EDGE;
  hspi5.Init.NSS = SPI_NSS_SOFT;
  hspi5.Init.FirstBit = SPI_FIRSTBIT_MSB;
  hspi5.Init.TIMode = SPI_TIMODE_DISABLE;
  hspi5.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  hspi5.Init.CRCPolynomial = 15;
  if (HAL_SPI_Init(&hspi5) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }
}

Nichts Besonderes, oder? Dies ist eine reine Eins-zu-Eins-Kommunikation, aber ich habe den CS-Pin trotzdem eingestellt und konfiguriert. Mein Problem mit diesem Code ist, dass er höchstens in 5 % der Fälle wie IDK funktioniert. Den Rest der Zeit bekam ich Müll oder noch schlimmer, es sieht so aus, als hätte die Funktion HAL_SPI_Receive() absolut nichts bekommen.

Beispiel für aktuelles Verhalten:

Ich sende: [1][2][3][4][5][6][7][8] und der STM32 empfängt: [0][0][1][1][2][2] [3][3]

Alle Hinweise und/oder Hilfe, um mich freizuschalten, werden sehr nützlich sein, danke!

Sie müssen den /CS-Pin sogar mit nur einem einzigen Gerät verwenden, da er der Schlüssel zum Framing ist. Darüber hinaus ist Ihre Frage fehlerhaft, weil Sie sagen, dass sie "Müll produziert", aber keine Details zu diesem Müll angeben. Wir haben also keine Möglichkeit zu wissen, ob es sich um verschobene Bits in Werten oder Nicht-ASCII-Zeichen handelt, die eher auf etwas wie einen Pufferüberlauf im STM32-Programm hinweisen.
Wenn ich zum Beispiel sende: [1][2][3][4][5][6][7][8][0][0][0][0][0][0]. ][0][0] Ich bekomme: [0][1][2][3][4][5][6][7][8][0][0][0][0 ][0][0][0]
Haben Sie überprüft, ob die Phase für beide Geräte in Ordnung konfiguriert ist?
ja, Polarität niedrig und Flanke der Phase 1

Antworten (1)

Das /CSSignal wird sogar mit nur einem einzigen Peripheriegerät benötigt, da es der Schlüssel zum Erreichen der Wortsynchronisation zwischen Sender und Empfänger ist – der Empfänger weiß, dass der erste Takt nach dem /CSLow-Pegel dem ersten Datenbit im Wort entspricht. Da SPIes sich bei einer synchronousSchnittstelle typischerweise um eine minimale Taktfrequenz handelt, interpretiert der Empfänger ohne Synchronisation einfach den ersten Takt, den er sieht (zu einem Zeitpunkt, zu dem er nach einem sucht), als Beginn eines Wortes.

Alternative Schemata, bei denen der Beginn eines Wortes durch eine Zeitlücke in der Taktung angezeigt wird, sind möglich, aber das sind sie nicht wirklich, SPIund Ihr Code unternimmt keinen Versuch, so etwas zu implementieren. Kritisch, wenn es jemals zu einer Fehlkoordinierung kommt, z. B. wenn der Sender erneut sendet, während der Empfänger nach einem abgelaufenen Empfangsversuch noch damit beschäftigt ist, eine serielle Ausgabe zu erzeugen oder zu recyceln, kann es durchaus sein, dass er damit beginnt, Bits aus dem falschen Taktzyklus zu empfangen.

Und selbst wenn Sie am Ende nicht mit verschobenen Bits in einem Wort enden, können Sie immer noch mit verschobenen Wörtern in einer Nachricht enden.

Schließlich müssen Sie bei der Kommunikation auf Binärebene zwischen unterschiedlichen Systemen, die verschiedene Sprachen verwenden, darauf achten, dass sie kompatible Datencodierungen verwenden. Python verfügt über Funktionen zum Packen binärer Datenobjekte in so ziemlich jeder gewünschten Kombination aus Elementgröße und Endianness. Es wäre gut, diese zu verwenden, um explizit die Kompatibilität mit dem Datentyp herzustellen, als den der STM32 die empfangenen Informationen interpretiert.

Es wird vermutlich in fast jedem Beispiel für den Peripheriemodus behandelt. Ich persönlich hatte noch keine Notwendigkeit, die STM32-SPI-Engine in einem anderen als dem Master-Modus zu verwenden.
Wenn dies jetzt zu Ihrer Frage geworden ist, müssen Sie sie bearbeiten und zur Essenz der geposteten Frage machen. Wenn Sie dies tun möchten, lösche ich dies und lasse jemanden eine Antwort auf die überarbeitete Frage geben. Bis zu einem gewissen Grad ist es jedoch nicht wirklich eine Frage, die Sie stellen sollten, bis Sie zumindest versucht haben , die Antwort selbst zu finden. Wie wäre es also, wenn Sie sich die Beispiele für den SPI-Peripheriemodus ansehen?
Ok, nvm, CS hinzugefügt. Nichts Neues unter der Sonne damit. Wenn ich [1][2][3][4][5][6][7][8] sende, bekomme ich [0][0][1][1][2][2][3] [3] ...
Funktioniert es jetzt nicht mehr vollständig, wenn Sie es /CSaktiviert lassen, es aber trennen und hoch binden? Wenn nicht, haben Sie die Dinge nicht wirklich davon abhängig gemacht. Es sieht auch so aus, als ob Sie wahrscheinlich einen Rückgabewert der Lesefunktion auf Erfolg überprüfen sollten oder wie viele Bytes empfangen wurden. Und die "Verdopplung" ist auch verdächtig für eine andere Art von Softwareproblem.
Wenn ich den CS auf hoch gebunden habe, ist der Inhalt mehr Müll (zum Beispiel erhalte ich jetzt [128][0][0][64][2][0][0][6]). Was den Rückgabecode der Lesefunktion betrifft, bekomme ich "HAL_OK", also ist alles in Ordnung
Wenn Sie überhaupt etwas mit /CS high bekommen , dann haben Sie entweder /CS noch nicht auf dem Empfänger aktiviert oder Ihr Code ignoriert den Lesefehler , der aus einer von /CS abhängigen peripheren SPI-Implementierung resultieren müsste sieht es nie.
Auf dem STM32 (Slave) habe ich jetzt: hspi5.Init.NSS = SPI_NSS_HARD_INPUT;und den entsprechenden Code in HAL_SPI_MspInit(), der von CubeMX generiert wurde. Kann ich sonst noch etwas tun? Oh, und ich habe vorhin einen Fehler gemacht, mit CS, das auf STM32 (Slave) an HIGH gebunden ist, habe ich tatsächlich nichts gelesen. Sieht so aus, als ob auf STM32 alles in Ordnung ist, also ... Python-Seite?
Ich habe ein Szenario erstellt, in dem ich ein 16-Byte-Paket mit 1,2,3 ... 15,16 von einem Arduino oder einem Raspberry Pi an den STM32F4 sende und überprüfe, ob der Inhalt noch korrekt ist (1,2,3. .16). Ich bekomme 16-17% "korrekte" Pakete ... Ich habe eher etwas, das überhaupt nicht funktioniert, weil dies bedeuten würde, dass ich in die falsche Richtung gehe. Aber hier ... es funktioniert "ein bisschen", und ich verstehe das nicht ... (und warum natürlich ...)
Ich würde empfehlen, dass Sie die while () -Schleife loswerden und dies zu einem One-Shot-Test nach dem Zurücksetzen machen, bei dem Sie den Empfänger vor dem Sender starten, um Verwirrung zwischen "Ende von einem und Beginn des nächsten" zu vermeiden. Versuchen Sie, die explizite Binärverpackung von python struct zu verwenden, damit Sie genau wissen, was Sie senden. Und erwägen Sie, sich ein digitales Oszilloskop des Basismodells oder sogar nur einen billigen USB-Logikanalysator zu besorgen. Vielleicht auch Backup, um nur ein einzelnes Byte zu senden und sicherzustellen, dass Sie 100% Erfolg haben. Stellen Sie dann sicher, dass Sie zwei senden können, ohne sie jemals falsch anzuordnen usw.
Ich erreiche nur einen 100%igen Paketempfang, indem ich das Hardware-NSS deaktiviere und DMA verwende (da ich es nicht wirklich brauche, in einem seltsamen hausgemachten "Blockiermodus"): Ja, das ist irgendwie hässlich / nutzlos HAL_StatusTypeDef ret = HAL_SPI_Receive_DMA(&hspi5, (uint8_t*)&buf, BRAIN_COM_BUF_SIZE); while (HAL_SPI_GetState(&hspi5) != HAL_SPI_STATE_READY) {}und aber es funktioniert... Warum? Das ist in der Tat eine gute Frage...
Das funktioniert wahrscheinlich nur, weil Sie das Experiment in einer koordinierten Reihenfolge starten und nicht als etwas, auf das Sie sich verlassen können. Auch hier müssen Sie die Auswahlleitung verwenden oder einen Echtzeit-Lückenalgorithmus implementieren.
Ich verstehe das, aber die Verwendung der CS-Leitung produziert Müll, ich weiß nicht, was ich hier tun soll.
Sehen Sie sich eines der Beispiele an, wie vor Tagen vorgeschlagen
Beispiele? Wo ?
Von ST natürlich. Siehe ihre Website. Wahrscheinlich entweder in dem Download, in dem Sie die HAL-Bibliotheken erhalten haben, oder in einem anderen daneben verfügbaren.