STM32F103: Unterschiedliche Puls-Pausezeiten, Pausezeiten länger

OP #6149115
Lesenswert?

Im Moment bin ich unangenehm vom STM32F103 überrascht.

Für bestimmte Projekte (bspw. das Anbinden von parallelen Displays 
dessen Anschluesse quer Beet über 3 Ports verteilt sind - nein, das kann 
ich nicht ändern, weil das Board vorgegeben ist) möchte ich das 
Bitwackeln so schnell als möglich erledigen.

Leider kann ich nicht alle Pins mittels DMA (bspw. über einen SPI) 
ansprechen, deshalb: Bitwackeln.

Mein Problem (oder besser mein Ärgernis) ist folgendes:

Coretakt: 72MHz
Library: libopencm3

Während das Setzen und wieder Löschen eines GPIO's bei 160 ns liegt, 
benötigt das Löschen und wieder Setzen "satte" 430 ns (was mehr als das 
Doppelte ist).

Weshalb ist das so?
Mein Testprogramm ist im Anhang, Systemtimertakt ist ausgeschaltet.

Verrückt ist, dass das bei einem STM32F030 so nicht auftritt, da 
benötigt da beträgt das Pause-Puls Verhältnis ca. 220 ns : 220 ns

Selbst bei einem ATmega328p  erreiche ich Zeiten um 280 ns (bei 16 MHz 
Takt).

Die Fragen also:

Warum sind die Zeiten unterschiedlich ?

Welche Methode kann ich noch verwenden (ausser über BSRR) um evtl. 
schnellere Schaltzeiten zu erreichen ?

Gruß,

JJ
OP #6149133
Lesenswert?

Uwe B. schrieb:
> Lasse den Code zumindestens im RAM laufen. Oder besser, lade die
> Basisadresse des GPIO Block in ein Register und toggle durch setzen der
> entsprechenden BSSR Bits mit Codeausfuehrung aus dem RAM

Puuuuuh... aus dem RAM laufen lassen ... erfordert für mein Setup 
grundsätzliche Änderungen (weil bisher nicht vorgesehen und bisher auch 
nicht notwendig war).

Okay, wollte ich irgendwann sowieso einmal machen.

Beim Togglen bin ich gerade dabei (allerdings mit Code aus dem Flash) 
und das schaut nicht wirklich besser aus.

Kann sein, dass mit der Codeausführung aus dem RAM das besser wird, es 
erklärt aber nicht, warum die Pausezeit länger ist.
(Firma: matzetronics) #6149135
Lesenswert?

Ralph S. schrieb:
> Welche Methode kann ich noch verwenden (ausser über BSRR) um evtl.
> schnellere Schaltzeiten zu erreichen ?

Es ist nicht klar, wie schnell nun die APB2 Clock ist. Zumindest sieht 
es so aus, als würdest du die 72MHz gleich wieder durch 8 teilen (als 
AHB Clock) und damit auch die APB2 Clock darauf begrenzen. die 
verbleibenden 9 Mhz sind dann wirklich langsamer als ein AVR bei 16MHz.
Das muss aber nicht sein, denn die AHB Clock kann ruhig 72Mhz sein und 
ebenso APB2. Siehe dazu im RM0008 Reference Manual den Clocktree auf 
Seite 90.
Nur APB1 muss per Vorteiler auf 36Mhz und weniger begrenzt werden. Poste 
mal dein startup File.
OP #6149166
Lesenswert?

Wenn du dieses

 systick_set_clocksource(STK_CSR_CLKSOURCE_AHB_DIV8);

durch 8 teilen meinst, das geschieht ja nur in

oid systick_setup(void)

und ist in der sys_init auskommentiert und wird nicht aufgerufen (weil 
ich ja wirklich alles ausschalten wollte).

Ein herkömmliches Startup-File gibt es bei libopencm3 nicht, es werden 
mit vector.c und nvic.c die Interruptvektoren festgelegt. 
Takteinstellungen geschehen innerhalb eines Projektes.

Mit dem Einstellen des Taktes wie oben im Anhang (und einem aufgesetzten 
UART) zeigt mit das Programm für die Systemeinstellung das hier an:
1
-------------------------------------
2

3
 STM32F103 / 72 MHz 19200bd 8N1
4
 Januar 2020 R. Seelig 
5

6
 APB1 = 36 MHz
7
 APB2 = 72 MHz
8
 AHB  = 72 MHz
9
-------------------------------------

(und ich habe was weiß ich wie oft AHB, APB1 und APB2 überprüft). Ein 
Indiz dafür, dass das mit voller Geschwindigkeit läuft ist auch, dass 
ich wesentlich höhere Taktraten erreiche, wenn ich ein einzelnes Bit 
über DMA und SPI befeuere.

Aaaaaber, ich werde mal die HAL installieren und sehen, wie es sich da 
verhält (für den Fall, dass im Setup der libopencm3 etwas nicht stimmt).
OP #6149172
Lesenswert?

Das hier ist der Code für die Takteinstellung:
1
void rcc_clock_setup_in_hse_8mhz_out_72mhz(void)
2
{
3
  /* Enable internal high-speed oscillator. */
4
  rcc_osc_on(RCC_HSI);
5
  rcc_wait_for_osc_ready(RCC_HSI);
6

7
  /* Select HSI as SYSCLK source. */
8
  rcc_set_sysclk_source(RCC_CFGR_SW_SYSCLKSEL_HSICLK);
9

10
  /* Enable external high-speed oscillator 8MHz. */
11
  rcc_osc_on(RCC_HSE);
12
  rcc_wait_for_osc_ready(RCC_HSE);
13
  rcc_set_sysclk_source(RCC_CFGR_SW_SYSCLKSEL_HSECLK);
14

15
  /*
16
   * Set prescalers for AHB, ADC, ABP1, ABP2.
17
   * Do this before touching the PLL (TODO: why?).
18
   */
19
  rcc_set_hpre(RCC_CFGR_HPRE_SYSCLK_NODIV);    /* Set. 72MHz Max. 72MHz */
20
  rcc_set_adcpre(RCC_CFGR_ADCPRE_PCLK2_DIV8);  /* Set.  9MHz Max. 14MHz */
21
  rcc_set_ppre1(RCC_CFGR_PPRE1_HCLK_DIV2);     /* Set. 36MHz Max. 36MHz */
22
  rcc_set_ppre2(RCC_CFGR_PPRE2_HCLK_NODIV);    /* Set. 72MHz Max. 72MHz */
23

24
  /*
25
   * Sysclk runs with 72MHz -> 2 waitstates.
26
   * 0WS from 0-24MHz
27
   * 1WS from 24-48MHz
28
   * 2WS from 48-72MHz
29
   */
30
  flash_set_ws(FLASH_ACR_LATENCY_2WS);
31

32
  /*
33
   * Set the PLL multiplication factor to 9.
34
   * 8MHz (external) * 9 (multiplier) = 72MHz
35
   */
36
  rcc_set_pll_multiplication_factor(RCC_CFGR_PLLMUL_PLL_CLK_MUL9);
37

38
  /* Select HSE as PLL source. */
39
  rcc_set_pll_source(RCC_CFGR_PLLSRC_HSE_CLK);
40

41
  /*
42
   * External frequency undivided before entering PLL
43
   * (only valid/needed for HSE).
44
   */
45
  rcc_set_pllxtpre(RCC_CFGR_PLLXTPRE_HSE_CLK);
46

47
  /* Enable PLL oscillator and wait for it to stabilize. */
48
  rcc_osc_on(RCC_PLL);
49
  rcc_wait_for_osc_ready(RCC_PLL);
50

51
  /* Select PLL as SYSCLK source. */
52
  rcc_set_sysclk_source(RCC_CFGR_SW_SYSCLKSEL_PLLCLK);
53

54
  /* Set the peripheral clock frequencies used */
55
  rcc_ahb_frequency = 72000000;
56
  rcc_apb1_frequency = 36000000;
57
  rcc_apb2_frequency = 72000000;
58
}

Wobei das hier:
1
  rcc_set_hpre(RCC_CFGR_HPRE_SYSCLK_NODIV);    /* Set. 72MHz Max. 72MHz */
2
  rcc_set_adcpre(RCC_CFGR_ADCPRE_PCLK2_DIV8);  /* Set.  9MHz Max. 14MHz */
3
  rcc_set_ppre1(RCC_CFGR_PPRE1_HCLK_DIV2);     /* Set. 36MHz Max. 36MHz */
4
  rcc_set_ppre2(RCC_CFGR_PPRE2_HCLK_NODIV);    /* Set. 72MHz Max. 72MHz */

für mich unauffällig ausschaut.
(Firma: matzetronics) #6149304
Lesenswert?

Ich persönlich weiss jetzt nicht, wie die Funktionien nun ausgeführt 
werden, ich kenne das von anderen startup files so, das man direkt 
sieht, welche Register mit welchen Werten gefüllt werden, also mit 
deutlich weniger Abstraktion als deine Lib.
Allerdings kann es beim Porthandling sinnvoll sein, statt der Shifterei 
zum Resetten eines Bits einfach das GPIO->BR Register zu benutzen.

Besser, du suchst mal andere Benutzer der libopencm3, ich bin da erstmal 
raus.
(Firma: matzetronics) #6149354
Lesenswert?

Programmierer schrieb:
> Das dürfte
> geschwindigkeitstechnisch kein Unterschied sein.

Immerhin muss was gemodelt werden. Wie das gemacht wird, hängt vom 
Compiler ab und könnte man im Kompilat mal untersuchen. Da der TE aber 
die max. Geschwindigkeit rausholen möchte, sollte man meine Variante 
zumindest mal ausprobieren, denn selbst wenn ein schlauer Compiler ein 
SWAP oder so benutzt, kostet es Zeit und würde die längere Zeit beim 
Resetten erklären (siehe Threadtitel).
Gast #6149562
Lesenswert?

Programmierer schrieb:
> Stimmt, es ist BSRR und nicht BRR. Der einzige Unterschied ist, dass
> 0x100 und nicht 0x1 geladen werden muss. Das dürfte
> geschwindigkeitstechnisch kein Unterschied sein.

Klar macht das einen RIESENunterschied. movs geht nur für 8-Bit 
Konstanten.
Je nachdem, wie der Compiler das macht (einmal vor der Schleife bei 
Konstanten in verschiedene Register laden oder jedesmal die Konstanten 
nei laden) ... Ohne Assembler-Output ist das alles Kaffeesatzleserei.
OP #6160686
Lesenswert?

so, nachdem Karneval vorbei ist, habe ich mich meinem "Problem" wieder 
gewidmet und aufgrund eines anderen Threads

Beitrag "STM32F103C8T6 - Fälschung von ST bestätigt"

habe ich mir den Chip angesehen und siehe da, es ist auch einer mit der 
Bezeichnung MYS807 und den beiden "zusätzlichen" Vertiefungen.

Danach habe ich mein Testprogramm auf meiner eigenen Platine und einem 
Nucleoboard getestet und siehe da:

Die Pausezeit ist nicht mehr heftig länger !!!

Bei den "Erkenntnissen" zur Fälschung wurde auch etwas über den ACK bei 
I2C gesagt: Prompt funktionieren meine I2C Routinen auch nicht !

Somit hat sich mein Problem erledigt.

Vielen Dank für die Gedanken aus dem Forum
Gast #6161698
Lesenswert?

Habs nochmal nachgestellt und die Ergebnisse im Anhang erhalten

Hier der verwendete Code (O3 Speed Optimierung)
1
#include "stm32f10x_conf.h"
2

3
void gpio_initialisierung(void)
4
{
5
    GPIO_InitTypeDef GPIO_InitStructure;
6

7
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
8
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
9
  GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_Out_PP;
10
  GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_4;
11
  GPIO_Init(GPIOA, &GPIO_InitStructure);
12
}
13

14
int main(void)
15
{
16
    gpio_initialisierung();
17

18
  while(1)
19
  {
20
    GPIOA->ODR &= ~GPIO_Pin_4;
21
    GPIOA->ODR |= GPIO_Pin_4;
22
  }
Angehängte Dateien:
Gast #6161711
Lesenswert?

ach und die loop braucht 0 ns ?

Probier mal folgendes:
1
int main(void)
2
{
3
    gpio_initialisierung();
4

5
  while(1)
6
  {
7
    GPIOA->ODR &= ~GPIO_Pin_4;
8
    GPIOA->ODR |= GPIO_Pin_4;
9
    GPIOA->ODR &= ~GPIO_Pin_4;
10
    GPIOA->ODR |= GPIO_Pin_4;
11
    GPIOA->ODR &= ~GPIO_Pin_4;
12
    GPIOA->ODR |= GPIO_Pin_4;
13
    GPIOA->ODR &= ~GPIO_Pin_4;
14
    GPIOA->ODR |= GPIO_Pin_4;
15
    GPIOA->ODR &= ~GPIO_Pin_4;
16
    GPIOA->ODR |= GPIO_Pin_4;
17
  }
Gast #6161737
Lesenswert?

Matthias S. schrieb:
> Um die Veroder- und Verunderei auszuschliessen, kannste auch mal, wie
> o.a., die GPIO->BSRR und GPIO->BRR Register schreiben.

Damit erreiche ich Zyklus-Zeiten von ca 55nsec, 25nsec high und
30nsec low (abstrahiert von der zusätzlichen Zeit für die Schleife),
bei einer Optimierungsstufe des Compilers von -O3.
Gast #6162142
Lesenswert?

Ich glaube ehrlich gesagt nicht an diese Fake-Geschichte. Ich vermute 
eher, dass der TO den uc falsch programmiert hat.

Wenn er sich nochmal meldet, kann ich ihm ein entsprechendes HEX-File 
zukommen lassen. Wenn er ein Bluepill-Board nutzt, kann ich ihm das 
geben, was auch ich hier getestet habe. Erst dann lasse ich mich 
überzeugen.
OP #6162584
Lesenswert?

... ich bin m Moment nicht zu Hause. Ob du das mit dem Fake glaubst oder 
nicht ist unintetessant. Es ist sogar uninteressant ob ichs falsch 
programmiert habe oder nicht.

Interessant isr, dass ich auf einem neueren BluePill Board (welches ein 
Testprogramm als Fake ausgewiesen hat) und ein anderes Board (welches 
lt. Testprogramm kein Fake ist) mit ein und derselben Firmware 
unterschiedliche Laufzeiten generiert.

Das Testprogramm auf Fake oder nicht Fake ist hier zu finden:

Beitrag "Re: STM32F103C8T6 - Fälschung von ST bestätigt"
Gast #6163202
Lesenswert?

Wie unterschiedlich sind die Laufzeiten in etwa?

Hier konnte ich ca 15% langsamer für den Fake-Chip ermitteln bei 
harmlosen GPIO-Spielchen, also nix mit DMA, ADC oder IRQs
UART zum PC paßte allerdings oder der PC war gutmütig genug das Signal 
noch zu akzeptieren.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren