Forum: Mikrocontroller und Digitale Elektronik Verständnisfrage STM32 GPIO maximale Frequenz


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Peter H. (peter_hilleb)


Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hallo, ich mal wieder.

Ich habe die Clock so wie im Bild ersichtlich konfiguriert.

Nun verwende ich folgenden Code:
1
while(1)
2
{
3
  HAL_GPIO_TogglePin(SpiClk_GPIO_Port, SpiClk_Pin); 
4
  HAL_GPIO_TogglePin(SpiClk_GPIO_Port, SpiClk_Pin);
5
}

Wenn ich nun entsprechenden Ausgang am Oszi messe toggelt der mit ca 660 
kHz.
Ich hätte mir da eigentlich deutlich mehr erwartet, oder ist das normal?

Danke für jeden Hinweis!

Hier noch der generierte Code von CubeMx:
1
void SystemClock_Config(void)
2
{
3
4
  RCC_OscInitTypeDef RCC_OscInitStruct;
5
  RCC_ClkInitTypeDef RCC_ClkInitStruct;
6
7
    /**Initializes the CPU, AHB and APB busses clocks 
8
    */
9
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
10
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
11
  RCC_OscInitStruct.HSICalibrationValue = 16;
12
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
13
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI_DIV2;
14
  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL16;
15
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
16
  {
17
    _Error_Handler(__FILE__, __LINE__);
18
  }
19
20
    /**Initializes the CPU, AHB and APB busses clocks 
21
    */
22
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
23
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
24
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
25
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
26
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
27
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
28
29
  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
30
  {
31
    _Error_Handler(__FILE__, __LINE__);
32
  }
33
34
    /**Configure the Systick interrupt time 
35
    */
36
  HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);
37
38
    /**Configure the Systick 
39
    */
40
  HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);
41
42
  /* SysTick_IRQn interrupt configuration */
43
  HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
44
}

: Bearbeitet durch User
Beitrag #5322613 wurde vom Autor gelöscht.
von Mike R. (thesealion)


Bewertung
0 lesenswert
nicht lesenswert
Theoretisch sollte das schneller gehen, aber je nachdem mit welchen 
Einstellungen du deinen Code kompiliert hast und wie die Funktion 
"HAL_GPIO_TogglePin()" aussieht kann das schon hinkommen.

Den Luxus einer einfachen Schnittstelle / eines HAL erkauft man sich 
immer auf kosten von Codegröße und Laufzeit!

von Ingo L. (corrtexx)


Bewertung
0 lesenswert
nicht lesenswert
Peter H. schrieb:
> Ich hätte mir da eigentlich deutlich mehr erwartet, oder ist das normal?
Schau dir mal an, was die Funktion
1
HAL_GPIO_TogglePin(SpiClk_GPIO_Port, SpiClk_Pin);
macht. Wirste dich wundern. Ein direkter Registerzugriff is deutlich 
schneller.

von Peter H. (peter_hilleb)


Bewertung
0 lesenswert
nicht lesenswert
1
void HAL_GPIO_TogglePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
2
{
3
  /* Check the parameters */
4
  assert_param(IS_GPIO_PIN(GPIO_Pin));
5
6
  GPIOx->ODR ^= GPIO_Pin;
7
}

Kam mir auf den ersten Blick nicht so verdächtig vor.
Das IS_GPIO_PIN macht schon ein paar Sachen... Dachte aber nicht dass es 
so viel ausmacht.

Denn noch danke, ich kann zum testen ja mal nur den unteren teil selbst 
ausführen.

von Mike R. (thesealion)


Bewertung
0 lesenswert
nicht lesenswert
Auch der Befehl
1
GPIOx->ODR ^= GPIO_Pin;

ist nicht ganz billig. Außerdem hast du (je nach Optimierung) zwei 
Funktionsaufrufe mit allem was dazu gehört alleine um die Unterfunktion 
zu erreichen.

von Torsten (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Ein ARM Mcu hat heute mehrere Busse, die CPU läuft von den Peripherie 
Clocks unabhängig. Am schnellsten geht das toggeln, wenn man nur das 
Outputregister genau mit dem wert beschreibt, der benötigt wird.
Lesen kostet extra.

Deine Schleife und HAL kosten natürlich auch - werden aber mit der Core 
clock abgearbeitet, die schneller ist, als die Peripherie clock.

Speicher und Flash Zugriffe Können je nach Controller auch noch Mal 
extra kosten. Z.b. das Peripherie Basis Register, kann im Rom/Flash 
liegen und wenn der Mcu  keinen Cache hat oder den Flash nicht schnell 
genug lesen kann, dauert das auch.

Last but not least habe ich im Raspberry Pi beobachtet, dass die Arm und 
VPU die gpio gleich schnell toggeln können. Nur nach einigen cyclen war 
die Arm CPU langsamer. Das lag daran, dass der soc ein Feature hat, das 
sie bei zu schnellen Arm Zugriffen auf den Bus den ARM Core warten lässt

von Olaf (Gast)


Bewertung
0 lesenswert
nicht lesenswert
> Ein ARM Mcu hat heute mehrere Busse, die CPU läuft von den Peripherie
> Clocks unabhängig.

Und die Zugriffe dazwischen muessen syncronisiert werden. Das kostet 
auch nochmal Zeit!

Olaf

von Schwanzus Longus (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Gibt doch genug Infos dazu im Netz, einfach mal eine dieser Seiten 
durchlesen.
Z.B.
https://vjordan.info/log/fpga/stm32-bare-metal-start-up-and-real-bit-banging-speed.html

von Daniel B. (dbuergin)


Bewertung
0 lesenswert
nicht lesenswert
Pack das mal in deine main(), damit solltest du das Maximum bekommen,
was Du mit den Clocks eingestellt hast.
1
while(1)
2
{
3
   SpiClk_GPIO_Port->BSSRL = SpiClk_Pin; // Set the pin high
4
   SpiClk_GPIO_Port->BSSRH = SpiClk_Pin; // Set the pin low
5
}

von STM Apprentice (Gast)


Bewertung
-1 lesenswert
nicht lesenswert
Da hammas wieda:

Entweder HAL oder schnell.

HAL ist ja sooooo schöööön bequem.

Da kann auch nix zu schnell werden. Könnt ja sein dass
man sich sonst "der-rennt", wie der Bayer so schön zu
sagen pflegt.

von Markus M. (adrock)


Bewertung
0 lesenswert
nicht lesenswert
BTW: Ich verstehe diesen Test aus assert_param() nicht:

#define   IS_GPIO_PIN(PIN)   ((((PIN) & (uint16_t)0x00) == 0x00) && 
((PIN) != (uint16_t)0x00))

Also der zweite Teil ist klar, PIN darf nicht 0 sein (fängt bei 1 an, 
wie sinnvoll (sic)). Aber wozu am Anfang das mit dem &?

von W.S. (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Peter H. schrieb:
> GPIOx->ODR ^= GPIO_Pin;

Jaja, das kommt davon, wenn man partout NICHT das Manual zum Chip zu 
lesen bereit ist und deshalb seine Uralt-Ideen vom AVR oder sonstigem µC 
auch auf einen 32Bitter überträgt ohne weiter drüber nachzudenken.

Versuche mal lieber sowas:
 GPIO.BSRR = (1<<Pinnummer);
 GPIO.BSRR = (16<<Pinnummer);
in deiner Schleife.

W.S.

von dasrotemopped (Gast)


Bewertung
0 lesenswert
nicht lesenswert
CubeMX und schnell ohne CPU Last geht mit DMA auf GPIO Port

Einfach in CubeMX einen 16bit DMA konfigurieren, Memory to peripheral 
Modus, dann geht es so schnell wie der DMA Controller kann, meist zu 
schnell. Also den DMA von einem Timer triggern lassen, dann kann man 
sich die Geschwindigkeit einstellen. AN4031 hilft beim Einstieg.

von STM Apprentice (Gast)


Bewertung
0 lesenswert
nicht lesenswert
dasrotemopped schrieb:
> CubeMX und schnell ohne CPU Last geht mit DMA auf GPIO Port

Äusserst sinnvoll!

Einfach per DMA einen Port dauernd togglen lassen.
Bloss keinen unnötigen Hardware-Leerlauf erzeugen.

Das hilft auch beim Programmieren sehr viel weiter
wie es der TO vor hat.

von Markus M. (adrock)


Bewertung
0 lesenswert
nicht lesenswert
W.S. schrieb:
> Peter H. schrieb:
>> GPIOx->ODR ^= GPIO_Pin;
>
> Jaja, das kommt davon, wenn man partout NICHT das Manual zum Chip zu
> lesen bereit ist und deshalb seine Uralt-Ideen vom AVR oder sonstigem µC
> auch auf einen 32Bitter überträgt ohne weiter drüber nachzudenken.

Du hast aber schon gesehen, dass der Codeschnipsel offenbar aus der HAL 
Library von ST war?

: Bearbeitet durch User
von Stefan ⛄ F. (stefanus)


Bewertung
0 lesenswert
nicht lesenswert
Der Codeschnipsel aus der HAL ist ja nicht falsch, denn die Funktion 
soll den Pin 1x toggeln, egal in welchem Zustand er vorher war.

Wenn man aber weiß, dass man den Pin schneller setzen bzw. rücksetzen 
kann, dann macht man das, anstatt zu toggeln.

von Johannes S. (jojos)


Bewertung
0 lesenswert
nicht lesenswert
Mike R. schrieb:
> Auch der BefehlGPIOx->ODR ^= GPIO_Pin;
>
> ist nicht ganz billig. Außerdem hast du (je nach Optimierung) zwei
> Funktionsaufrufe mit allem was dazu gehört alleine um die Unterfunktion
> zu erreichen.

so ist das, das wird zu:
1
          HAL_GPIO_TogglePin:
2
08000260:   sub     sp, #8
3
08000262:   str     r0, [sp, #4]
4
08000264:   mov     r3, r1
5
08000266:   strh.w  r3, [sp, #2]
6
509         GPIOx->ODR ^= GPIO_Pin;
7
0800026a:   ldr     r3, [sp, #4]
8
0800026c:   ldr     r2, [r3, #12]
9
0800026e:   ldrh.w  r3, [sp, #2]
10
08000272:   eors    r2, r3
11
08000274:   ldr     r3, [sp, #4]
12
08000276:   str     r2, [r3, #12]
13
510       }

Peter H. schrieb:
> Kam mir auf den ersten Blick nicht so verdächtig vor.
> Das IS_GPIO_PIN macht schon ein paar Sachen... Dachte aber nicht dass es
> so viel ausmacht.

das steckt aber im assert_param(), und das verpufft zu Luft wenn das 
define USE_FULL_ASSERT nicht gesetzt ist. Da man bei den vielen 
Parametern viel falsch machen kann ist das gar nicht verkehrt das im 
debug build zu aktivieren.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
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.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.