H743 und F746 - Probleme mit dem Takt

OP #7508840
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 ?

#7509097
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 ...

(Firma: Schweigstill IT) Persönliche Seite #7509117
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.

(Firma: 1984now) #7509127
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.

OP #7509166
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.

(Firma: Schweigstill IT) Persönliche Seite #7509183
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?

#7509202
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

Persönliche Seite #7509224
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).

OP #7509306
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?

(Firma: Schweigstill IT) Persönliche Seite #7509401
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.

OP #7509488
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?

OP #7510193
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/

Persönliche Seite #7510196
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.

(Firma: Schweigstill IT) Persönliche Seite #7510293
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?

OP #7510323
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.

Persönliche Seite #7510325
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.

Persönliche Seite #7510354
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.

OP #7510370
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.

Persönliche Seite #7510380
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.

OP #7512929
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.

OP #7513228
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.

Persönliche Seite #7513237
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.

OP #7513309
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
Persönliche Seite #7513375
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.

OP #7513420
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.

OP #7513458
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

12
157c166
13
< PC8.GPIOParameters=GPIO_Speed
14
---
15
> PC8.GPIOParameters=GPIO_Speed,PinState
16

17
159a169
18
> PC8.PinState=GPIO_PIN_SET

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