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
Mist, vor lauter "Ärgernis" vergessen den Code anzuhängen...
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
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.
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
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).
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.
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
Mit Optimierung kompiliert? Zeig mal das Disassembly der main.
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.
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
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.
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
Nee, das ist Quatsch meinerseits - das sind ja alles Konstanten.
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.
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.
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
> Leider kann ich nicht alle Pins mittels DMA
Natürlich. Man kann alle Ports per DMA ansprechen. Egal ob es normale
GPIOs sind.
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.
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 | } |
also Ergebnis ist: Setzen und wieder Löschen: 150ns Löschen und wieder Setzen: 125ns
Achso vergessen: Der Takt ist 72MHz und das Board ein Bluepill mit einem STM32F103C8T6.
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 | }
|
NichtWichtig schrieb: > ach und die loop braucht 0 ns ? Man stimmt! Ich bin echt ein Schlauberger. Ich probiere es nochmal...
So also nun ergeben sich diese Werte: 125ns für "ein aus" und "aus ein".
Um die Veroder- und Verunderei auszuschliessen, kannste auch mal, wie o.a., die GPIO->BSRR und GPIO->BRR Register schreiben.
:
Bearbeitet durch User
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.
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.
Das sieht also nach einer zuverlässigen Methode aus, um Fake und Original zu unterscheiden.
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.
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.
Lest dieses Posting des TE: Beitrag "Re: STM32F103: Unterschiedliche Puls-Pausezeiten, Pausezeiten länger"
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
... 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"
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.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.