Konfigurieren Sie den SPI-Slave, um Daten zu verarbeiten, die zur falschen Zeit kommen

Ich experimentiere mit dem SPI-Protokoll (schnelle Geschwindigkeiten, bei denen 5 Bytes Daten in etwas weniger als 500 us übertragen werden) auf dem STM32F410, der als SPI-Vollduplex-Slave konfiguriert ist. Ein Master-Gerät sendet ein Befehlsbyte an den STM32F4 und der STM32F4 antwortet mit 4 Bestätigungsbytes, gefolgt von einer Routine, die bei etwa 1,3 ms (gemessen durch die DWT-Taktzykluszählung) ausgeführt wird. Es wird erwartet, dass diese 5-Byte-Datenübertragung etwa 25 bis 27 Mal pro Sekunde stattfindet.

Ich stelle fest, dass das Master-Gerät manchmal genau dieselben Daten nacheinander in einer Zeitspanne von 90 us senden kann (der STM32F4-Slave sollte damit rechnen, dass er abwechselnd Daten über SPI in einer Zeitspanne von mindestens 4 ms dazwischen empfängt). Ich habe Screenshots des Logikanalysators angehängt, die dieses Vorkommen zeigen:

Das erste empfangene 0x42-Byte ist zu erwarten, und der STM32F4-Slave hat mit den entsprechenden Bytes geantwortet (beachten Sie, dass das zweite 0x42 danach nicht mehr vorhanden sein sollte):Erster Teil des ungewöhnlichen Ereignisses

Das zweite empfangene 0x42-Byte sollte nicht aufgetreten sein (Master-Gerät kann in diesem Szenario nicht konfiguriert/programmiert werden):Zweiter Teil des ungewöhnlichen Ereignisses

Nach dem obigen Vorfall konnte der STM32F4-Slave nie wieder richtig auf das Master-Gerät antworten (die an den Master zurückgesendeten Bestätigungsbytes sind immer 0x99 – das ist das im SPI-Interrupt-Sendepuffer konfigurierte Byte):Nach einem Fehler wird die ganze Zeit eine falsche Antwort an den Master zurückgesendet

In dieser Situation habe ich versucht, den Funktionsaufruf zu entfernen __AppliSendBuff(), der einem HF-Transceiver befiehlt, Daten zu übertragen, und wenn das ungewöhnliche Ereignis eintritt, kann der STM32F4-Slave immer noch korrekt auf den Master antworten.

Meine Frage ist : Wie könnte ich die SPI-Daten ignorieren, die zu unerwarteten Zeiten vom Master kommen? Warum führt eine fehlgeschlagene SPI-Transaktion dazu, dass alle anderen zukünftigen SPI-Transaktionen fehlschlagen? Welche Vorsichtsmaßnahmen sollte ich treffen, wenn ich Code für den STM32F4-Slave schreibe?

Was ich versucht habe : Deaktivieren der SPI_CS GPIO-Interrupts, wenn der CS-Chip heruntergezogen wird, sodass die SPI-Transaktion mitten im gesamten Prozess nicht stattfindet, bis ich den SPI_CS GPIO-Interrupt wieder aktiviere. Vor dieser Änderung würde der STM32F4-Slave im zweiten empfangenen 0x42-Befehl nur 0x99 auf 0x42 und 0xFF antworten, die auf 0x42 folgen. Trotzdem schlagen alle anderen SPI-Transaktionen fehl und der Slave würde mit 0x99 antworten.

Mein STM32F4-Code :
Das Interrupt-Segment:

/*** STM32F4 INTERRUPT HANDLERS ***/

/* GPIO Interrupt Handler */
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {
   if(GPIO_Pin == SPI2_CS_PIN) {
      /* Temporarily disable SPI2 CS interrupt */
      HAL_NVIC_DisableIRQ(EXTI1_IRQn);

      /* Generate interrupt flags when master device sends SPI data */
      /* dummybyte is a uint8_t array of size 1, with the element being 0x99 */
      HAL_SPI_TransmitReceive_IT(&hspi2, (uint8_t*)dummybyte, (uint8_t*)pSpi2RxBuff, cSpi2RxLen);
   }
   else if (...) {
      ...
   }
}

/* SPI Interrupt Handler */
void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi) {
   if(hspi->Instance == SPI2) {
      if (...) {
         ...
      }
      else if(pSpi2RxBuff[0] == 0x41) {
         /* Activate 0x41 flag for further processing in main loop if 0x41 was received */
         xFlag_41 = SET;
      }
      else if(pSpi2RxBuff[0] == 0x42) {
         /* Activate 0x42 flag for further processing in main loop if 0x42 was received */
         xFlag_42 = SET;
      }
      else {
         /* Discard data by doing nothing */
      }
   }
}

Die Hauptschleife:

while (1) {
   if(xFlag_41 == SET) {
      /* Respond back to system with acknowledge bytes */
      HAL_SPI_TransmitReceive(&hspi2, (uint8_t*)pSend41Data, (uint8_t*)pTempRxBuff, cSpi2TxLen, SPI2_TIMEOUT);
      
      /* Commands RF Transceiver to transmit data respective to received command from master */
      __AppliSendBuff(&command41);

      xFlag_41 = RESET;

      /* Re-enable SPI2_CS interrupts. Note that priority was set in MX_GPIO_Init() */
      HAL_NVIC_EnableIRQ(EXTI1_IRQn);
   }
   else if(xFlag_42 == SET) {
      /* Respond back to system with acknowledge bytes */
      HAL_SPI_TransmitReceive(&hspi2, (uint8_t*)pSend42Data, (uint8_t*)pTempRxBuff, cSpi2TxLen, SPI2_TIMEOUT);
          
      /* Commands RF Transceiver to transmit data respective to received command from master */
      __AppliSendBuff(&command42);

      xFlag_42 = RESET;

      /* Re-enable SPI2_CS interrupts. Note that priority was set in MX_GPIO_Init() */
      HAL_NVIC_EnableIRQ(EXTI1_IRQn);
   }
}

Muss ich den SPI-Slave auch so konfigurieren, dass er 4 Dummy-Bytes sendet (vielleicht um die SPI-Datenregister zu leeren), falls ich ein Junk-/nicht registriertes Befehlsbyte erhalte?

Danke schön!


Update: Ich habe das Deaktivieren des CS-Line-Interrupt-Deaktivierens (das ein GPIO-Interrupt-Deaktivieren ist) ausgelassen und die Flag-Reset-Aktionen auf die erste Zeile in den Else-If-Blöcken verschoben, und es wurden einige Änderungen im Logikanalysator angezeigt (die erste richtige Sequenz war immer noch das gleiche):

Zweite falsche Reihenfolge:Zweite falsche Reihenfolge

0x41 genau nach der zweiten falschen Sequenz oben:Falsch 0x41

0x42 genau nach dem obigen 0x41 (falsche Bytes an den Master zurückgesendet):Falsch 0x42

Und alle danach ausgetauschten Bytes sind wie folgt (unabhängig von 0x41 oder 0x42):Falsche Sequenzen danach

Ich habe vergessen, die Interrupt-Prioritäten in den ursprünglichen Beitrag oben aufzunehmen:

/* SPI CS line has the highest interrupt priority */
HAL_NVIC_SetPriority(EXTI1_IRQn, 1, 0);
HAL_NVIC_EnableIRQ(EXTI1_IRQn);
/* SPI Peripheral connected to the master device */
HAL_NVIC_SetPriority(SPI2_IRQn, 1, 1);
HAL_NVIC_EnableIRQ(SPI2_IRQn);

Antworten (1)

Ich habe ein wenig Probleme zu verfolgen, was passiert ist, bevor Sie den GPIO-Interrupt hinzugefügt haben, und danach. Wenn ich das richtig verstehe, passierte Folgendes, bevor Sie es hinzufügten:

  1. Nach der ersten (korrekten) Sequenz verlassen Sie die ISR mit gesetztem xFlag_42 und landen schließlich in __AppliSendBuff(&command42).

  2. In der Mitte von __AppliSendBuff wird der Interrupt aufgrund der falschen Sequenz erneut bestätigt.

  3. Die ISR setzt den Puffer zum Senden von 0x99 und kehrt zu dem Punkt zurück, an dem sie ausgeführt wurde, bevor sie den Interrupt erhielt.

  4. Die nächste Zeile setzt xFlag_42 zurück, und danach wird 0x99 gesendet.

Das macht alles Sinn. Aus Ihrer Beschreibung geht hervor, dass nachfolgende Transaktionen ebenfalls die 0x99-Antwort erhalten würden, was für mich keinen Sinn ergibt, da das Ganze an diesem Punkt von vorne beginnen sollte.

Die Dinge werden erheblich komplizierter, wenn Sie den Interrupt hinzufügen, um den GPIO zu deaktivieren. Sie erwähnen nicht, was die Interrupt-Priorität ist, aber insgesamt haben Sie zwei ISRs, die nacheinander mit dem SPI-Puffer herumspielen, und das ist wahrscheinlich nicht das, was Sie wollen.

Sie könnten versuchen, dieses xFlag_42 = RESET zu verschieben; die erste Zeile des else if sein. Das würde dazu führen, dass das Ganze zweimal ausgeführt wird. Wenn dieses Ergebnis unerwünscht ist, können Sie ein Flag hinzufügen, das besagt, dass Sie den ersten Datenverkehr verarbeiten, und Ihre ISR so schreiben, dass sie sofort zurückkehrt, ohne etwas zu tun, wenn dieses Flag gesetzt ist.

Danke für die Antwort! Ja, genau das war passiert. Bei der zweiten falschen Sequenz antwortet der Slave mit fünf 0x99 an den Master, obwohl es eine 0x42 war. Das erste 0x99 der falschen Sequenz sollte erwartet werden, aber ich verstehe immer noch nicht, warum die anderen Bytes mit einem 0x99 zurückgeantwortet wurden, als ob der HAL_SPI_TransmitReceive_IT()mehrfach ausgeführt würde, da sich der 0x99 nur in dieser Funktion befindet.
Ich verstehe auch nicht, warum die nachfolgenden SPI-Transaktionen mit 0x99 beantwortet wurden. Es macht, wie Sie sagten, keinen Sinn, da das SPI-Datenregister durch die neuen Puffer ersetzt werden sollte. Ich habe versucht, den CS-Line-Interrupt zu deaktivieren und die Flags in die erste Zeile des else if zu verschieben, aber es gab immer noch Fehler, obwohl es einige Änderungen gab. Ich werde den Beitrag bezüglich der Interrupt-Prioritäten aktualisieren, der SPI2_CS GPIO-Interrupt ist: HAL_NVIC_SetPriority(EXTI1_IRQn, 1, 0);während die SPI-Interrupt-Priorität selbst ist:HAL_NVIC_SetPriority(SPI2_IRQn, 1, 1);
@Cimory, du löschst die Interrupts, richtig?
Die GPIO-Interrupts werden (glaube ich) automatisch durch die HAL-Bibliothek gelöscht. Die Funktion __HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin);wird ausgeführt, bevor sie in meine GPIO-Interrupt-Callback-Funktion geht. Ich bin mir nicht sicher, ob ich die SPI-Interrupts löschen soll. Sollte die Funktion __HAL_SPI_DISABLE_IT()im Inneren nicht HAL_SPI_IRQHandler()alle Interrupt-Flags löschen und die SPI-Interrupts dauerhaft deaktivieren, bis sie wieder aktiviert werden?
Gibt es Flags, die ich löschen muss, bevor ich eine neue SPI-Transaktion einleite? Ich habe auch versucht, das SPI-Peripheriegerät zu deinitialisieren, wenn eine fehlgeschlagene SPI-Transaktion durch ist, HAL_SPI_DeInit()und das SPI-Peripheriegerät erneut zu initialisieren, aber das hat nicht gut geklappt.
Entschuldigung, ich bin mir nicht sicher, ob ich die Interrupts löschen soll.
Es klingt ziemlich riskant, das Peripheriegerät aus- und wieder einzuschalten.
Ich werde versuchen, den SPI-Interrupt zu löschen - dies könnte der Grund sein, warum ich 0x99 sende, nachdem ein Fehler aufgetreten ist. Danke für den Vorschlag. Gibt es noch andere Schritte/Verfahren, die mir bei der Konfiguration des STM32 als Slave fehlen könnten?
Ich habe die Überprüfung auf aktive Flags im SPI_CS-Interrupt-Block hinzugefügt und verhindert, HAL_SPI_TransmitReceive_IT()dass er ausgeführt wird, wenn eines der Flags für die While-Schleife ist SETund die SPI-Kommunikation einwandfrei läuft. Danke für den Vorschlag und dafür, dass Sie mir geholfen haben, das Problem zu verstehen!
Großartig! Es freut mich, dass ich helfen konnte.