Forum: Mikrocontroller und Digitale Elektronik Probleme beim STM32H743 & SPI


von Dirk (Gast)


Lesenswert?

Hallo,
hat jemand eine Funktionierendes Beispiel wo auf dem STM32H743 V die SPI 
läuft?

Ich habe inzwischen X Versionen aus dem Internet und aus CubeMX getestet 
und keine sendet auch nur ein Bit. Einige der Beispiele nehmen auch 
rücksicht auf den BUG in der SPI, aber es geht trozdem nicht.
Ich hatte auch die Clock im verdacht, aber alle Bits sind richtig 
gesetzt, Der Code komme auch aus CubeMX (8MHz extern 480MHz intern).


Ich will immer ein Byte senden & empfangen, Fullduplex, Master an 
B12/13/14 CS auf B10.
Eigentlich auf einem STM32F0/1/3/4 kein Problem, nur auf dem H7 will das 
ganze überhaupt nicht laufen.

Wenn Jemand eine kleines Beispiel Program hat, wo nur die Clock und die 
SPI eingestellt wird, sowie eine While Schleife mit einem Transfer wäre 
ich recht dankbar. Wenn das ganze dann noch unter LIBOPENCM3 oder auf 
Registerebene gemacht ist wäre noch besser.

Ich hoffe das jemand so was hat.
Viele Grüsse, Dirk

von Thomas T. (runout)


Lesenswert?

Der STM32H743 ist schon ganz schön "anders"...

Hatte auch Probleme bei der SDIO-Schnittstelle.
STM32F4 ging auto-of-the-box. H7 -> problem problem

Was benutzt du für ein Board?
Ein Nucleo-144 (H743) ging nicht, ein Disco-Board schon.

Die H7 haben wohl mehrere Power-Domains die richtig versorgt werden 
wollen.
Hast du Oszi-Bilder von deinen SPI/CS-Signalen?

Grüße
runout

von Johannes S. (Gast)


Lesenswert?

ja, das SPI ist beim H7 (und U5 afaik) komplett anders. Der HAL Code 
funktioniert aber, habe den aber nur indirekt in Mbed benutzt. Wenn das 
mit den LL Makros benutzt wird es komplizierter, da spielt die 
Reihenfolge eine Rolle. Beim H7 kann man einige Register oder Bits nicht 
ändern wenn das device enabled ist, wird von STM als Feature verkauft.

von Michael (Gast)


Lesenswert?

Du hast eventuell einen Fake bekommen

von Dirk (Gast)


Lesenswert?

Ja diese Feature kenne ich inzwischen.
Aber das ist halt etwas mit dem ich leben könnte, wenn ich dann mal was 
habe was arbeitet.


Ich habe eine eigene Platine, da war vor 2 Wochen noch ein STM32F407 
drauf!
Prozesor arbeit, alle RAM Bereiche arbeiten, GPIO gehen, Sysclock und 
FREERTOS arbeiten.
Also im Grunde geht "alles" bis auf einige Hardware Funktionen.


Bilder gibt es keine, weil sich nichts tut. Ein saubers 3,3V oder GND 
Signal hilft irgendwie nicht.

Ich habe mir immer den LL Code erzeugen lassen, den HAL Code kann ich 
mir gleich mal ansehen.
Ich habe um weiter zu kommen ersteinmal eine Software SPI eingebaut, das 
ist ja zum Gück noch machbar als Master.

Ich hoffe das ich mit den Seriellen, DMA, I²S und DCMI nicht auch noch 
Probleme bekomme.

von Dirk (Gast)


Lesenswert?

Einen Fake direkt von ST, das bezweifel ich mal stark.

von m.n. (Gast)


Angehängte Dateien:

Lesenswert?

Für SPI1 (PB3 - PB5, PB7 = SS) beim H73x/H75x und byteweise Übertragung.
SPI-Knecht ist ein TDC7200.

von Michael (Gast)


Lesenswert?

Dirk schrieb:
> Einen Fake direkt von ST, das bezweifel ich mal stark.

Wie stark? Bitte Angabe in MPa oder MN

von Johannes S. (Gast)


Lesenswert?

Der H7 ist einfach eine zickige Diva, die devices sind mit den vielen 
Modi sehr komplex geworden. Zum SPI gibt es noch
AN5543 und
www.st.com/content/ccc/resource/training/technical/product_training/grou 
p0/52/17/7a/28/2b/90/41/7d/STM32H7-Peripheral-Serial_Peripheral_interfac 
e_SPI/files/STM32H7-Peripheral-Serial_Peripheral_interface_SPI.pdf/_jcr_ 
content/translations/en.STM32H7-Peripheral-Serial_Peripheral_interface_S 
PI.pdf

von Dirk (Gast)


Lesenswert?

Die 2 Dokumente kenne ich schon, die sind fürs Marketing nett nur um 
Fehler zu finden helfen sie mir nicht.
Das mit der diva kann ich inzwischen bestätigen.
Da hätte ich mich vorher mal besser informiert. Aber jetzt muss es damit 
laufen egal wie.

Der Code für den 750 passt nicht, der hat anscheinend nicht den Fehler 
mit dem takt. Jedenfalls sehe ich dazu nix.

Wenn jemand also einen passenden Code für die spi hat wäre es sehr 
hilfreich für mich.

von m.n. (Gast)


Lesenswert?

Dirk schrieb:
> Der Code für den 750 passt nicht, der hat anscheinend nicht den Fehler
> mit dem takt. Jedenfalls sehe ich dazu nix.

Daran erkennt man den Profi!

von Gerald M. (gerald_m17)


Lesenswert?

CubeMX hat mir für den H7 direkt einen funktionierenden SPI Code 
geliefert. Egal ob via DMA, Interrupt oder pollen.
Man muss nur die entsprechende HAL-Funktion aufrufen und gegebenenfalls 
eine Callbackfunktion definieren.

Edit: War aber für den H753.

: Bearbeitet durch User
von mr. mo (Gast)


Lesenswert?

Dirk schrieb:
> Einige der Beispiele nehmen auch
> rücksicht auf den BUG in der SPI, aber es geht trozdem nicht.

Welcher Bug isn das?

von Dirk (Gast)


Lesenswert?

Die spi hat Probleme wenn der Systemtakt sehr viel größer ist wie der 
spi takt. Da gibt es dann einige Möglichkeiten das zu umgehen. Und das 
ist dann halt leich zu erkennen wenn es im Code steht.

Außerdem ist es nicht gerade einfach alles einzustellen, eine falsche 
Reihenfolge und das wars.
Denn hal Code konnte ich mir noch nicht richtig ansehen, nur ein wenig 
und habe da auf den ersten Blick nicht sehen können was die anders 
machen wie ich.

Habe gerade den crc getestet und musste feststellen das die svd? Datei 
defekt war (falsche Adresse),wenn ich jetzt wüsste wo ich die schon 
wieder her habe.

von mr. mo (Gast)


Lesenswert?

Dirk schrieb:
> Die spi hat Probleme wenn der Systemtakt sehr viel größer ist wie der
> spi takt. Da gibt es dann einige Möglichkeiten das zu umgehen. Und das
> ist dann halt leich zu erkennen wenn es im Code steht.

Dank dir für die Auskunft. Solche Probleme sind mir beim STM32H745 noch 
nicht untergekommen. Ich habe ebenfalls SPI laufen, benutze aber nicht 
die HAL, sondern nur LL und Register.

Der größte Unterschied der mir aufgefallen ist, dass man fürs SPI 
explizit angeben muss, welche Taktquelle benutzt wird. Im Cube sollte 
das der Konfigurator eigentlich automatisch machen. Bei mir macht dies 
folgende Zeile.
1
LL_RCC_SetSPIClockSource(LL_RCC_SPI123_CLKSOURCE_PLL1Q); // 192 MHz

Bei der Übertragung im Polling Mode muss man einiges mehr machen, z. B. 
angeben wie viele Bytes man übertragen möchte bzw. noch einige Flags 
clearen. Folgenden Schnipsel verwende ich.
1
void LL_SPI::readWrite(uint8_t* rx, uint8_t* tx, uint32_t n)
2
{
3
  LL_SPI_Enable(spi);
4
  LL_SPI_StartMasterTransfer(spi);
5
  LL_SPI_SetTransferSize(spi, n);
6
7
  for (auto i = 0; i < n; ++i)
8
  {
9
    while (!LL_SPI_IsActiveFlag_TXP(spi));
10
    LL_SPI_TransmitData8(spi, tx[i]);
11
    while (!LL_SPI_IsActiveFlag_RXP(spi));
12
    rx[i] = LL_SPI_ReceiveData8(spi);
13
  }
14
15
  while (!LL_SPI_IsActiveFlag_EOT(spi));
16
  LL_SPI_ClearFlag_EOT(spi);
17
  LL_SPI_ClearFlag_TXTF(spi);
18
  LL_SPI_Disable(spi);
19
}

Bei der Initialisierung des SPI gibts es lediglich die Besonderheit 
(gabs glaube ich auch beim F7), dass man den Schwellwert fürs FIFO 
korrekt einstellen muss. Für 1 Byte verwende ich folgende Funktion, das 
geht auch im Konfigurator.
1
LL_SPI_SetFIFOThreshold(spi, LL_SPI_FIFO_TH_01DATA);

Vielleicht hilft dir das als Orientierung.

von m.n. (Gast)


Lesenswert?

Dirk schrieb:
> Die spi hat Probleme wenn der Systemtakt sehr viel größer ist wie der
> spi takt.

Das steht ja in den Errata der H7xx. Was "sehr viele größer als" sein 
soll allerdings nicht.

Dann stell den SPI-Takt einfach höher ein oder lass die Beine per 
Software wackeln. Aber mecker hier nicht rum, wenn andere Leute Deine 
Probleme nicht haben.

Gerald M. schrieb:
> CubeMX hat mir für den H7 direkt einen funktionierenden SPI Code
> geliefert. Egal ob via DMA, Interrupt oder pollen.
> ...
> Edit: War aber für den H753.

Das ist unerheblich.

von Peter M. (pm4812)


Angehängte Dateien:

Lesenswert?

ich wärme den Thread mal auf, weil mir die Antwort von Mr. Mo geholfen 
hat mein Problem mit SPI Master TxRx auf einem H7A3 zu lösen. Der H7 ist 
in der Tat recht zickig, ich habe 2 Tage rumgewürgt bevor ich Code, der 
auf dem G4 einwandfrei lief auf dem H7 zum Laufen gebracht habe.

Voraussetzungen: ich verwende die LL API und lasse den Code mit CubeMX 
erzeugen. Nucleo STM32H7A3Zi @280 MHz, SPI2 an PLL3P @160 MHz, SPI 
Prescaler = 8 (=20 MBit/s). 8 Bit, Motorola, MSB First, KEIN CRC, 
Hardware NSS. DMA1 Stream 2 für RX, DMA1 Stream 3 für TX - beide 
"Normal" mit Memory Increment.

Meine Implementierung:
Der DMA wird einmalig initialisiert - ich nutze den SPI2 und die 
DMA-Channels ausschließlich für diesen einen Zweck, darum brauche ich 
diese grundlegende Initialisierung nur einmal:
1
  /* SPI Config:
2
   * Frame Format:       Motorola
3
   * Data Size:         8 Bits
4
   * First Bit:         MSB First
5
   * Baud-Rate:         20 MBit/s
6
   * Clock Polarity (CPOL):  Low
7
   * Clock Phase (CPHA):    1 Edge
8
   * NSSP: Enabled
9
   * NSS: Output Hardware
10
   *
11
   * DMA Config:
12
   * SPI2 Rx: DMA1 Stream 2 - Normal - Byte
13
   * SPI2 Tx: DMA1 Stream 3 - Normal - Byte
14
   */
15
16
  IPC_SPIcfg.hSPI = SPI2;
17
  IPC_SPIcfg.rxDMA = DMA1;
18
  IPC_SPIcfg.rxCh = LL_DMA_STREAM_2;
19
  IPC_SPIcfg.txDMA = DMA1;
20
  IPC_SPIcfg.txCh = LL_DMA_STREAM_3;
21
22
  // Configure RX
23
  // LL_DMA_ConfigAddresses(DMA, DMA Channel, Source Addr, Dest Addr, Direction)
24
  LL_DMA_ConfigAddresses(
25
      IPC_SPIcfg.rxDMA,                  // DMA Peripheral
26
      IPC_SPIcfg.rxCh,                  // DMA Channel
27
      LL_SPI_DMA_GetRxRegAddr(IPC_SPIcfg.hSPI),      // Source Address
28
      (uint32_t)RxData,                  // Destination Address
29
      LL_DMA_GetDataTransferDirection(          // Direction
30
          IPC_SPIcfg.rxDMA,
31
          IPC_SPIcfg.rxCh));
32
33
  // Configure TX
34
  // LL_DMA_ConfigAddresses(DMA, DMA Channel, Source Addr, Dest Addr, Direction)
35
  LL_DMA_ConfigAddresses(
36
      IPC_SPIcfg.txDMA,                  // DMA Peripheral
37
      IPC_SPIcfg.txCh,                  // DMA Channel
38
      (uint32_t)TxData,                  // Source Address
39
      LL_SPI_DMA_GetTxRegAddr(IPC_SPIcfg.hSPI),      // Destination Address
40
      LL_DMA_GetDataTransferDirection(          // Direction
41
          IPC_SPIcfg.txDMA,
42
          IPC_SPIcfg.txCh));
43
44
  // LL_RCC_SetSPIClockSource(LL_RCC_SPI123_CLKSOURCE_PLL3P);

Zum Senden / Empfangen der Daten verwende ich folgende Funktion:
1
uint8_t IPC_send(void) {
2
  // @brief  send stream data
3
  // @params  none, void
4
  // @return  u8 status: 0=ok
5
6
  static MEAS_values_TDS * pTx = NULL;
7
  if(pTx == TxData) pTx = TxData + 1;
8
  else pTx = TxData;
9
  uint32_t txAddr = (uint32_t)pTx;
10
11
  *pTx = MEAS_values;
12
13
  static uint8_t * pRx = NULL;
14
  if(pRx == RxData) pRx = RxData + HalfBufSize;
15
  else pRx = RxData;
16
  uint32_t rxAddr = (uint32_t)pRx;
17
18
  // Note: see RM0468 Rev 3 - page 2219
19
  // Chapter 55.4.14: Communication using DMA
20
21
  LL_DMA_SetMemoryAddress(IPC_SPIcfg.rxDMA, IPC_SPIcfg.rxCh, rxAddr);            // set RxBuffer Address
22
  LL_DMA_SetDataLength(IPC_SPIcfg.rxDMA, IPC_SPIcfg.rxCh, HalfBufSize);          // set Rx Size
23
24
  LL_DMA_SetMemoryAddress(IPC_SPIcfg.txDMA, IPC_SPIcfg.txCh, txAddr);            // set TxBuffer Address
25
  LL_DMA_SetDataLength(IPC_SPIcfg.txDMA, IPC_SPIcfg.txCh, HalfBufSize);          // set Tx Size
26
27
  LL_SPI_EnableDMAReq_RX(IPC_SPIcfg.hSPI);                        // enable Rx DMA
28
  LL_DMA_EnableStream(IPC_SPIcfg.rxDMA, IPC_SPIcfg.rxCh);                  // enable RX DMA stream
29
  LL_DMA_EnableStream(IPC_SPIcfg.txDMA, IPC_SPIcfg.txCh);                  // enable TX DMA stream
30
  LL_SPI_EnableDMAReq_TX(IPC_SPIcfg.hSPI);                        // enable Tx DMA
31
32
  LL_DMA_EnableIT_TC(IPC_SPIcfg.rxDMA, IPC_SPIcfg.rxCh);                  // enable Transfer Complete IRQ
33
  LL_DMA_EnableIT_TE(IPC_SPIcfg.rxDMA, IPC_SPIcfg.rxCh);                  // enable Transfer Error IRQ
34
35
  // LL_SPI_EnableMasterRxAutoSuspend(IPC_SPIcfg.hSPI); -> disabled, not for Full duplex TxRx!
36
  LL_SPI_Enable(IPC_SPIcfg.hSPI);
37
  LL_SPI_StartMasterTransfer(IPC_SPIcfg.hSPI);
38
  LL_SPI_SetTransferSize(IPC_SPIcfg.hSPI, HalfBufSize);
39
40
  return(0);
41
}

Und der DMA Transfer Complete / Transfer Error Interrupt Handler sieht 
so aus:
1
void IPC_DMA1Str2_IRQHandler(void) {
2
  // @brief  DMA1 Stream 2 IRQ Handler
3
  // @params  none, void
4
  // @return  none, void
5
6
  // Note: see RM0468 Rev 3 - page 2219
7
  // Chapter 55.4.14: Communication using DMA
8
9
  LL_DMA_DisableStream(IPC_SPIcfg.txDMA, IPC_SPIcfg.txCh);    // Disable DMA (Tx)
10
  LL_DMA_DisableStream(IPC_SPIcfg.rxDMA, IPC_SPIcfg.rxCh);    // Disable DMA (Rx)
11
  LL_SPI_Disable(IPC_SPIcfg.hSPI);                // Disable SPI
12
  LL_SPI_DisableDMAReq_TX(IPC_SPIcfg.hSPI);            // Remove DMA (Tx)
13
  LL_SPI_DisableDMAReq_RX(IPC_SPIcfg.hSPI);            // Remove DMA (Rx)
14
15
  LL_DMA_DisableIT_TC(IPC_SPIcfg.rxDMA, IPC_SPIcfg.rxCh);
16
  LL_DMA_DisableIT_TE(IPC_SPIcfg.rxDMA, IPC_SPIcfg.rxCh);
17
18
  DBG_ipc_itctr[0]++;
19
20
  if(LL_DMA_IsActiveFlag_TC2(IPC_SPIcfg.rxDMA)) {
21
    LL_DMA_ClearFlag_TC2(IPC_SPIcfg.rxDMA);
22
    DBG_ipc_itctr[1]++;
23
  }
24
25
    if(LL_DMA_IsActiveFlag_TE2(IPC_SPIcfg.rxDMA)) {
26
    LL_DMA_ClearFlag_TE2(IPC_SPIcfg.rxDMA);
27
    DBG_ipc_itctr[2]++;
28
  }
29
}

Was ich NICHT bestätigen kann ist, dass man explizit angeben muss, 
welche Clock SPI1-3 verwenden. Das habe ich im CubeMX "Clock Setup" 
erledigt. Ich verwende PLL3P, die ich auf 160 MHz eingestellt habe, 
während der Core auf 280 MH7 läuft.
1
 LL_RCC_SetSPIClockSource(LL_RCC_SPI123_CLKSOURCE_PLL1Q); // 192 MHz
 habe ich also NICHT gebraucht

Was ich noch nicht wirklich sagen kann ist: wie sich die 
FIFO-Einstellungen auswirken. Ich bin jetzt erst mal froh, dass die 
Daten von Nucleo 1 auf Nucleo 2 geschickt werden, wirklich Plan von dem 
ganzen Thema habe ich selber noch nicht, ist mein erstes Projekt mit 
einem H7.

Mein Fehler war - und das war der Punkt an dem der Post von mr.mo 
geholfen hat, dass ich die beiden Zeilen
1
  LL_SPI_StartMasterTransfer(IPC_SPIcfg.hSPI);
2
  LL_SPI_SetTransferSize(IPC_SPIcfg.hSPI, HalfBufSize);
vergessen hatte. Ohne die beiden Zeilen nach
1
 LL_SPI_Enable(IPC_SPIcfg.hSPI);
 kommt sofort der Transfer Error Interrupt.

Anmerkung: "HalfBufSize" ist "sizeof(MEAS_values_TDS)" = 40 Byte; Der Rx 
und Tx Buffer sind doppelt so groß wie die Transfer-Size, ich nutze 
abwechselnd den High- und den Low-Buffer. Noch nicht implementiert ist, 
die Behandlung der empfangenen Daten. ATM schau ich nur mit dem Scope, 
ob was gesendet wird.

von Wastl (hartundweichware)


Angehängte Dateien:

Lesenswert?

Peter M. schrieb:
> ich wärme den Thread mal auf

tldr

Aufgrund deiner langen Zugehörigkeit zum Forum solltest du
elementare Dinge beim Posten bereits wissen und dementsprechend
umsetzen.

Ja, dein Sourcecode ist länger.

von Peter M. (pm4812)


Lesenswert?

falls du Admin / Mod bist: dann lösche meinen Beitrag und diese Antwort 
bitte.

Und ich hatte noch überlegt, ob ich das auf Stack Overflow poste, aber 
ne, hab ich mir gedacht, bringst du auch hier mal etwas Content rein, 
nach dem die Leute lange suchen müssen. Und was kommt: ein 
Reichsbedenkenträger der einen anscheißt weil der Post zu lang ist. So 
sind wir halt in Deutschland ...

nächstes mal poste ich wieder da, wo es willkommen ist, wenn man den 
Code direkt sieht und direkt über die Suchmaschine finden kann.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Wastl schrieb:
> Ja, dein Sourcecode ist länger.

Das sehe ich etwas anders. Der gepostete Sourcecode besteht aus 3 
Teilen, wobei jeder dieser Teile gerade noch eine Bildschirmseite 
unterschreiten. Von daher finde ich das noch okay. Das als 3 Anhänge zu 
posten (darauf liefe es hinaus), halte ich für übertrieben.

Peter M. schrieb:
> falls du Admin / Mod bist: dann lösche meinen Beitrag und diese Antwort
> bitte.

Dazu sehe ich keinen Anlass. Der Begriff "längerer Sourcecode" trifft 
nach meiner Meinung auf Deinen Beitrag nicht zu. Da gibt es ganz andere 
Kaliber.

> nächstes mal poste ich wieder da, wo es willkommen ist,

Schließe bitte nicht von einem auf viele. Das wäre ein Fehler.

: Bearbeitet durch Moderator
von Peter M. (pm4812)


Lesenswert?

Frank M. schrieb:

> Schließe bitte nicht von einem auf viele. Das wäre ein Fehler.

ok. Case Closed

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.