Guten Tag,
ich lerne gerade den STM32F767 kennen (Nucleo-board) und hab mir gerade
'nen Wolf gesucht weil ich die Pins nicht schneller als 12,7 MHz toggeln
konnte
Den Pin bediene ich mit:
1
GPIOD->BSRR=0x04000000U;
2
GPIOD->BSRR=0x00000400U;
Irgendwann hab ich dann, warum auch immer, mal beim kompilieren von
Debug auf Release umgestellt. Also die Optimization von -O0 auf -O3.
Und siehe da die im Datenblatt angepriesenen 108MHz sind da :)
"Again what learned" sagt der Franzose ;)
Was mir jetzt noch unklar ist: wieso ich ziemlich präzise alle ms eine
Unterbrechung von ca 430ns habe
Bob A. schrieb:> Was mir jetzt noch unklar ist: wieso ich ziemlich präzise alle ms eine> Unterbrechung von ca 430ns habe
SysTick Timer Interrupt. Ohne Optimierung übersetzt der Compiler
ziemlich "dumm", sodass selbst so simple Register-Zugriffe und die
vermutlich drum herum gebaute Schleife um ein Vielfaches langsamer
werden.
Bob A. schrieb:> mal beim kompilieren von> Debug auf Release umgestellt
Das ist kein Wunder. In Debug-Versionen muss zusätzlicher Code eingefügt
werden (z.B. zur Anzeige von Zeilennummern im Sourcecode), und der muss
natürlich auch ausgeführt werden. Und einige Optimierungen werden nicht
angewendet, sonst erlebt man beim Debuggen komische Sachen wie fehlende
Codestücke.
Georg
Die Zeilennummern stehen nicht direkt im Code drin. Aber wenn man den
Optimizer frei arbeiten lässt, strukturiert er das Programm bis zur
Unkenntlichkeit um, so dass der Debugger Probleme bekommt, den
zugehörigen C-Quelltext wieder zu finden.
Man kann auch optimierten Code mit Debug-Informationen kompilieren. Der
Code selbst wird dadurch nicht beeinflusst, der Controller merkt keinen
Unterschied zwischen "Mit Debug Info" und "Ohne Debug Info". Es wird
lediglich die ELF Datei größer. Daher kann man das meist auch völlig
bedenkenlos machen. Die zusätzlichen Debug-Informationen in der ELF
Datei werden vom Debugger ausgewertet (typischerweise GDB) um z.B. zur
Adressen Code-Stellen zuzuordnen. Wie schon gesagt ist diese Zuordnung
bei eingeschalteter Optimierung etwas durcheinander was das Debugging
erschwert. Es ist aber manchmal unumgänglich, wenn ein Problem nur bei
eingeschalteter Optimierung auftritt, oder der Controller schlicht nicht
genug Flash für die unoptimierte Version hat.
Wobei "lahm legen" übertrieben ist. Auch bei voller Optimierung
funktioniert das Debugging an sich; die Abfolge der Anweisungen
innerhalb von Funktionen gerät durcheinander und lokale Variablen können
verschwinden/sich anders verhalten. Mit etwas Fummelei kann man dem
Programmablauf aber schon folgen.
Dr. Sommer schrieb:> Wobei "lahm legen" übertrieben ist. Auch bei voller Optimierung> funktioniert das Debugging an sich;
.. wenn man nicht die Debug Symbole ausgeschaltet hat. Das machen einige
IDEs als Vorgabe im Release Mode. Abhilfe: Wieder einschalten, sowohl
beim Compiler als auch beim Linker.
Weiterhin ist es eine große Hilfe wenn man das Disassembly wenigstens
lesen kann.
Ein Vergleich der Assembler Instruktionen und dem zugehörigen C Code
ergibt gelegentlich die Einsicht dass der Compiler ein paar Dinge findet
die man flashc programmiert hat.
Jim M. schrieb:> . Das machen einige IDEs als Vorgabe im Release Mode
Bloß warum... Die 1MB hat man auf seiner Festplatte ja noch. Das landet
ja wie gesagt nicht auf dem Controller...
Jim M. schrieb:> Weiterhin ist es eine große Hilfe wenn man das Disassembly wenigstens> lesen kann
Das sowieso ja... Wobei der optimierte Code mMn besser lesbar ist.
TIP: der F7 hat ITCM Speicher
mach dich schlau und lege die ISR und zeitkritische funktionen in diesem
Bereich ab
zugriffe aus dem flash haben bei den 216Mhz 7 Waitstates.
bei funktionen aus dem ITCM: 0
Dr. Sommer schrieb:> Bob A. schrieb:>> Was mir jetzt noch unklar ist: wieso ich ziemlich präzise alle ms eine>> Unterbrechung von ca 430ns habe>> SysTick Timer Interrupt. Ohne Optimierung übersetzt der Compiler> ziemlich "dumm", sodass selbst so simple Register-Zugriffe und die> vermutlich drum herum gebaute Schleife um ein Vielfaches langsamer> werden.
Die Pause alle ms hab ich auch mit -O3...
Wo kommt denn der SysTick her?
tgdfgdf schrieb:> TIP: der F7 hat ITCM Speicher> mach dich schlau und lege die ISR und zeitkritische funktionen in diesem> Bereich ab>> zugriffe aus dem flash haben bei den 216Mhz 7 Waitstates.> bei funktionen aus dem ITCM: 0
Vielen Dank für den Tipp!
Bislang denke ich dass es auch aus dem Flash raus schnell genug ist,
aber sowas im Hinterstübchen zu haben ist Gold wert :)
Bob A. schrieb:> Wo kommt denn der SysTick her?
Die HAL definiert den und braucht den IIRC auch. Der wird natürlich
nicht bei -O3 wegoptimiert, denn das ist ja gewünschte Funktionalität!
Wenn dich diese Unterbrechung stört, solltest du dein Konzept
überdenken. Pins mit 108MHz in Software togglen klingt nicht besonders
sinnvoll.
Und vielen Dank an alle die beim Thema debug / Optimierer für beseres
Verständnis gesorgt haben!
Sehr gut zu wissen, und -Og bringt noch einen ordentlichen Schub, da
komm ich immerhin auf 21MHz.
Das könnte für das Projekt ausreichen falls doch mal parallel am Oszi
und im Quelltext debugged wird!
Dr. Sommer schrieb:> Bob A. schrieb:>> Wo kommt denn der SysTick her?>> Die HAL definiert den und braucht den IIRC auch. Der wird natürlich> nicht bei -O3 wegoptimiert, denn das ist ja gewünschte Funktionalität!> Wenn dich diese Unterbrechung stört, solltest du dein Konzept> überdenken. Pins mit 108MHz in Software togglen klingt nicht besonders> sinnvoll.
Ist es ja auch nicht, aber diese kleine Experimentchen helfen mir beim
Kennenlernen und Verstehen.
Die mit -O0 gemessenen 12MHz waren aber evtl etwas lahm - und wenn der
µC 108MHz können sollte ist es offensichtlich das man etwas falsch
gemacht hat ;)
Ob's stört muss sich herausstellen, denke aber bereits zum jetzigen
Zeitpunkt ob ich nicht auf die HAL verzichten sollte. Aber es ist nunmal
sooo bequem ;-)
dann pack den M7 mal richtig voll .. ^^
die Speicherbereiche sind auch sehr witzig.
bei mir sind es
16K ITCM ( für funktionen )
224K SRAM1 ( allgemeinkram )
16K SRAM2 ( für ethernet )
64k DTCM ( für schnelle sachen , RTOS stack )
problem ist da das originale linkerfile...
der packt den Stack ans ende vom "RAM ( 320k )" was am ende des SRAM2
ist
Der ist langsamer und ist cacheable was irgendwann beim RTOS schonmal
für verwirrung sorgt ^^
Wenn man diverse blöcke belegt und er kommt irgendwann über die grenze
der ersten 64k( was DTCM ist ) und will in den SRAM1 wirds auch
witzig.
Die DMA geschichte funktioniert nur zuverlässig aus SRAM1 oder SRAM2
Wenn man dann sich wundert warum das Gerät am anfang bei funktion X so
schnell war und nun plötzlich langsamer läuft ... hat das 2 ursachen:
RAM bereiche im .map irgendwo anders
Der jump im flash ist größer und er muss den ART komplett umladen
Der M7 hat mich schon so manchen nerv gekostet ^^
Aber er ist gut.
Johnny B. schrieb:> Ich nutze normalerweise nur noch folgende Optimierungsoptionen beim GCC:>> Debug> -Og (Code wird optimiert, kann aber dennoch gedebuggt werden)>> Release> -Os (Kleine Grösse aber dennoch normalerweise schnellerer Code als bei> -O2)
Der Witz ist ja, das -Os sämtliche Optimierungen von -O2 beinhaltet,
außer jenen die zusätzlichen Speicherplatz kosten. Auf Grund der
Waitstates ist aber kompakterer Code häufig auch schneller. -O2 und -Os
geben sich aber meistens nicht so viel, weder beim Platz noch bei der
Geschwindigkeit. Bei -O3 sieht die Sache schon ganz anders aus. Da
werden dann eben auch mal Schleifen ausgerollt und ein dämliches delay()
müllt den Flash mit sinnlosen NOPs voll. -O3 macht, gerade wegen der
Waitstates, auf Cortex-M nur sehr selten Sinn. Es erzeugt eigentlich
immer größeren Code als -O2 und am Ende ist der dann oft sogar doch noch
langsamer. Für ausgewählte, zeitkritische Funktionen mag -O3 aber
mittels Compilerdirektive trotzdem Sinn machen.
Oder die Compilerdirektive kommt fors die nop Delayschleife ;)
Die Flash Waitstates werdem ja bei immer mehr ARM SoCs durch mini Caches
am Flash wegabstrahiert.
Da werden dann 128Bit aus dem Flash geladen und dann liegen die da bis
alle 16Bit Thumbs abgeholt wurden (manchmal auch 32Bit).
Zudem bemerken diese Caches wann sie drohen leerzulaufen und laden weder
128Bit nach. Da bekommt man die Waitstates also erst bei sprüngen wider
zu sehen.
Daher ist das loop unrolling bei dieser Art Cache eigentlich von
Vorteil?
Mw E. schrieb:> Daher ist das loop unrolling bei dieser Art Cache eigentlich von> Vorteil?
Na eben nicht! Bei einer normalen Schleife passt vielleicht der ganze
Code in den Cache, so kann die Schleife im günstigsten Fall ganz ohne
Flash-Zugriff laufen. Eine ausgerollte Schleife passt ggf. eher nicht
hinein und erfordert mehr Flash-Zugriffe. Sprünge kosten aber auch Zeit,
die Prozessoren mit Branch Prediction (Cortex-M7!) reduzieren können.
Letztlich hängt es vom Einzelfall ab und muss individuell gemessen
werden.
Das muss dann aber eine kleine Schleife sein, denn 129/16 sind 8 befehle
Maximum. (bei den STM32F4 zB).
Dr. Sommer schrieb:> Letztlich hängt es vom Einzelfall ab und muss individuell gemessen> werden.
Ja da ist das Problem ;)