Forum: Mikrocontroller und Digitale Elektronik H743 und F746 - Probleme mit dem Takt


von Wicki W. (wicki)


Lesenswert?

Hi *,

beim austesten der machbaren Taktfrequenzen bin ich mit
dem Problem konfrontiert worden, dass der angezeigte
und der als alternate ausgebene Systemtakt nicht nur
nicht übereinstimmen sondern gewaltig differieren.

Beim 746 sagt er:
SystemCoreClock : 216 MHz
Beim 743:
SystemCoreClock : 400 MHz

und das ist auch jeweils das, was ich im Cubeide  1.13.2
konfiguriert habe.

Aber ein
while (1) {GPIOF->ODR ^= GPIO_ODR_OD1;}
bringt bei beiden nur rund 5MHz raus.
(4,75 und 5,25)

Beim 743 habe ich dann mal RCC_MCO_2 auf einen Port
gelegt und auch bekomme ich nur diese Frequenz angezeigt.
Interrupts sind aus und somit sollte der Port-Toggle
doch eigentlich der halben Taktfrequenz entstprechen.

Ich habe überigens keine Veränderung feststellen können, ob die
Ports auf "slow" oder "very fast" stehen - sollte ja eh eigentlich
nur die Stromaufnahme betreffen. Aber versucht hab ich das auch mal.

Die Config des 746
1
  __HAL_RCC_PWR_CLK_ENABLE();
2
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1); 
3
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
4
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
5
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
6
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
7
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
8
  RCC_OscInitStruct.PLL.PLLM = 8;
9
  RCC_OscInitStruct.PLL.PLLN = 216;
10
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
11
  RCC_OscInitStruct.PLL.PLLQ = 2;
Hat jemand eine Idee dazu ?

von Andreas B. (abm)


Lesenswert?

Dass GPIOF->ODR ^= GPIO_ODR_OD1 schnarchlangsam ist, ist ein alter Hut. 
(Da scheinen auch ein paar Tippfehler zu sein ...). Mit halbem CPU-Takt 
ist da nix.
Dass schafft selbst ein STM32G0 viel schneller.

Was die MCO-Ausgänge anbelangt: Die GPIOs können lt. Datenblatt unter 
günstigen Umständen garantiert bis zu 180 Mhz.
Aber man sollte vielleicht mal die RCC-Register "zu Fuß" kontrollieren, 
ob da wirklich das drinsteht, was man vermutet/erhofft. Insbesondere 
PLLRDY, die eingestellten Faktoren/Teiler und die SWS-Bits. Ach ja, die 
Teiler für MCO1 bzw. MCO2 nicht zu vergessen ...

von Andreas S. (Firma: Schweigstill IT) (schweigstill) Benutzerseite


Lesenswert?

Wicki W. schrieb:
> Aber ein
> while (1) {GPIOF->ODR ^= GPIO_ODR_OD1;}
> bringt bei beiden nur rund 5MHz raus.
> (4,75 und 5,25)
>
> Beim 743 habe ich dann mal RCC_MCO_2 auf einen Port
> gelegt und auch bekomme ich nur diese Frequenz angezeigt.
> Interrupts sind aus und somit sollte der Port-Toggle
> doch eigentlich der halben Taktfrequenz entstprechen.

Falsch. Die obige Schleife enthält mindestens eine Port-Leseoperation, 
eine logische Operation, eine Port-Schreiboperation und einen Sprung. 
Selbst wenn all dies in jeweils einem CPU-Taktzyklus abliefe, wären das 
schon vier Takte.

Und warum hältst Du es nicht für nötig, mal einen Blick in die 
Systemarchitekturen der beiden Microcontroller zu schauen, z.B. in dem 
jeweiligen Reference Manual, Kapitel "Memory and bus architecture"? Die 
GPIO-Register hängen da so ziemlich am Ende der Nahrungskette, d.h. die 
Zugriffe erfolgen über etliche Bus Bridges, die teils mit 
unterschiedlichen Takten laufen und dementsprechend einsynchronisiert 
werden müssen.

Wie kommt man bloß auf die absurde Idee, dass ein Lesezugriff, der ja 
für die o.a. XOR-Verknüpfung erforderlich ist, in nur einem Zyklus 
möglich wäre? Ganz im Gegenteil wird dadurch jegliches Pipelining bei 
der Buszugriffen völlig vereitelt.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Wicki W. schrieb:
> Beim 743 habe ich dann mal RCC_MCO_2 auf einen Port
> gelegt und auch bekomme ich nur diese Frequenz angezeigt.

"Diese Frequenz"? Welche jetzt, die 5 MHz oder die 216 bzw. 400 MHz?

von Ob S. (Firma: 1984now) (observer)


Lesenswert?

Andreas S. schrieb:

> Falsch. Die obige Schleife enthält mindestens eine Port-Leseoperation,
> eine logische Operation, eine Port-Schreiboperation und einen Sprung.
> Selbst wenn all dies in jeweils einem CPU-Taktzyklus abliefe, wären das
> schon vier Takte.

Und dazu kommt noch: diese (hypothetischen) vier CPU-Takte würden nur 
die Hälfte der Wellenform erzeugen. Die Ausgabefrequenz wäre also 
bestenfalls 1/8 des CPU-Takts.

von Wicki W. (wicki)


Lesenswert?

Niklas G. schrieb:
> Wicki W. schrieb:
>> Beim 743 habe ich dann mal RCC_MCO_2 auf einen Port
>> gelegt und auch bekomme ich nur diese Frequenz angezeigt.
>
> "Diese Frequenz"? Welche jetzt, die 5 MHz oder die 216 bzw. 400 MHz?

Diese rund 5 MHz kommen raus.

Ob da nun 3 oder 5 MHz beim GPIO-schreiben rauskommen
und ob er 2, 5 oder 10 oder auch 20 Zyklen pro Toggle
braucht:

Auf jeden Fall ist es viel weniger als eigentlich ankommen
müsste - bei angeblichen 400HMz.

Ein knappes MHz bekomme ich selbst mit

 for (uint32_t i = 0; i < 10; i++) { }

 HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_0);

heraus - Aber das Signalbild wird immer
schwammiger. Vielleicht ist es auch einfach
nur ein HF-Problem.
Ich versuche grade, das etwas einzugrenzen.

von Andreas S. (Firma: Schweigstill IT) (schweigstill) Benutzerseite


Lesenswert?

Wicki W. schrieb:
> Auf jeden Fall ist es viel weniger als eigentlich ankommen
> müsste - bei angeblichen 400HMz.

Und was ergibt Deine konkrete Berechnung der Latenzen anhand der 
Systemarchitektur? Nicht irgendwelche gefühlten Abschätzungen, sondern 
quantitative Berechnungen anhand der Taktverhältnisse zwischen den 
Bus-Bridges, usw.. Welche ganz konkrete Dokumentation von ARM zu den 
betreffenden IP-Blöcken hast Du hierfür herangezogen?

von J. S. (jojos)


Lesenswert?

es hängt auch davon ab an welchem APB man hängt, beim H743 takten die 
mit 200 oder 100 MHz, nicht mit dem SysClock, siehe Clock Config im 
CubeMX.

: Bearbeitet durch User
von Frank K. (fchk)


Lesenswert?

Wicki W. schrieb:

> Diese rund 5 MHz kommen raus.
>
> Ob da nun 3 oder 5 MHz beim GPIO-schreiben rauskommen
> und ob er 2, 5 oder 10 oder auch 20 Zyklen pro Toggle
> braucht:
>
> Auf jeden Fall ist es viel weniger als eigentlich ankommen
> müsste - bei angeblichen 400HMz.

Ja, ist auch klar.

Bei so einem STM32H7 ist wie bei allen ARM-und MIPS-MCUs/MPUs der 
Prozessorkern ein Zukaufteil, eine Black Box, wo der Chiphersteller 
keinen Zugriff auf die Interna hat. Die ganze Peripherie wird über 
asynchrone Busse angekoppelt, die mit einem Bruchteil des 
Prozessortaktes laufen. Das gilt im übrigen auch für den gesamten 
Speicher (Flash und RAM) mit Ausnahme des TCM. Deswegen ist die 
IO-Geschwindigkeit VIEL langsamer als der Prozessortakt.

Gegenbeispiel Microchip PIC24/dsPIC33: Hier ist der Prozessorteil kein 
Zukaufteil, sondern integraler Bestandteil. Die ganzen SFRs (Special 
Function Registers) sind genau wie das RAM und die Prozessorregister 
(die sich in den ersten Adressen des Datenadressbereiches befinden) 
direkt synchron an den Prozessorkern angebunden. Genau deswegen kann der 
PIC24 auch atomare Bitbefehle, wählend ARM und MIPS (z.B. PIC32) das von 
sich aus grundsätzlich nicht können - hier muss die Peripherie 
entsprechende Bit-Set, Bit-Clear und Bit-Toggle Register oder 
Bit-Banding bereitstellen.

Und wer schnelle, deterministische Signale erzeugen will, braucht extra 
Hardware dafür, entweder in Form von Prozessorperipherie oder eines 
FPGA-Blockes.

fchk

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Wicki W. schrieb:
> Diese rund 5 MHz kommen raus.

Dann stimmt deine Taktkonfiguration nicht, und die ganzen Überlegungen 
bzgl. GPIO-Zugriff, Prozessor-Latenz usw. sind hinfällig. Die 
Taktausgabe auf MCO kommt direkt aus dem Taktsystem/PLL und hat mit dem 
Prozessorkern, Busstruktur nicht viel zu tun. Lediglich die "analoge" 
Maximalfrequenz des GPIO-Treibers kann hier limitieren, aber einen 
verschliffenen Sinus sollte man bei 400 MHz noch erkennen können (sofern 
dein Oszilloskop das kann!).

Wicki W. schrieb:
> RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;

Aus dem HSI so einen hohen Takt zu erzeugen ist fragwürdig, schau mal 
ins Datasheet ob das überhaupt erlaubt ist. Benutze einen externen 
Quarz/Keramik-Oszillator und prüfe mit dem Oszilloskop ob er anläuft.

Schau mal ob die RCC-Initialisierungsfunktionen Fehler zurückgeben (im 
Debugger durchsteppen).

: Bearbeitet durch User
von Wicki W. (wicki)


Lesenswert?

"Schau mal ob die RCC-Initialisierungsfunktionen Fehler zurückgeben (im
Debugger durchsteppen)."

Guter Ansatz. Hatte ich nicht dran gedacht.
Ich habe mir aber grad mal die RCC_MC02 genauer angesehen:
Wenn ich HSE 1:1 durchleite, dann messe ich 8 MHz.
Und das was rauskommt, das kann man noch als Rechteck
durchgehen lassen.

Wenn ich SYSCLK/ 5 hinleite, dann sollten es 26MHz werden.
Es kommt aber nur noch Grütze an.

Ein Pegel von ca. 1.5 Volt mit ca. 0,5 Volt Jitter.
Und wenn man den genauer ansieht, dann sieht man:
der jittert mit 26,6MHz.

Mit einem Teiler von 10 sind es 40 MHz und mit 1 bin
ich in dem Bereich, den ich nicht mehr messen kann....

Also die Taktung stimmt also wohl. Und grundsätzlich
gehen auch Signale im 2-stellingen MHz-Bereich raus.
Ich weiss aber nicht, ob man solche Signale noch
sauber verarbeiten kann.

Mit welchen Geschwindigkeiten arbeitet Ihr denn so?

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Was für ein Oszilloskop benutzt du?

von Wicki W. (wicki)


Lesenswert?

Niklas G. schrieb:
> Was für ein Oszilloskop benutzt du?


Bei 30 bzw. 50 MHz ist Schluss.
Unit-T und Peaktech.

Als ich die gekauft habe, dacht ich nicht im Traum dran mal
mehr als 10 MHz messen zu wollen.

von Andreas S. (Firma: Schweigstill IT) (schweigstill) Benutzerseite


Lesenswert?

Und wann stellst Du mal Deine Berechnung zur Verfügung, auf Grund derer 
die hohe Frequenz beim Togglen des Ausganges zustandekommen soll?

von Andreas S. (Firma: Schweigstill IT) (schweigstill) Benutzerseite


Lesenswert?

Wicki W. schrieb:
> Wenn ich HSE 1:1 durchleite, dann messe ich 8 MHz.
> Und das was rauskommt, das kann man noch als Rechteck
> durchgehen lassen.
>
> Wenn ich SYSCLK/ 5 hinleite, dann sollten es 26MHz werden.
> Es kommt aber nur noch Grütze an.
>
> Ein Pegel von ca. 1.5 Volt mit ca. 0,5 Volt Jitter.
> Und wenn man den genauer ansieht, dann sieht man:
> der jittert mit 26,6MHz.

Aha, und das soll daran liegen, dass der Prozessor kein ordentliches 
Ausgangssignal liefert? Das ist völliger Unsinn. Der tatsächliche Grund 
liegt vielmehr in Deinem Aufbau bzw. der Art und Weise, wie das Signal 
abgegriffen wird. Lass mich raten: Die Masseklemme ist nicht in 
unmittelbarer Nähe des Microcontrollers angeschlossen und auch nicht so 
kurz wie möglich. Womöglich handelt es sich auch noch um einen 
1:1-Tastkopf oder gar ein einfaches Stück Koaxialkabel, so dass dort 
haufenweise Reflektionen auftreten können.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Wicki W. schrieb:
> Bei 30 bzw. 50 MHz ist Schluss.
> Unit-T und Peaktech

Dann ist ja wohl klar dass da nichts vernünftiges bei rauskommt. Du 
könntest mit einem Timer eine PWM erzeugen mit z.B. 1kHz und prüfen ob 
auch tatsächlich 1kHz raus kommen; wenn nicht, ist der Takt falsch.

von Wicki W. (wicki)


Lesenswert?

Andreas S. schrieb:

> Aha, und das soll daran liegen, dass der Prozessor kein ordentliches
> Ausgangssignal liefert?


Hab ich das gesagt?
Nö, hab ich nicht.
Ich hab lediglich Fakten aufgezählt.
Sicher einige vergessen, nicht beachtet oder
bewusst vernachlässigt.

Den Verdacht, dass es (auch) ein HF-Problem ist, den hab ich
auch schon geäußert und werde das eingrenzen.

Wichtiger ist mir jetzt erst mal eine Testumgebung um
die Grenzen und Probleme richtig austesten zu können.
Das stelle ich grad zusammen und dann ins Netz.


"Dann ist ja wohl klar dass da nichts vernünftiges bei rauskommt."

Und wenn mit der Herr Erlkönig nun mal erklären könnten,
warum man mit einem 50HMz-Scope keine 30 MHz messen können soll...


Achja - mich interessiert nach wie vor:

Mit welchen Geschwindigkeiten arbeitet Ihr denn so?

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Wicki W. schrieb:
> Und wenn mit der Herr Erlkönig nun mal erklären könnten,
> warum man mit einem 50HMz-Scope keine 30 MHz messen können soll...

Kann man, wird halt ziemlich verschliffen/sinusartig. Aber ich dachte du 
versuchst 400 MHz vom MCO messen?

von Wicki W. (wicki)


Lesenswert?

Niklas G. schrieb:
>> warum man mit einem 50HMz-Scope keine 30 MHz messen können soll...
>
> Kann man, wird halt ziemlich verschliffen/sinusartig. Aber ich dachte du
> versuchst 400 MHz vom MCO messen?

Nein, nein, dass ich das mit den hier vorhandenen Geräten
nicht kann, das ist mir klar.
Aber ich war davon ausgegangen, das bis zu 10 MHz kein Problem
sein sollten - und war sehr überrascht, was ich dann so zu sehen
bekam.

Wie auch immer:
Mich würde wirklich interessieren, ob hier jemand praktische
Erfahrungen mit dem 743 oder 746 bei sehr schnellen
Signalen auf den IO-Ports hat.

Ich taste mich da jetzt so langsam ran
und wundere mich oft ;-)

http://erste.de/STM32/

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Wicki W. schrieb:
> Mich würde wirklich interessieren, ob hier jemand praktische
> Erfahrungen mit dem 743 oder 746 bei sehr schnellen
> Signalen auf den IO-Ports hat.

Schau dir das STM32F746NG Discovery an. Das hat SDRAM, ein paralleles 
Display und eine per SDIO angebunde SD-Karte. Letztere kann man 
problemlos mit 48 MHz ansteuern. Schau mal ins Datenblatt wie schnell 
SDRAM und Display sind, die funktionieren auch problemlos.

: Bearbeitet durch User
von Andreas S. (Firma: Schweigstill IT) (schweigstill) Benutzerseite


Lesenswert?

Wicki W. schrieb:
> Wie auch immer:
> Mich würde wirklich interessieren, ob hier jemand praktische
> Erfahrungen mit dem 743 oder 746 bei sehr schnellen
> Signalen auf den IO-Ports hat.

Was nützt das, wenn Du die relevanten Fragen eh hartnäckig ignorierst? 
Und noch einmal: Wie hast Du denn berechnet, welche Frequenz das 
Ausgangssignal haben sollte, wenn per Firmware an dem GPIO gewackelt 
wird?

von Wicki W. (wicki)


Lesenswert?

Andreas S. schrieb:
> Wicki W. schrieb:
>> Wie auch immer:
>> Mich würde wirklich interessieren, ob hier jemand praktische
>> Erfahrungen mit dem 743 oder 746 bei sehr schnellen
>> Signalen auf den IO-Ports hat.
>
> Was nützt das, wenn Du die relevanten Fragen eh hartnäckig ignorierst?
> Und noch einmal: Wie hast Du denn berechnet, welche Frequenz das
> Ausgangssignal haben sollte, wenn per Firmware an dem GPIO gewackelt
> wird?

Wem es nützt?
Jedem, der sich fragt: "Lohnt es sich, sich mit dem 746 oder
743 zu beschäftigen, wenn ich damit Signale im MHz-Bereich
erezugen oder erfassen will? Oder lohnt es sich nicht, weil
sich schon andere die Zähne dran ausgebissen haben?"

Ich habe überhaupt nichst errechnet. Dafür ist es noch viel zu früh.
Ich weiss aber, dass bei einem 400MHz Takt mehr als ein paar 100 kHz
raus kommen müssen - Ganz egal, wie verzwackt das interne
Bus-System ist.

Das taten sie auf Anhieb nicht und ich suche nach dem Grund.
Was ich dazu gerade tue, dass ist unter der obigen Link
Schritt für Schritt nachzulesen.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Wicki W. schrieb:
> Wem es nützt?
> Jedem, der sich fragt: "Lohnt es sich, sich mit dem 746 oder
> 743 zu beschäftigen, wenn ich damit Signale im MHz-Bereich
> erezugen oder erfassen will?

Ja. Alles STM32 können Signale im unteren zweistelligen MHz-Bereich 
ausgeben. In Software wie gezeigt geht es zwar, ist aber wenig sinnvoll. 
Viel besser geht das mit Timern, DMA oder auch FSMC. Damit kommt man auf 
die maximale im Datasheet angegebene GPIO-Frequenz.

von Harry L. (mysth)


Lesenswert?

Niklas G. schrieb:
> Ja. Alles STM32 können Signale im unteren zweistelligen MHz-Bereich
> ausgeben. In Software wie gezeigt geht es zwar, ist aber wenig sinnvoll.
> Viel besser geht das mit Timern, DMA oder auch FSMC. Damit kommt man auf
> die maximale im Datasheet angegebene GPIO-Frequenz.

+1

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Wie Andreas schon erwähnt hat können die GPIO-Treiber des STM32F746NG 
bis zu 180 MHz ausgeben. Über die Peripherie-Blöcke erreicht man:
- Mit Timern bis zu 108 MHz; der Timer läuft intern zwar bei 216 MHz, 
kann aber nur maximal die halbe Frequenz als "PWM" erzeugen
- Der SDIO-Block kann 50 MHz
- Der TFT-Controller kann 45 MHz
- Der FMC kann bis zu 108 MHz je nach Speichertyp
- Der QSPI ebenso 108 MHz
- Der normale SPI kann 54 MHz
- Das USB-ULPI Interface läuft bei 60 MHz
- Das Kamera-Interface kann 54 MHz

Die 180 MHz kann man wohl nur mit dem MCO erreichen. Zum Vergleich: Die 
GPIO-Treiber des guten alten STM32F103RB können 50 MHz treiben, bei 72 
MHz internem Takt können die Timer also 36 MHz maximale Ausgabefrequenz. 
Schnelle dedizierte Interfaces hat er leider keine.

Wie bei so gut wie allen schnellen Prozessoren ist die interne 
Taktfrequenz (hier: 216 MHz) nur für den Prozessorkern und den 
schnellsten Bus (AHB) relevant. Nahezu das ganze Drumherum läuft 
langsamer. Nur einige sehr schnelle Interfaces wie DDR-SDRAM, PCIe, 
USB-HS, HDMI, SD-bus mit UHS erreichen höhere Frequenzen, brauchen dafür 
aber ausgeklügelte (differentielle) Transceiver mit Selbstkalibration. 
Beliebige Bitmuster kann man damit nicht ausgeben.

Bei "richtigen" Prozessoren (SoC) der Cortex-A -Klasse ist das noch 
deutlicher; deren Prozessorkerne laufen zwar im GHz-Bereich, aber allein 
schon der Zugriff auf die GPIO-Register braucht Hundert(e) Takte, weil 
die GPIO-Peripherie und dessen Bus eben so langsam ist. Es kommt auch 
selten jemand auf die Idee, auf solchen Prozessoren schnelle 
GPIO-Zugriffe zu machen; die werden eher für Status-LEDs oder Buttons 
genutzt. Für schnelle Datenübertragungen werden auch hier dedizierte 
Peripherieblöcke genutzt. Controller wie der STM32F746NG sind da schon 
eher eine Besonderheit, weil der Prozessorkern schon recht schnell ist 
(im Vergleich zu "normalen" Mikrocontrollern) aber der GPIO-Zugriff 
ebenfalls noch recht direkt/schnell geht (im Vergleich zu 
Anwendungsprozessoren).

Bleibt also die übliche Frage: Was willst du eigentlich erreichen? Wenn 
du einfach nur einen schnellen Takt ausgeben möchtest, dafür gibt es 
PLL-ICs; manche Controller haben auch extrem schnelle PWM-Ausgänge.

von Wicki W. (wicki)


Lesenswert?

Hi zusammen,

hey, Danke!
Das sind mal schön zusammengefasste und verständliche Infos.

"Bleibt also die übliche Frage: Was willst du eigentlich erreichen?"

Das habe ich alles in dem o.g. Link zusammengenfasst.
Eigentlich wollte ich nur im µSec Bereich einlesen
und ausgeben können. Und das schien mir bei bis zu
480MHz Clock nicht _zu_verwegen.

Ich hab für den max7219 einen SPI "von Hand" geschrieben
(also ohne das SPI-Interface) um ein bisschen zu experimentieren.
Dann diese Signale mit einem 746 eingefangen und dargestellt.
Und beim Schrauben an den Timings bin ich auf das Eingangsproblem
gestossen.
Jetzt sehe ich schon ein wenig klarer und es geht weiter.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Wicki W. schrieb:
> Das habe ich alles in dem o.g. Link zusammengenfasst.

Ich habe relativ wenig Lust das alles zu lesen. Da scheint vieles nicht 
für die Frage relevant zu sein.

Wicki W. schrieb:
> Eigentlich wollte ich nur im µSec Bereich einlesen
> und ausgeben können.

1 MHz sind überhaupt kein Problem, selbst mit dem alten (und billigen) 
STM32F103RB. Das kann man z.B. mit einem Timer + DMA machen.

Wenn du unbedingt per Software toggeln möchtest, versuche es mal so in 
der Art:
1
extern "C" void toggle (GPIO_TypeDef* GPIOx, std::uint16_t pinMask) {
2
  __asm__ volatile (
3
    "1: str %[maskS], [%[BSRR]]\n"
4
    "str %[maskR], [%[BSRR]]\n"
5
    "str %[maskS], [%[BSRR]]\n"
6
    "str %[maskR], [%[BSRR]]\n"
7
    "str %[maskS], [%[BSRR]]\n"
8
    "str %[maskR], [%[BSRR]]\n"
9
    "str %[maskS], [%[BSRR]]\n"
10
    "str %[maskR], [%[BSRR]]\n"
11
    "str %[maskS], [%[BSRR]]\n"
12
    "str %[maskR], [%[BSRR]]\n"
13
    "str %[maskS], [%[BSRR]]\n"
14
    "str %[maskR], [%[BSRR]]\n"
15
    "str %[maskS], [%[BSRR]]\n"
16
    "str %[maskR], [%[BSRR]]\n"
17
    "b 1b"
18
    : :
19
    [maskS] "l" (pinMask),
20
    [maskR] "l" (std::uint32_t { pinMask } << 16),
21
    [BSRR] "l" (&GPIOx->BSRR) : "memory");
22
}

Den Code sollte man nach Möglichkeit in den ITCM RAM um Wait States zu 
vermeiden. Zur Sicherheit ist die Schleife so eingestellt dass sie in 
eine Cache-Line passt. Ist aber immer noch langsamer als per Timer.

von Wicki W. (wicki)


Lesenswert?

"Wenn du unbedingt per Software toggeln möchtest,"

Möchte ich ja gar nicht.
Es ist hat zum ausprobieren das einfachste.
Optimieren kann man später immer noch.

Aber Deine Testidee werde ich mal in die Liste
aufnehmen.
Heute ists zu spät...

gut n8

wicki

von Wicki W. (wicki)


Lesenswert?

Hab jetzt mal ausprobiert.

Das war eine gute Idee und gibt mir ein Gefühl dafür,
wo bei dem H743 die Grenzen sind (was klassiches
GPIO-Handling betrifft)

1
fastToggle.h
2
#ifndef TOGGLE_H
3
#define TOGGLE_H
4
5
#include "stm32h7xx_hal.h"
6
void fastToggle(GPIO_TypeDef* GPIOx, uint16_t pinMask);
7
#endif
8
9
fastToggle.c
10
#include "fastToggle.h"
11
12
void fastToggle(GPIO_TypeDef* GPIOx, uint16_t pinMask) {
13
    __asm__ volatile (
14
        "1: str %[maskS], [%[BSRR]]\n"
15
        "str %[maskR], [%[BSRR]]\n"
16
        "str %[maskS], [%[BSRR]]\n"
17
        "str %[maskR], [%[BSRR]]\n"
18
        "str %[maskS], [%[BSRR]]\n"
19
        "str %[maskR], [%[BSRR]]\n"
20
        "str %[maskS], [%[BSRR]]\n"
21
        "str %[maskR], [%[BSRR]]\n"
22
        "str %[maskS], [%[BSRR]]\n"
23
        "str %[maskR], [%[BSRR]]\n"
24
        "str %[maskS], [%[BSRR]]\n"
25
        "str %[maskR], [%[BSRR]]\n"
26
        "str %[maskS], [%[BSRR]]\n"
27
        "str %[maskR], [%[BSRR]]\n"
28
        "b 1b"
29
        :
30
        :
31
        [maskS] "l" (pinMask),
32
        [maskR] "l" ((uint32_t)pinMask << 16),
33
        [BSRR] "l" (&GPIOx->BSRR)
34
        : "memory"
35
    );
36
}
Das Resultat: 16.6 MHz Ausgangssignal - eigentlich schon ganz gut.

http://erste.de/STM32/h743zi_fast_toggle_400MHz_2023-10-10_17-08-38.jpg

Viel mehr, als mit einer HAL-GPIO-Schleife machbar war.
30nS von Pegelwechsel zu Pegelwechsel. Bei 400/2 MHz Sysclock.
Würde bedeuten 6 Zyklen pro Toggle. Das erscheint auf den ersten
Blick stimmig.
"Sinnvoll" ist das schon aufgrund der Signalqualität eher nicht.
Aber ein sehr schönes Experiment.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Wicki W. schrieb:
> Bei 400/2 MHz Sysclock.
> Würde bedeuten 6 Zyklen pro Toggle. Das erscheint auf den ersten
> Blick stimmig.

Mach das doch nochmal mit Code im ITCM-RAM. 6 Takte pro "STR" sind schon 
etwas viel, das kommt wohl durch die Flash Wait States zustande.

von Wicki W. (wicki)


Lesenswert?

Wenn ich das richtig sehe, dann liegt das im  ITCM-RAM:

1
 ITCMRAM (xrw)  : ORIGIN = 0x00000000, LENGTH = 64K
2
3
 .text.fastToggle
4
                0x0000000008007a74       0x42 ./Core/Src/fastToggle.o
5
                0x0000000008007a74                fastToggle
6
 *fill*         0x0000000008007ab6        0x2

oder ?

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Wicki W. schrieb:
> .text.fastToggle
>
>                 0x0000000008007a74

Nö. Das ist ne Flash-Adresse.

von Wicki W. (wicki)


Lesenswert?

habs grad gesehen - konnte aber schon nicht mehr ändern...

Wie krieg ichs denn dann da rein?

Das im Linker-script ist wohl nicht die Lösung:
1
 .itcm :
2
  {
3
    . = ALIGN(4);
4
    KEEP(*(fastToggle.o))  /*  fastToggle.o in ITCM-RAM */
5
    . = ALIGN(4);
6
  } > ITCM_RAM

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?


: Bearbeitet durch User
von Wicki W. (wicki)


Lesenswert?

Wenn ich das jetzt richtig (und nicht wieder eine 8 über-)sehe, dann
ist fastTogle jetzt im itcm-RAM.
1
 *(fastToggle.o)
2
 .itcm          0x0000000000000000       0x42 ./Core/Src/fastToggle.o
3
                0x0000000000000000                fastToggle

sagt das .map-File.

Verändert hat sicher aber nichts.
Es bleibt bei 16.6MHz - Also 6 Zyklen pro
Toggle.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Zeig zur Sicherheit mal den Disassembly Code der fastToggle und auch des 
Aufrufs derselben (also wahrscheinlich aus der main()).

Auf was hast du den HPRE Prescaler eingestellt?

Wicki W. schrieb:
> "Sinnvoll" ist das schon aufgrund der Signalqualität eher nicht.

16 MHz sollten noch ganz gut aus dem GPIO-Pin rauskommen. Das 
Verschleifen kommt wohl eher vom Oszilloskop oder der Leitungsführung.

von Wicki W. (wicki)



Lesenswert?

Die Signale sind mir zunächst mal nicht so wichtig.
Aber obwohl fastToggle jetzt bei 0x00 steht
scheint der Aufruf nach 0c80... zu gehen.


Wie kommt er darauf, dass das "HAL_EXTI_D3_EventInputConfig" sein
soll?

1
aus main:  
2
 
3
4
 disassemble 0x800ee80
5
Dump of assembler code for function __fastToggle_veneer:
6
   0x0800ee80 <+0>:     ldr.w   pc, [pc]        ; 0x800ee84 <__fastToggle_veneer+4>
7
   0x0800ee84 <+4>:     movs    r1, r0
8
   0x0800ee86 <+6>:     movs    r0, r0
9
End of assembler dump.
10
11
12
13
Das sieht aber schräg aus:
14
15
  disassemble 0x00000000
16
Dump of assembler code for function HAL_EXTI_D3_EventInputConfig:
17
   0x00000000 <+0>:     push    {r7}
18
   0x00000002 <+2>:     sub     sp, #12
19
   0x00000004 <+4>:     add     r7, sp, #0
20
   0x00000006 <+6>:     str     r0, [r7, #4]
21
   0x00000008 <+8>:     mov     r3, r1
22
   0x0000000a <+10>:    strh    r3, [r7, #2]
23
   0x0000000c <+12>:    ldrh    r3, [r7, #2]
24
   0x0000000e <+14>:    lsls    r2, r3, #16
25
   0x00000010 <+16>:    ldr     r3, [r7, #4]
26
   0x00000012 <+18>:    add.w   r1, r3, #24
27
   0x00000016 <+22>:    ldrh    r3, [r7, #2]
28
   0x00000018 <+24>:    str     r3, [r1, #0]
29
   0x0000001a <+26>:    str     r2, [r1, #0]
30
   0x0000001c <+28>:    str     r3, [r1, #0]
31
   0x0000001e <+30>:    str     r2, [r1, #0]
32
   0x00000020 <+32>:    str     r3, [r1, #0]
33
   0x00000022 <+34>:    str     r2, [r1, #0]
34
   0x00000024 <+36>:    str     r3, [r1, #0]
35
   0x00000026 <+38>:    str     r2, [r1, #0]
36
   0x00000028 <+40>:    str     r3, [r1, #0]
37
   0x0000002a <+42>:    str     r2, [r1, #0]
38
   0x0000002c <+44>:    str     r3, [r1, #0]
39
   0x0000002e <+46>:    str     r2, [r1, #0]
40
   0x00000030 <+48>:    str     r3, [r1, #0]
41
   0x00000032 <+50>:    str     r2, [r1, #0]
42
   0x00000034 <+52>:    b.n     0x18 <HAL_EXTI_D3_EventInputConfig+24>
43
   0x00000036 <+54>:    nop
44
   0x00000038 <+56>:    adds    r7, #12
45
   0x0000003a <+58>:    mov     sp, r7
46
   0x0000003c <+60>:    ldr.w   r7, [sp], #4
47
   0x00000040 <+64>:    ldrh    r7, [r2, #30]
48
   0x00000042 <+66>:    b.n     0xfffffb90

: Bearbeitet durch User
von Hans-Georg L. (h-g-l)


Lesenswert?

Ich habe das gerade mal mit meinem Nucleo553 Board probiert.
Aus dem MCO2 bekomme ich 480Mhz / 4 = 120 MHz. ( 
GPIO_SPEED_FREQ_VERY_HIGH)
Durch 3 dividiert schafft er nicht mehr jeden Takt.

Mit
1
  while (1)
2
  {
3
    HAL_GPIO_TogglePin(LD1_GPIO_Port, LD1_Pin);
4
  }

bekomme ich an der LED 3,8 MHz

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Wicki W. schrieb:
> Aber obwohl fastToggle jetzt bei 0x00 steht
> scheint der Aufruf nach 0c80... zu gehen.

Das ist soweit normal, das ist ein "veneer" oder "Trampolin", eine 
Funktion welche einfach nur ans eigentliche Ziel springt. Das macht der 
Compiler, weil die Adresse der Funktion sehr weit weg ist, und in die 
Instruktionen für relative Sprünge ("bl") die Adresse nicht als 
Immediate hinein passt.

Wicki W. schrieb:
> 0x0800ee84 <+4>:     movs    r1, r0
>    0x0800ee86 <+6>:     movs    r0, r0

An genau dieser Stelle steht die Adresse der Zielfunktion, "fastToggle". 
Der Disassembler disassembliert dies fälschlicherweise, da steht 
eigentlich einfach nur 0x00000001. Das entspricht zufällig diesen beiden 
sinnlosen "mov"-Instruktionen. Das "ldr.w   pc, [pc]" lädt diese Adresse 
in den PC, d.h. der Prozessor springt an eben diese Stelle, d.h. an 
0x00000001. Soweit also alles richtig, nur blöd dargestellt.

Wicki W. schrieb:
> Das sieht aber schräg aus:

Du hast ohne Optimierungen kompiliert... Die STR-Kette ist korrekt, aber 
die Schleife ist nicht sehr effizient, d.h. du solltest Jitter auf dem 
Signal sehen.

Wicki W. schrieb:
> Wie kommt er darauf, dass das "HAL_EXTI_D3_EventInputConfig" sein
> soll?

Wahrscheinlich wird diese (und andere) Funktionen wegoptimiert, aber das 
Symbol behalten und auf 0 gesetzt. Wenn der Disassembler aus der Adresse 
0 das zugehörige Symbol herausfinden will, gibt er das erstbeste zurück, 
und das war jetzt zufällig nicht fastToggle sondern 
HAL_EXTI_D3_EventInputConfig. Auch nicht ungewöhnlich, nur lästig.

Ich denke schon dass die Funktion jetzt korrekt aus dem ITCM-RAM 
ausgeführt wird. Eventuell ist die Busstruktur vom H7 so "tief" dass es 
wirklich nicht schneller geht. Vielleicht ist aber doch der Prescaler 
HPRE zu groß. Bei den älteren STM32F4 u.a. geht der IO-Zugriff IIRC in 2 
Takten, sofern man den Code aus dem RAM ausführt.

Hans-Georg L. schrieb:
> HAL_GPIO_TogglePin(LD1_GPIO_Port, LD1_Pin);

Wenn man HAL_GPIO_TogglePin nutzt sollte man prüfen ob das die aktuelle 
Version ist oder die alte nicht interrupt-sichere. Es sollte so 
aussehen:
1
/**
2
  * @brief  Toggle the specified GPIO pin.
3
  * @param  GPIOx where x can be (A..F) to select the GPIO peripheral for STM32F3 family
4
  * @param  GPIO_Pin specifies the pin to be toggled.
5
  * @retval None
6
  */
7
void HAL_GPIO_TogglePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
8
{
9
  uint32_t odr;
10
11
  /* Check the parameters */
12
  assert_param(IS_GPIO_PIN(GPIO_Pin));
13
14
  /* get current Output Data Register value */
15
  odr = GPIOx->ODR;
16
17
  /* Set selected pins that were at low level, and reset ones that were high */
18
  GPIOx->BSRR = ((odr & GPIO_Pin) << GPIO_NUMBER) | (~odr & GPIO_Pin);
19
}

Der Trick mit BSRR sorgt dafür dass auch wenn zwischen den letzten 
beiden Zeilen ein Interrupt einen anderen Pin auf dem selben Port 
ändert, dieser nicht direkt wieder zurückgesetzt wird. Alte Versionen 
der Funktion haben das mit
1
GPIOx->ODR ^= GPIO_Pin;

gemacht, was eben nicht Interrupt-sicher ist.

von Wicki W. (wicki)


Lesenswert?

Das klingt alles sehr logisch und erklärt
das Verhalten...

"du solltest Jitter auf dem Signal sehen"

Ich habe Sprünge zwischen 16.45 und 16.73 MHz.
Ganz selten taucht mal 17.01 auf.
Das habe ich für Messungenauigkeiten gehalten.
Aber das Signal zittert wirklich ein bisschen.
So um die 5 nS herum etwa.

von Wicki W. (wicki)


Lesenswert?

Nachtrag....
Cube steckt immer wieder voller Überraschungen:
Nun sagt er beim Klick auf .ioc: "rendering UI"....
und wenn er dann fertig ist, dann ist das UI ein weisser
Bildschirm (bzw. ein weisses Fenster).
Keine Fehlermeldung, kein Menue, keine Buttons.
Kein nichts....
Hat das schon mal wer so gehabt?

Geändert waren ein paar M7-Einstellungen, weil ich mal
sehen wollte, wie die sich auswirken.  (ob sinnvoll oder
nicht sei mal dahingestellt.)
Dass dann aber das ganze Cube-UI verschwindet, das hätte ich
so nicht erwartet.
Das .ioc aus dem Backup wieder zurück und dann ging es wieder.
1
12a13,21
2
> CORTEX_M7.CPU_DCache=Enabled
3
> CORTEX_M7.CPU_ICache=Enabled
4
> CORTEX_M7.DisableExec_Spec=MPU_INSTRUCTION_ACCESS_ENABLE
5
> CORTEX_M7.Enable_S-Cortex_Memory_Protection_Unit_Region1_Settings_S=__NULL
6
> CORTEX_M7.Enable_Spec=__NULL
7
> CORTEX_M7.IPParameters=CPU_ICache,CPU_DCache,default_mode_Activation,DisableExec_Spec,IsCacheable_Spec,IsBufferable_Spec,Enable_S-Cortex_Memory_Protection_Unit_Region1_Settings_S,Enable_Spec
8
> CORTEX_M7.IsBufferable_Spec=MPU_ACCESS_BUFFERABLE
9
> CORTEX_M7.IsCacheable_Spec=MPU_ACCESS_CACHEABLE
10
> CORTEX_M7.default_mode_Activation=1
11
157c166
12
< PC8.GPIOParameters=GPIO_Speed
13
---
14
> PC8.GPIOParameters=GPIO_Speed,PinState
15
159a169
16
> PC8.PinState=GPIO_PIN_SET

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.