Forum: Mikrocontroller und Digitale Elektronik STM32H7, SPI Slave, erstes Mal nur 0er, generelles Verhalten


von Gerald M. (gerald_m17)


Lesenswert?

Hallo,

ich habe mit CubeMX einen STM32H7 als SPI Slave mit Hardware NSS 
konfiguriert.
Der Mikrocontroller misst mit 100Hz Sensoren über den ADC ein. Ein 
Raspberry kann dann "irgendwann" die Sensoren über SPI abfragen.
Die Sensorwerte werden in ein globales Struct gespeichert.
Um die Slave Funktion zu aktivieren übergebe ich vor der Main Schleife 
die Adresse des Structs an die HAL_SPI_transceive_DMA().
Nach der Übertragung starte ich um Interrupt wieder die gleiche Funktion 
mit dem gleichen Pointer.

Bisher dachte ich, dass einfach nur die Adresse genommen wird und die 
Daten von dort zum Zeitpunkt der SPI Übertragung genommen werden.
Nun ist es aber so, dass bei der ersten Übertragung tatsächlich die 
Nullen, mit denen das Array initialisiert wird, übertragen werden, 
obwohl ich in der Zwischenzeit (aber erst nach der Initialisierung) 
mehrfach neue Werte in das Struct hineingeschrieben habe.
Ist das das normale Verhalten? Gibt es eine Variante mit der ich 
wirklich die aktuellen Daten übertrage? Oder muss ich nach jeder 
Datanaktualisierung wieder die HAL_SPI_transceive_DMA Funktion 
ausführen?
Gibt es auch eine Variante, bei der ich die Funktion nur zur 
Initialisierung aufgerufen werden muss, und ab da werden immer die Daten 
bei jeder SPI Abfrage übertragen? Ich meine ich hatte das schon einmal 
im DMA_Circular Mode getestet, da hat die Funktion aber auch immer nur 
einmal die Daten übertragen.

In kurz: Gewünschtes Verhalten:
Funktionsaufruf bei dem ich die Adresse und die Länge des 
Speicherbereiches definiere. Ab dann wird bei jeder SPI-Clock das 
aktuelle Bit des Speichers übertragen, wenn die Länge des Structs 
erreicht wird geht der Pointer wieder auf die ursprüngliche Adresse 
zurück. CS brauche ich eigentlich nicht, da nur die beiden Teilnehmer 
existieren. Ich nutze ihn um zu erkennen ob gerade ein Transfer 
stattfindet, dann ändere ich die Daten natürlich nicht. Idealerweise 
würde der Pointer wieder auf die Anfangsadresse gesetzt werden wenn eine 
falling Edge am CS-Pin passiert, falls doch etwas bei der Kommunikation 
schief geht, sonst komme ich da ja nie mehr raus.

von Stefan F. (Gast)


Lesenswert?

Es ist ganz sicher nicht normal, wenn dein DMA Transfer Daten sendet, 
die gar nicht mehr im Speicher existieren. Dazu bräuchte er einen 
Zwischenspeicher, der den Zustand der Vergangenheit kennt. So einen 
Speicher gibt es nicht.

Ich würde das mal debuggen und dabei kontrollieren, wann auf welche 
Speicheradressen zugegriffen wird und ob da wirklich die erwarteten 
Daten drin stehen.

Wenn dir die Funktionsweise des Framework zu unklar ist, fällt es dir 
womöglich leichter, die Register anhand des Referenzhandbuches zu 
programmieren. Dann hast du keinen unbekannten Code dazwischen, den und 
dessen Doku du zusätzlich zur Beschreibung der Register verstehen musst. 
Selbst wenn du am Ende doch die HAL nimmst, wird es dir helfen, dich 
vorher mit den Registern und deren Möglichkeiten zu befassen.

von Harry L. (mysth)


Lesenswert?

Der H7 hat einen Cache von dem dein DMA nichts mitbekommt.
Er hat aber auch eine MPU, mit der du de Speicher, den dein DMA anpackt 
vom Caching ausnehmen kannst.

Das ist der Weg.

von Gerald M. (gerald_m17)


Lesenswert?

Stefan F. schrieb:
> Dann hast du keinen unbekannten Code dazwischen, den und
> dessen Doku du zusätzlich zur Beschreibung der Register verstehen musst.

Tatsächlich ist die HAL Funktion nicht übermäßig lang und außerdem recht 
verständlich geschrieben. Es lag auch daran:

Harry L. schrieb:
> Der H7 hat einen Cache von dem dein DMA nichts mitbekommt.

Die Lösung war zwar etwas kryptisch hier herauszulesen, aber ich habe 
nun das Struct in den D2 RAM "verschoben" und jetzt geht es tatsächlich.
Hierfür habe ich
1
__attribute__((section(".dma_buffer")))
 vor das Struct geschrieben und im Linkerfile:
1
.dma_buffer :
2
  {
3
  *(.dma_buffer)
4
  } >RAM_D2
hinzugefügt. So läuft alles im Circular Mode und ich muss nur zu Beginn 
die HAL_SPI_TransmitReceive_DMA Funktion einmal aufrufen und ab dann 
kann der Raspberry dauerhaft die Daten aufrufen.

von Kevin M. (arduinolover)


Lesenswert?

Gerald M. schrieb:
> Die Lösung war zwar etwas kryptisch hier herauszulesen, aber ich habe
> nun das Struct in den D2 RAM "verschoben" und jetzt geht es tatsächlich.

Das ist weder kryptisch noch hat es etwas mit caching zu tun. Der 
normale DMA bzw. der BDMA kommt beim H7 nicht in jeden Speicher-Bereich. 
Ein Blick ins Datenblatt / Reference Manual und man weiß das.

von J. S. (jojos)


Lesenswert?

Es kann definitiv mit dem Cache zusammenhängen, die Speicherbereiche 
werden da auch unterschiedlich behandelt.

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.