STM32 CubeMx Lib mit SPI sehr langsam?

Gast #4671248
Lesenswert?
• ▲
▼
Hallo,

ich nutze einen STM32F103, der mit 64MHz läuft (HSI mit PLL).
Dazu die SPI Lib von Cubemx:

Der Code in der Main ist simpel, und testweise das einzige das 
ausgeführt wird:
1
      if(ADS1262GetDRDY(Channel1)
2
      {
3
        if(ADS1262ReadDataCRC(Channel1, &ADC1Result, 6) == 0)
4
        {
5
[..] // Bisschen Daten kopieren
6
        }
7
      }

ADS1262GetDRDY() prüft dabei nur, ob ein GPIO gesetzt ist oder nicht. 
Die eigentliche Leseroutine sieht so aus:
1
uint8_t ADS1262ReadDataCRC(uint8_t ADCIndex, ADCRESULT *Result, uint8_t NumBytes)
2
{
3
  uint8_t ADCBytes[6], CRCValue;
4
  SPI_HandleTypeDef *pSPIHandle;
5

6
  ADCBytes[0] = 0;
7
  ADCBytes[1] = 0;
8
  ADCBytes[2] = 0;
9
  ADCBytes[3] = 0;
10
  ADCBytes[4] = 0;
11
  ADCBytes[5] = 0;
12

13
  if(ADCIndex == Channel1)
14
  {
15
    pSPIHandle = &hspi1_adc;
16
  }
17
  else if(ADCIndex == Channel2)
18
  {
19
    pSPIHandle = &hspi2_adc;
20
  }
21
  else
22
    return 1;
23
  // check for errors when calling the function
24
  if(NumBytes != 6 || Result == NULL)
25
    return 1;
26
  else
27
  {
28
    // Get the data
29
    //HAL_SPI_Init(&hspi1_adc);
30
    mADC_CS_ASSERT(ADCIndex);
31
    while(HAL_SPI_STATE_BUSY == HAL_SPI_GetState(pSPIHandle));    // wait for SPI to become free
32
    HAL_SPI_Receive(pSPIHandle, ADCBytes, 6, 2);          // receive data from ADC
33
    mADC_CS_DEASSERT(ADCIndex);
34
    CRCValue = 0xFF & (ADCBytes[1]+ADCBytes[2]+ADCBytes[3]+ADCBytes[4]+0x9B);
35
    // check for transmission errors
36
    if(CRCValue == ADCBytes[5])
37
    {
38
      Result->Status = ADCBytes[0];
39
      Result->ADCValue = (ADCBytes[1]<<24) |  (ADCBytes[2]<<16) | (ADCBytes[3]<<8) | (ADCBytes[4]<<0);
40
      Result->Checksum = ADCBytes[5];
41
      return(0);
42
    }
43
    else
44
    {
45
      return(2);
46
    }
47
  }
48
}

Die Leseroutine braucht für die 6 gammeligen Bytes geschlagene 36µs (von 
CS low bis wieder high), der SPI läuft dabei mit 8MHz.
Allein von CS low bis zum start der CLK vergehen fast 8µs, nach jedem 
Byte ca. 3µs.
Mir schein als ob diese aufgeblasene CubeMX Lib nur abartig langsam ist. 
Der STM32F103 hat Prefetch & Cache eingeschaltet, 2 Waitstates für den 
Flash wie gefordert.

Hat jemand mal Messergebnisse um vergleichen zu können? Bringt SPI mit 
DMA da was?


Danke und Grüße
Stampede
Gast #4790140
Lesenswert?
• ▲
▼
Stampede schrieb:
> Die Leseroutine braucht für die 6 gammeligen Bytes geschlagene 36µs (von
> CS low bis wieder high), der SPI läuft dabei mit 8MHz.
> Allein von CS low bis zum start der CLK vergehen fast 8µs, nach jedem
> Byte ca. 3µs.
...

> Mir schein als ob diese aufgeblasene CubeMX Lib nur abartig langsam ist.
Das habe ich auch festgestellt.

Das ist kein Wunder, wenn man sich mal den HAL-Code anschaut.
In HAL_SPI_Transmit werden:
- irgendwelche Parameter gecheckt
- die SPI-Resource gelockt
- ein Timeout initialisiert
- geguckt, ob überhaupt Daten zum Verschicken da sind
- diverse Daten im Handle aktualisiert
- ggf. nochmal im Konfigurationsregister geschrieben
- ggf. CRC initialisiert
- ggf. das SPI enabeld
- nach der Breite des Datentransfer geschaut (8 Bit/16 Bit)
- und yeah Daten ins Datenregister des SPI geschrieben
- auf das TXE-Flag gewartet
- das Overrun-Flag zurückgesetzt
- Timeout und andere Fehlerfälle behandelt
- ggf. CRC aktualisiert
- und die SPI-Resource wieder freigegeben


> Der STM32F103 hat Prefetch & Cache eingeschaltet, 2 Waitstates für den
> Flash wie gefordert.
Ich glaube das hat da gar nicht so viel Einfluss.
Ich hatte hier testweise die Taktfrequenz von 8 MHz auf 16 MHz erhöht 
(CM4).
Die Übertragung auf der Leitung war immer noch wesentlich kürzer, als 
das Ganze drumherum.

> Hat jemand mal Messergebnisse um vergleichen zu können? Bringt SPI mit
> DMA da was?
Die Zeit zwischen zwei Bytes mit
1
  HAL_SPI_Transmit( &TFT_SPI_Handle, &data, 1, 1);
betrug irgendwas um die 50 µs.

Ich habe den ganzen Overhead aus dem HAL weggelassen und jetzt nur noch 
den relevanten Teil dastehen:
1
  // warten bis frei
2
  while((( TFT_SPI_Handle.Instance->SR) & SPI_FLAG_TXE) != SPI_FLAG_TXE);
3
  // Datum rausballern
4
  TFT_SPI_Handle.Instance->DR = data;
5
  // Overflowbit zurücksetzen, ohne dem gings irgendwie nicht
6
  TFT_SPI_Handle.Instance->SR &= ~( SPI_FLAG_OVR);
Damit wurde der Abstand zwischen den Datenbytes auf ca. 2 µs reduziert.

Die Initialisierung mit HAL_SPI_Init und HAL_SPI_MspInit habe ich 
gelassen.
Der Einsatz von DMA könnte natürlich auch noch was bringen.

Mir reicht das oben erreichte.

Wolf
Gast #4790149
Lesenswert?
• ▲
▼
CubeMX bietet für jede Peripherie (SPI, I2C, ADC, DAC .. usw.) immer 3 
Modi an: polling, IRQ, DMA. Polling ist das langsamste, DMA das 
schnellste. Du verwendest Polling. Verwende DMA und du wirst sehen, das 
die selbe SPI Hardware mit CubeMX ca 8x so schnell wird.

Gruß,

dasrotemopped.
Gast #4790225
Lesenswert?
• ▲
▼
Ja...die HAL rührt reichlich Mehraufwand ein. Der Vorteil der HAL soll 
eine bessere Portierbarkeit zwischen verschiedenen Mikrocontrollern 
ermöglichen-behauptet zumindest ST.

Ich persönlich finde die CubeMX zwar an sich eine wirklich gute Idee, 
bin von der HAL aber auch nicht allzusehr begeistert. Die meisten 
Funktionen, die eigentlich mit ein oder zwei Whileschleifen und einem 
einfachen Kopierbefehl erschlagen werden könnten arten in der HAL zu 
riesigen Code-Romanen aus.
Gast #4804215
Lesenswert?
• ▲
▼
dasrotemopped schrieb:
> Du verwendest Polling. Verwende DMA und du wirst sehen, das
> die selbe SPI Hardware mit CubeMX ca 8x so schnell wird.

So das habe ich jetzt mal gemacht. Und damit ich nicht mit dem Scope 
stoppen muss, lass ich den STM auch gleich ausrechnen, wie schnell der 
Transfer erledigt wird.
Randbedingungen: STM32F4xx, 16 MHz Systemtakt, 8 MHz SPI-Takt
theoretisches Maximum: 1 MByte/s
Test: 4 Rechtecke auf einem ILI9341-Display (320x240, 16-Bit-Farbe) 
einfarbig einfärben
Dabei werden reichlich 150 KByte zum Display geschickt.

Hier die Ergebnisse:
1
HAL, polling mode            50 kByte/s
2
HAL, interrupt mode         100 kByte/s
3
zu Fuss (siehe oben)        315 kByte/s
4
HAL, DMA mode               991 kByte/s
5
HAL, DMA + Rest zu Fuss     997 kByte/s
Dabei fragt man sich, warum STM beim DMA-Counter zu geizig war und nur 
16 Bit (statt z.B. 24) verbaut hat. So musste ich den DMA-Transfer 
unnötigerweise splitten.

Danke nochmal für den Anschubser, sonst hätte ich das sicher nicht 
weiter optimiert.

Wolf

Antwort schreiben

Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt. Bitte hier nur auf die ursprüngliche Frage antworten, für neue Fragen einen neuen Beitrag erstellen.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.