Forum: Mikrocontroller und Digitale Elektronik STM32F103: Unterschiedliche Puls-Pausezeiten, Pausezeiten länger


von Ralph S. (jjflash)


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

von Ralph S. (jjflash)


Angehängte Dateien:

Lesenswert?

Mist, vor lauter "Ärgernis" vergessen den Code anzuhängen...

von Uwe B. (Firma: TU Darmstadt) (uwebonnes)


Lesenswert?

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

von Ralph S. (jjflash)


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.

von Matthias S. (Firma: matzetronics) (mschoeldgen)


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.

: Bearbeitet durch User
von Ralph S. (jjflash)


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).

von Ralph S. (jjflash)


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.

von Matthias S. (Firma: matzetronics) (mschoeldgen)


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.

: Bearbeitet durch User
von Programmierer (Gast)


Lesenswert?

Mit Optimierung kompiliert? Zeig mal das Disassembly der main.

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Matthias S. schrieb:
> GPIO->BR

Wird auch GPIO->BRR genannt.

von Programmierer (Gast)


Lesenswert?

Matthias S. schrieb:
> Matthias S. schrieb:
> GPIO->BR
>
> Wird auch GPIO->BRR genannt.

Wird doch im Code sogar schon benutzt, in den IOPIN_SET und IOPIN_CLR 
Makros.

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Das kann ich nicht sehen. Ich lese da:
1
#define IOPIN_SET()   ( GPIO_BSRR(GPIOPORT) = GPIOBIT )
2
#define IOPIN_CLR()   ( GPIO_BSRR(GPIOPORT) = (GPIOBIT << 16))
mit BRR sähe das so aus:
1
#define IOPIN_CLR()   ( GPIO_BRR(GPIOPORT) = GPIOBIT)

: Bearbeitet durch User
von Programmierer (Gast)


Lesenswert?

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.

von Matthias S. (Firma: matzetronics) (mschoeldgen)


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).

: Bearbeitet durch User
von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Nee, das ist Quatsch meinerseits - das sind ja alles Konstanten.

von A. B. (Gast)


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.

von Programmierer (Gast)


Lesenswert?

A. B. schrieb:
> Klar macht das einen RIESENunterschied. movs geht nur für 8-Bit
> Konstanten.

Ja, das andere mov welches 0x100 kann ist eine 32bit Instruktion. Die 
braucht aber auch nur 1 Takt.

von Ralph S. (jjflash)


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

von blu (Gast)


Lesenswert?

> Leider kann ich nicht alle Pins mittels DMA

Natürlich. Man kann alle Ports per DMA ansprechen. Egal ob es normale 
GPIOs sind.

von blu (Gast)


Lesenswert?

Nachtrag: Ich habe das mal genutzt, um per DMA sehr viele PWMs zu 
erzeugen (auf allen Pins) ohne das der Prozessor dabei etwas tun müsste.

von blu (Gast)


Angehängte Dateien:

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
  }

von blu (Gast)


Lesenswert?

also Ergebnis ist:

Setzen und wieder Löschen: 150ns
Löschen und wieder Setzen: 125ns

von blu (Gast)


Lesenswert?

Achso vergessen: Der Takt ist 72MHz und das Board ein Bluepill mit einem 
STM32F103C8T6.

von NichtWichtig (Gast)


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
  }

von blu (Gast)


Lesenswert?

NichtWichtig schrieb:
> ach und die loop braucht 0 ns ?

Man stimmt! Ich bin echt ein Schlauberger. Ich probiere es nochmal...

von blu (Gast)


Angehängte Dateien:

Lesenswert?

So also nun ergeben sich diese Werte:

125ns für "ein aus" und "aus ein".

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

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

: Bearbeitet durch User
von STM Apprentice (Gast)


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.

von blu (Gast)


Lesenswert?

STM Apprentice schrieb:
> 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.

Kann ich bestätigen. Habs grade nochmal getestet und komme ebenfalls auf 
etwa 25/30ns.

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Das sieht also nach einer zuverlässigen Methode aus, um Fake und 
Original zu unterscheiden.

von STM Apprentice (Gast)


Lesenswert?

Matthias S. schrieb:
> Das sieht also nach einer zuverlässigen Methode aus, um Fake und
> Original zu unterscheiden.

Das geht für mich aus dem Thread nicht hervor. Welche Methode?

Bitte erkläre das genauer.

von blu (Gast)


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.

von STM Apprentice (Gast)


Lesenswert?

blu schrieb:
> Erst dann lasse ich mich überzeugen.

Yes Sir!

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?


von Richard K. (richi123)


Lesenswert?

Bei Bedarf könnte ich ein Bildchen des Dies machen.

...muss heute diesbezüglich auch noch was hochladen...
Spoiler: Es gibt STM32, die einen CKS32 enthalten. :)

: Bearbeitet durch User
von Ralph S. (jjflash)


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"

von NichtWichtig (Gast)


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.

von Ralph S. (jjflash)


Lesenswert?

NichtWichtig schrieb:
> Wie unterschiedlich sind die Laufzeiten in etwa?

Ich habe nicht weiter nachgeforscht, nachdem das, was ich machen wollte 
auf einem originalen STM lief.

Ich für mich weiß noch nicht, was ich mit den Fake-Chips machen werde. 
Die meisten Programme laufen auf den Fake-Chips.

Ich muß nur wissen, dass eben nicht alles auf den Chips läuft.

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.