Forum: Mikrocontroller und Digitale Elektronik STM32: Timer-ISR löst 2x aus - Fehler im Flag-Reset bei Optimierung O3


von STM32-User (Gast)


Angehängte Dateien:

Lesenswert?

Ich möchte euch ein sehr merkwürdiges Problem schildern, welches bei 
Optimierungen > O0 auftritt:

Eine Timer-ISR ist so konfiguriert, daß sie jede Millisekunde auslöst. 
Ohne Optimierung funktioniert dies wie erwartet.
Beim Optimierungslevel O3 findet eine doppelte Auslösung statt (ca 400ns 
nach der ersten)

Ich habe sehr lange gebraucht, um hierfür einen "Workaround" zu finden- 
die letzte Anweisung in der ISR ist eine "ohne effekt", die jedoch dazu 
führt, daß wieder das normale Verhalten eintritt , d.h. die ISR genau 1x 
aufgerufen wird.

Zum Nachvollziehen eine kleine STM32-Applikation, die bei jedem IRQ 
einen kurzen High-Puls am GPIO3 vollzieht,  danach das Timerflag 
rücksetzt.

Man kann mit einem Oszi 1 oder 2 Pulse sehen, wenn man mit O3 
kompiliert: - 1 pulse wenn die letzte aktion aktiv ist: "TimeTick;"  (no 
effekt statement, welches aber den 2. pulse unterdrückt)
- 2 pulse  wenn nach dem Rücksetzen des Statusregisters nichts mehr 
kommt


Hierzu habe ich 2 Fragen und würde mich freuen, wenn ein STM32 Experte 
seine Weisheit mit mir teilen würde:

1) Wodurch genau kommt der Fehler zustande - die Registerbelegungen des 
Timers ist exakt identisch.

2) Kann es sich um einen GCC Optimierungsfehler handeln?  (Timingfehler 
, ein fehlendes NOP sozusagen,  welches ich mit dem "no return 
statement" erzwinge?)
=> falls es in die Richtung geht,  verstehe ich eines nicht:
ob mit oder ohne TimeTick;  ,   die Größe des erzeugten Bin-Files ist 
identisch.   (da ich im ASM nicht soo fit bin, habe ich hier noch kein 
Vergleich durchgeführt, werde dies morgen mal genauer analysieren)


Vielen Dank im Voraus für jegliche Anregungen oder Ideen, die mich auf 
des Rätsels Lösung bringen

Anmerkung: Nutzt man die eingebaute "rücksetz-Funktion" der STM periph. 
libary, tritt dieses Verhalten ebenso nicht auf.
Da ich die Routine jedoch später im RAM laufen lassen muß, habe ich 
jegliche Flash-routinen in den RAM "portiert"  - und danach trat es 
auf..

von Dr. Sommer (Gast)


Lesenswert?

Das Update-Flag bei den STM32-Timern ist ein bisschen schräg. Verschiebe 
die Anweisung mit dem TIM_IT_Update an den Anfang der ISR. Poste auch 
mal die dissassembly der -O0 und -O3 Varianten, das ist das wichtigste 
bei Optimierer-Problemen...

von holger (Gast)


Lesenswert?

>Das Update-Flag bei den STM32-Timern ist ein bisschen schräg.

Man sollte die Interrupt Flags ganz am Anfang der ISR löschen.
Tut man es zu weit hinten, kann es passieren das die ISR verlassen
wird bevor das Flag wirklich zurückgesetzt wurde. Und schwupps
landet man ein zweites mal in der ISR.

von STM32-User (Gast)



Lesenswert?

Hier nun die beiden Assembly Listings der ISR - jeweils direkt vor 
"Main" abgeschnitten..

Im direkten Vergleich bemerkt man einige unterschiede - es deutet alles 
darauf hin, daß Eure Annahme richtig war,  denn im "Workaround" ist vor 
dem Rücksprung noch ein zusätzlicher Befehl  -> damit vermutlich genug 
Zeit das Register rückzusetzen bevor der INT verlassen wird.


Eine Kleinigkeit fiel mir noch auf -  einmal ist hinter dem Rücksprung 
noch ein NOP vorhanden, ein anderes mal fehlt es.

So ganz wird mir dessen Existenzgrund nicht klar - ist dies evtl ein 
anderer "workaround" für den Kommando-Pipeliner, dessen Sequenz ja durch 
den HW-INT irgendwo unterbrochen wurde und der nun zurückspringen muß? - 
die Frage wäre nur, warum das NOP nur in einem der Fälle und nicht 
generell?!?


Vielen Dank im Voraus für eure Zeit und eure Ratschläge!

ein dankbarer STM32-User

von STM32-User (Gast)


Lesenswert?

Euer Rat ist eindeutig Gold wert -  Sowas gehört als Warnung ganz Dick 
gedruckt ins Datenblatt :)

Danke für diesen Tipp!

Da der Thread nun eigentlich abgeschlossen ist, hätte ich eine 
philosophische Frage:

Wie wäre dieser Fehler einzuordnen -  müßte der Compiler bei 
entsprechenden Optimierungen nicht ein zusätzliches NOP zur Sicherheit 
einfügen?  (-> da es ja eindeutig nur bei best. Optimierungen auftritt)

Oder ist die Ursache eher im Silikon zu suchen,  da offensichtlich das 
Löschen des Registers und Update des Interrupt-Handlers nicht zeitgleich 
passieren, sodaß im "fehlerfall" die ISR im Anschluß direkt nochmal 
aufgerufen wird?


Euch Beiden eine angenehme Restwoche und nochmal vielen Dank für eure 
Mühe!

der immer wieder dazulernende
STM32-User

von Ingo (Gast)


Lesenswert?

Ich bin auch auf diesen Fehler beim InputCapture gefallen, irgendwo 
stand mal genau erklärt wie der Fehler zu Stande kommt. Weiß aber nicht 
mehr wo

von (prx) A. K. (prx)


Lesenswert?

STM32-User schrieb im Beitrag #3372931:
> Wie wäre dieser Fehler einzuordnen -  müßte der Compiler bei
> entsprechenden Optimierungen nicht ein zusätzliches NOP zur Sicherheit
> einfügen?  (-> da es ja eindeutig nur bei best. Optimierungen auftritt)

Das ist nun aber definitiv nicht Sache des Compilers. Das ist auch kein 
Fehler, weder beim Compiler noch in der Hardware. Sondern das ist 
einfach nur etwas, auf das der Programmierer achten muss.

Wenn du AVRs kennst, dann kennst du vielleicht den Effekt, dass ein 
Input-Befehl, der unmittelbar auf einen Output-Befehl folgt, nicht 
sicher den Zustand eines dadurch geänderten Pins erfassen kann. Weil im 
Ablauf das eine oder andere taktgesteuerte Flipflop dazwischen sitzt.

> Oder ist die Ursache eher im Silikon zu suchen,  da offensichtlich das
> Löschen des Registers und Update des Interrupt-Handlers nicht zeitgleich
> passieren, sodaß im "fehlerfall" die ISR im Anschluß direkt nochmal
> aufgerufen wird?

Aufgrund des exakten Ablaufs in der Hardware ist es völlig normal, dass 
der Zustand des Interrupt-Systems ein ganz klein wenig dem vom 
Programmierer wahrgenommenen Programmablauf hinterher hinkt. ARM hatte 
beim Design der Cortex-M die Interrupt-Verarbeitung durch Prozessors 
aber sehr effizient gestaltet. Und hat damit nun manchen Programmier 
überholt. ;-)

Bei anderen Architekturen landen in Interrupt-Handlern meist noch 
diverse Befehle zwischen der letzten C Anweisung und dem Return. Dieser 
Wasserkopf in Interrupt-Handlern sorgt üblicherweise dafür, dass dein 
Problem nicht auftritt. Bei den Cortex-M gibts den aber nicht, folglich 
muss man selber ein wenig aufpassen.

: Bearbeitet durch User
von STM32-User (Gast)


Lesenswert?

A. K. schrieb:
>> Wie wäre dieser Fehler einzuordnen -  müßte der Compiler bei
>> entsprechenden Optimierungen nicht ein zusätzliches NOP zur Sicherheit
>> einfügen?  (-> da es ja eindeutig nur bei best. Optimierungen auftritt)
>
> Das ist nun aber definitiv nicht Sache des Compilers. Das ist auch kein
> Fehler, weder beim Compiler noch in der Hardware. Sondern das ist
> einfach nur etwas, auf das der Programmierer achten muss.
>
> Wenn du AVRs kennst, dann kennst du vielleicht den Effekt, dass ein
> Input-Befehl, der unmittelbar auf einen Output-Befehl folgt, nicht
> sicher den Zustand eines dadurch geänderten Pins erfassen kann. Weil im
> Ablauf das eine oder andere taktgesteuerte Flipflop dazwischen sitzt


Danke für die Einordnung -   wenn dies definitiv ein "Programmierer muß 
das Wissen"-Ding ist, dann frage ich mich, wieso dies nicht in der 
Beschreibung des Systemverhaltens (==> in der Doku/Datenblatt) 
beschrieben wird,  sondern selbst in den Beispielen oft ganz zum Schluß 
as Flag gesetzt wird, was dem Nutzer extrem schwierig zu debuggende 
Fehler unterschiebt.
Ich habe nun dazugelernt, frage mich aber wirklich, wie weit dieses 
Wissen wohl verbreitet ist  und wieviel Prozent der Projekte einfach nur 
"Glück in Ihrer Unwissenheit haben", da sie längere Funktionen am ende 
des ISRs haben.

Erlaube mir deshalb folgende Behauptung:
Wenn syntaktisch richtiger Code in einer Hochsprache übersetzt wird, 
sollte dies unabhängig von der Optimierung zu gleichem Systemverhalten 
führen.
Ist diese Annahme etwa zu naiv?

Gibt es einen allgemeingültigen "Sicheren Weg"/Tutorial/Guideline, 
solche Probleme zu vermeiden?

(diesmal trat der fehler am Anfang der Entwicklung auf, es war daher 
noch halbwegs übersichtlich. Tritt soetwas später und sporadisch auf, 
ist das u.U. Projektgefährdend, da man irsinnig viel Zeit darauf 
verwendet bis man einen solchen Fehler überhaupt reproduzierbar und 
damit analysierbar kriegt.)


Die "IO-Problematik" bei AVRs kenne ich, stufte sie jedoch als absolut 
irrelevant ein, da meiner Ansicht nach keine Notwendigkeit besteht, 
sofort nach dem setzen eines Outputs Pins dessen input-register zu 
lesen:
1. I.D.R hat man den outputwert ohnehin in irgendeiner Variablen
2. kann man ja auch das output register nehmen, welches (sofern mich 
meine Erinnerung nicht täuscht) immer den korrekten Wert enthält

Für mein Verständnis sind es 2 paar Schuhe, ob ein IO regelmäßig falsch 
gelesen wird oder eine Interuptroutine ohne erkennbaren und debugbaren 
Grund 2x hintereinander ausgeführt wird.
Ohne ein schnelles Oszi und einige Stunden Sucherei ist der Fehler IMHO 
gar nicht zu finden, (sofern er einen ohne das nötige Vorwissen ereilt)

Durch Eure Beiträge habe ich nun wieder etwas dazugelernt  und stehe 
deshalb tief in Eurer Schuld - vielen Dank!


Über jegliche Tipps, wie ich (und jeder spätere Leser dieses Threads) 
solche oder ähnliche Fallstricke gezielt vermeiden kann, würde ich mich 
natürlich sehr freuen.

von (prx) A. K. (prx)


Lesenswert?

STM32-User schrieb im Beitrag #3373167:
> Wenn syntaktisch richtiger Code in einer Hochsprache übersetzt wird,
> sollte dies unabhängig von der Optimierung zu gleichem Systemverhalten
> führen. Ist diese Annahme etwa zu naiv?

Nur bezogen auf jene Aspekte, die zur Sprache C gehören. Das 
Laufzeitverhalten von Interrupt-Systemen oder I/O-Bausteinen in den 
erzeugten Code einzubeziehen ist jedoch eindeutig nicht Sache des 
Compilers.

von (prx) A. K. (prx)


Lesenswert?

STM32-User schrieb im Beitrag #3373167:
> Die "IO-Problematik" bei AVRs kenne ich, stufte sie jedoch als absolut
> irrelevant ein, da meiner Ansicht nach keine Notwendigkeit besteht,
> sofort nach dem setzen eines Outputs Pins dessen input-register zu
> lesen:

Das ist ziemlich direkt zur hiesigen Situation vergleichbar. Es wird ein 
Bit in einer I/O-Komponente zurückgesetzt, nämlich die Interrupt-Leitung 
des Timers, und anschliessend über den Interrupt-Controller vom 
Prozessor als Teil des Return-Befehls wieder ausgelesen.

Ein Beispiel, wo eine solche Sequenz bei AVRs leicht vorkommen kann, ist 
die Abfrage einer Tastaturmatrix. Es muss ja nicht das gleiche Portbit 
sein, um das es geht. Wenn man da nicht explizit ein NOP einschiebt, 
dann kriegt man bei den ATmegas Probleme, die man bei den alten 
AT890Sxxxx mangels Sync-Register am Eingang nicht hatte. Sollte avr-gcc 
vor jeden Lesebefehl ein NOP einschieben?

PS: Der ARM Compiler weiss bei den Cortex-M überhaupt nicht, ob er es 
mit einer Interrupt-Routine zu tun hat oder mit einer normalen Funktion. 
Anders als bei anderen Architekturen üblich sind die aus dessen Sicht 
identisch.

: Bearbeitet durch User
von STM32-User (Gast)


Lesenswert?

OK - wenn dem so ist, dann bin ich wohl dem falschen Pferd aufgesessen, 
daß sich der Compiler für eine bestimmte Hardwarearchitektur drum 
kümmern sollte

(könnte ich dies entscheiden, würde ich es definitiv als "must have" für 
alle Compiler festlegen - warum? Effizienz, Robustheit, standardisiertes 
Verhalten - eben die gründe, für die man eine Hochsprache i.d.R 
einsetzt)

gibt es sowas wie eine Wissensdatenbank ala "für Proz.X  füge n 
waitstates ein oder mache es am besten so... , für Proz.Y  ists egal..." 
?


OT: manchmal wünsche ich mir die gute alte AVR-Assembler Zeit zurück...
Ok, die programme von damals hatten weniger Funktionalität, doch ob Ihr 
es glaubt oder nicht, damals dauerte es zwar etwas länger bis ein 
Programm fertig war, dafür hatte es aber auch WESENTLICH weniger Fehler 
und lief ungleich Stabiler.

von STM32-User (Gast)


Lesenswert?

Kleine Anmerkung:  ob ISR oder nicht müßte der Compiler herauskriegen 
können.
OK - nennen wir es nicht Compiler, nennen wir es "Präprozessor ähnlicher 
Optimierer / graue Haare Verhinderer" :)

Danke für Deine Ausführung. Verstehe jetzt was Du meinst,  überlege mir 
nur gerade, wie man soetwas durch standardisierte Prozesse in einem 
Unternehmen verhindern könnte..

von obscurity (Gast)


Lesenswert?

STM32-User schrieb im Beitrag #3373167:
> Erlaube mir deshalb folgende Behauptung:
> Wenn syntaktisch richtiger Code in einer Hochsprache übersetzt wird,
> sollte dies unabhängig von der Optimierung zu gleichem Systemverhalten
> führen.
> Ist diese Annahme etwa zu naiv?

Ja, das ist absolut zu naiv. Die Interruptflags gehören zum Registersatz 
der Peripherie und nicht zum Cortex-Kern. Wie schnell die über die 
internen Busse angebunden sind kann der Compiler nicht wissen. Wenn das 
Zeitverhalten bei allen Optimierungsstufen gleich wäre, wozu wird da 
überhaupt optimiert? Also das Verhalten was du hier erlebt hast wurde 
hier schon beschrieben. Irgendwann fällt jeder mal auf sowas rein.
Man muss bei den Cortexen immer im Hinterkopf haben, dass die gesamte 
Peripherie über die AHB-Busse angebunden ist. Teilweise kann deren 
Taktrate auch noch deutlich nach unten geschraubt werden. Das würde die 
Effekte noch verstärken. Eventuell kannst du ja das Register nochmal 
lesen nach dem Schreiben. Ich denke an der Stelle wartet dann die CPU 
bis das Register gelesen ist. Das muss man dann aber auch so geschickt 
machen dass der Compiler das nicht wegoptimiert.

von (prx) A. K. (prx)


Lesenswert?

STM32-User schrieb im Beitrag #3373206:
> Kleine Anmerkung:  ob ISR oder nicht müßte der Compiler herauskriegen
> können.

Bei klassischen ARMs ist das so, weil ISRs einen gänzlich anderen 
Wasserkopf haben als normale Funktionen. Nicht aber bei den Cortex-M.

> OK - nennen wir es nicht Compiler, nennen wir es "Präprozessor ähnlicher
> Optimierer / graue Haare Verhinderer" :)

Ja, den Do-What-I-Mean-Not-What-I-Say Compiler hätten viele gerne. C ist 
halt seit jeher andersrum konzipiert. :-)

von (prx) A. K. (prx)


Lesenswert?

obscurity schrieb:
> Das muss man dann aber auch so geschickt
> machen dass der Compiler das nicht wegoptimiert.

Wird er nicht, weil volatile. Der Prozessor auch nicht, weil in einem 
Adressraum mit klarer Zugriffsreihenfolge (memory ordering).

: Bearbeitet durch User
von (prx) A. K. (prx)


Lesenswert?

obscurity schrieb:
> Man muss bei den Cortexen immer im Hinterkopf haben, dass die gesamte
> Peripherie über die AHB-Busse angebunden ist.

Eher die APB Busse. Der AHB ist der schnelle vorne, die oft mehreren 
APBs sind die teils langsameren weiter draussen.

von obscurity (Gast)


Lesenswert?

A. K. schrieb:
> Ja, den Do-What-I-Mean-Not-What-I-Say Compiler hätten viele gerne. C ist
> halt seit jeher andersrum konzipiert. :-)

Ich frage mich was das mit C und dem Compiler zu tun hat. Das selbe 
würde dir im Assembler passieren. Der Hersteller der CPU und nicht ARM 
steht vor der Entscheidung ob immer und überall oder nur bei bestimmten 
Registern Waitstates eingeschoben werden bis zum wirklichen Updates der 
Register. Hat er in deinem Fall aber nicht. Das würde ja auch die eine 
oder andere Benchmarkzahl verschlechtern und das ist ein NoGo. Sicher 
wird das auch in 99,9..% nicht benötigt. Und der Rest fällt einmal 
darauf rein und dann nie wieder.
Der Compiler weiss weder ob dein Programm im Flash oder im Ram läuft und 
ob du die Vektoren zur Laufzeit änderst oder nicht. An was soll er das 
denn festmachen? Und soll er jedesmal 10ms Waitstates als Vorsorge 
einschieben nur weil einer auf die Idee kommen könnte den AHB-Takt auf 
10khz zu drehen um Strom zu sparen?

von obscurity (Gast)


Lesenswert?

A. K. schrieb:
> Eher die APB Busse. Der AHB ist der schnelle vorne, die oft mehreren
> APBs sind die teils langsameren weiter draussen.

Ja klar. Wenn man es genau nimmt hast du natürlich Recht. Ändert aber 
nichts an der Tatsache, dass vom Setzten eines Registers in der CPU bis 
zu dem Zeitpunkt an dem das Register wirklich gesetzt ist immer eine 
Zeit x vergeht die der Compiler nicht kalkulieren kann.

A. K. schrieb:
> Wird er nicht, weil volatile. Der Prozessor auch nicht, weil in einem
> Adressraum mit klarer Zugriffsreihenfolge (memory ordering).

Wenn es so ist, dann ist es ja gut. Ich wollte mich hier nicht soweit 
aus dem Fenster lehnen und das ungetestet für alle Optimierungen zu 
behaupten. Fakt ist, bei mir hat das nachträgliche Lesen des Registers 
geholfen. Ob es aber nur an der zusätzlichen Zeit des Befehls lag oder 
ob da Waitstates eingeschoben werden kann ich nicht mit Gewissheit 
sagen.

von STM32-User (Gast)


Lesenswert?

A. K. schrieb:
>> Kleine Anmerkung:  ob ISR oder nicht müßte der Compiler herauskriegen
>> können.
>
> Bei klassischen ARMs ist das so, weil ISRs einen gänzlich anderen
> Wasserkopf haben als normale Funktionen. Nicht aber bei den Cortex-M.

Achso? - Ich dachte durch die ISR Sprungtabelle, die ja direkt auf die 
betreffenden Kandidaten zeigt, kriegt ein Compiler dies raus...
Aber ich kenne mich zu wenig mit den Internas der Compiler aus - 
vermutlich wäre dies zu hardwarespezifisch oder zu komplex, auf einzelne 
Register-setzen Befehle zu schauen (ISR-Tabellen-Vektor ist ja im 
Register gehalten und könnte sich gemeinerweise noch zur Laufzeit 
ändern)..

So langsam ergibt alles einen Sinn :)

Der Traum vom "do what I mean not what I say" compiler ist leider viel 
zu schön um wahr zu sein :)..

Als Alter Realist wäre ich trotzdem wenigstens für ein "behave like I 
said" (without assuming I have in depth hardware timing knowledge) 
compiler.
Vermutlich gibt es die sogar für teuer Geld von Keil&Co zu kaufen..

Schön, hier ein Forum zu haben, in dem es nach wie vor konstruktive 
Leute mit Ahnung gibt.

OT: mal eine Frage -  wie haltet ihr es eigentlich aus, bei dauerhaft 
">20 Einträge pro Tag" die sinnvollen herauszufiltern und diese auch 
noch kompetent zu beantworten?

Ich würde vermutlich nach einigen Wochen einfach keinen Bock mehr auf 
das zehntausendste "welcher 8 bitter ist von allen der beste" Themen 
haben,  wohingegen eine (1!) Übersicht über Eignung und Anwendungsfälle, 
gegenübergestellte Vor- und Nachteile ohne Frage äußerst interessant 
wäre.


Also vor eurer Einstellung und euer Durchhaltevermögen empfinde ich 
wirklich tiefen Respekt - Hut ab!!

von STM32-User (Gast)


Lesenswert?

obscurity schrieb:
> Ja, das ist absolut zu naiv. Die Interruptflags gehören zum Registersatz
> der Peripherie und nicht zum Cortex-Kern. Wie schnell die über die
> internen Busse angebunden sind kann der Compiler nicht wissen. Wenn das
> Zeitverhalten bei allen Optimierungsstufen gleich wäre, wozu wird da
> überhaupt optimiert?

Danke für den Hinweis - jetzt weiß ich wenigstens woher die Probleme 
kommen
Ich dachte, da der NVIC doch jetzt angeblich im Kern integriert wäre, 
würden das Rücksetzen der ISR-Flags in der ISR schon via Hardware so 
synchronisiert sein, daß der (viel zu schnelle kern) nicht gleich 2x 
auslöst..

Ich muß zugeben, daß ich an eine zu langsame Synchronisierung von 
Peripherie-Status-Registern" überhaupt nicht gedacht habe -  ging 
blauäugig davon aus, daß diese intern synchronisiert werden "bevor 
irgendwas böses passiert"
-> dafür hat mir meine Applikation halt auch ein blaues Auge verpaßt :)

Ich finde allerdings, daß diese Info in den Peripheriebeschreibungen 
fehlt- es ist einfach nicht oder wenn dann äußerst unzureichend erwähnt.
Beispielsweise eine Berechnung, wieviele Waitstates eingefügt werden 
müssen wenn CPUTakt X  und Peripherietakt Y ist.
Gibt es soetwas für STM32?   - habe dergleichen noch nicht gesehen..

Wäre ja nötig um sicherzugehen, daß auch in zukünftigem Code (ggf. bei 
veränderter Taktrate) alles sauber läuft.

von (prx) A. K. (prx)


Lesenswert?

STM32-User schrieb im Beitrag #3373298:
> Achso? - Ich dachte durch die ISR Sprungtabelle, die ja direkt auf die
> betreffenden Kandidaten zeigt, kriegt ein Compiler dies raus...

Du solltest mal versuchen, die Ebenen von Compiler und Maschine 
auseinander zu halten. Nicht jedes Array mit Zeigern auf Funktionen drin 
ist eine ISR-Sprungleiste.

> Aber ich kenne mich zu wenig mit den Internas der Compiler aus -
> vermutlich wäre dies zu hardwarespezifisch oder zu komplex, auf einzelne
> Register-setzen Befehle zu schauen (ISR-Tabellen-Vektor ist ja im
> Register gehalten und könnte sich gemeinerweise noch zur Laufzeit
> ändern)..

Das kann man wohl sagen. Es hätte beispielsweise zur Folge, dass man für 
jedes neue Registerbit eine neue Compilerversion bräuchte. Ein Alptraum.

> Vermutlich gibt es die sogar für teuer Geld von Keil&Co zu kaufen..

Woh kaum. Mit etwas Glück hast du bessere Doku und eine Liste gängiger 
Fallstricke. C ist nach dem Motto "Schrott rein, Schrott raus" gebaut. 
Egal ob GNU oder Keil.

> OT: mal eine Frage -  wie haltet ihr es eigentlich aus, bei dauerhaft
> ">20 Einträge pro Tag" die sinnvollen herauszufiltern und diese auch
> noch kompetent zu beantworten?

Indem man sich über die anderen Fälle lustig macht. Ok, das sehen diese 
Leute dann nicht immer so positiv. ;-)

von Ralf G. (ralg)


Lesenswert?

A. K. schrieb:
> Das
> Laufzeitverhalten von Interrupt-Systemen oder I/O-Bausteinen in den
> erzeugten Code einzubeziehen ist jedoch eindeutig nicht Sache des
> Compilers.

Oder vielleicht doch? Z.B. AVR: Die Assembler-Instruktion 'sei' wird vor 
einem letzten 'pop' eingefügt.

von STM32-User (Gast)


Lesenswert?

beim AVR wurden die "Peripherie-Stati" (die ja angenehmerweise im Kern 
waren) automatisch zurückgesetzt.

- schön robust,  gut durchdacht und ne Runde Sache meiner Meinung nach.

Wird echt zeit, daß Atmel oder irgendwer sonst mal wieder was nachlegt 
in dieser Richtung :)

von STM32-User (Gast)


Lesenswert?

das "unschönste" am AVR waren immernoch die Klimmzüge, mit denen man im 
Programm Konstante Daten aus dem Flash laden mußte und die Tatsache, daß 
kein Code aus externem Speicher ausgeführt werden konnte.

(unschön in dem Sinne nur deshalb, weil progmem eben 
Architekturspezifisch war und nicht mit einem "quasi-standard" zugriff 
via const char * ptr  ging.. )
Somit war der ganze mit progmem durchsetzte Code nicht mehr so einfach 
portierbar...

von STM32-User (Gast)


Lesenswert?

Ralf G. schrieb:
> Oder vielleicht doch? Z.B. AVR: Die Assembler-Instruktion 'sei' wird vor
> einem letzten 'pop' eingefügt.

also würde in folgendem Code automatisch die Interrupts aktiviert 
werden?
das wäre ja der Tod für jede größere ISR, da diese dann vorzeitig durch 
andere interrupts unterbrochen werden könnte..

Woher hast du diese Info -  oder habe ich etwas falsch verstanden?!?



....
cli

push R16

nop

pop R16

....

INTs nun aktiv  ohne SEI ?

von Ralf G. (ralg)


Lesenswert?

STM32-User schrieb im Beitrag #3373362:
> das wäre ja der Tod für jede größere ISR
nee, nee.

Meine Aussage bezog sich nur darauf, dass der Compiler sich nicht um 
Hardware-Eigenheiten kümmert.

Der konkrete Sachverhalt wurde in einem älteren Thread mal erklärt. In 
einem Programm von mir ist mir das mal aufgefallen. Ich weiss nicht mehr 
in welchem Programm und in welchem Zusammenhang. Ich suche noch...

Ich glaube, mir fällt langsam wieder ein, was da gemacht wurde: Die 
Wiederherstellung von SREG wurde um einen Befehl vorgezogen.

von (prx) A. K. (prx)


Lesenswert?

Ralf G. schrieb:
> Oder vielleicht doch? Z.B. AVR: Die Assembler-Instruktion 'sei' wird vor
> einem letzten 'pop' eingefügt.

Das Laufzeitverhalten des Prozessors selbst wird schon eingerechnet, so 
wie es der Befehlsreferenz dokumentiert ist. Nicht Bestandteil davon ist 
aber die Peripherie, wie NVIC, Timer etc.

Teil des dokumentierten Verhaltens ist, dass die ISR-Return Operation, 
also ein BR LR mit entsprechender Pseudoadresse, anfangs den Zustand des 
Interrupt-Requests abfragt, um daraus die optimierte Abarbeitung 
weiterer Interrupts abzuleiten.

Irgendwelche Kopplungen zwischen Timer- oder NVIC-Registern und dem am 
Core auflaufenden Interrupt-Signal gehören aber ebenso wenig dazu, wie 
das exakte Zeitverhalten der von ST, TI oder NXP implementierten 
Busssysteme.

Compiler sind Werkzeuge. Wie eine Axt. Es wäre wohl vermessen, den 
Hersteller der Axt zu beauftragen, nur Axte erzustellen, die garantiert 
keinen Finger abhacken können. Du musst schon selbst drauf achten, dass 
keiner im Weg ist.

von (prx) A. K. (prx)


Lesenswert?

STM32-User schrieb im Beitrag #3373362:
> also würde in folgendem Code automatisch die Interrupts aktiviert
> werden?

In eine ISR gehört kein SEI, es sein denn man will Schachtelung 
erlauben.

Was vmtl. gemeint war: Der AVR Compiler erzeugt als Teil des Wasserkopfs 
von Funktionen Code, der einen 16-Bit Stackpointer atomar ändert. Das 
geht nur bei abgeschalteten Interrupts. Und darin findet SEI genau vor 
dem letzten relevanten Befehl statt, was schon manche irritiert hat. Nur 
wird bei bisher abgeschalteten Interrupts der Folgebefehl von SEI 
immer direkt anschliessend ausgeführt.

Damit wird also eine bestimmte Eigenschaft des Prozessorkerns 
ausgenutzt, um die Interrupt-Latenz zu minimieren.

: Bearbeitet durch User
von (prx) A. K. (prx)


Lesenswert?

Ralf G. schrieb:
> Meine Aussage bezog sich nur darauf, dass der Compiler sich nicht um
> Hardware-Eigenheiten kümmert.

Wenn du mit Mehrkern- und Mehrprozessorsystemen arbeitest, wie in 
heutigen PCs oder Handys, und ein Programm mit mehreren Threads laufen 
lässt, dann kriegst du je nach Prozessor und Problem noch ganz andere 
Schweinereien auf den Tisch.

Dann musst du nämlich bei Nutzung gemeinsamer Variablen u.U. auch noch 
selber drauf achten, dass diese Variablen in der richtigen Reihenfolge 
im Speicher landen, weil sich das nicht nur durch Optimierung des 
Compilers, sondern auch durch Optimierung innerhalb Prozessors anders 
darstellen kann, als es aus dem C Quellcode ersichtlich ist.

Dann kann es sein, dass du manchen Code mit Memory-Barrier Befehlen 
spicken musst, um diese Reihenfolge sauber zu ordnen. Auch das nimmt 
einem der Compiler nicht ab. Weil sich der nicht um Code kümmert, den er 
nicht wahrnimmt.

Den Optimierungs-Effekt der Hardware kannst du aber auch bei den 
Cortexe-Ms erleben, zumindest theoretisch. Wenn du nämlich Daten ins RAM 
schreibst, die anschliessend vom DMA Controller verwendet werden. Selbst 
wenn du diese Daten als volatile deklarierst, ist dennoch je nach 
Adressraumkonfiguration ohne entsprechenden Barrier-Befehl nicht völlig 
gesichert, dass sie im RAM gelandet sind bevor der DMA Controller sie 
dort rausfischt.

von Dr. Sommer (Gast)


Lesenswert?

STM32-User schrieb:
> dann frage ich mich, wieso dies nicht in der
> Beschreibung des Systemverhaltens (==> in der Doku/Datenblatt)
> beschrieben wird
Weil die Doku ST-Qualität hat. Schau mal 
STM32: Errata vom STM32F4xx die nicht im Errata von ST stehen und 
http://www.efton.sk/STM32/STM32F4xx_doc_errors.txt
Bei der Programmierung mit den STM32 stößt man leider ständig auf 
fehlende/falsche/unzureichende Angaben in der Doku, da muss man sich mit 
abfinden...

Und ich gebe meinen Vorrednern definitiv Recht, dass das einfügen von 
Waitstates hier nicht Aufgabe des Compilers ist; bei richtigen™ 
Compilern wie dem GCC ist zB die ISR einfach nur ein Array an 
Funktionspointern das per Linkerscript an die richtige Stelle gepackt 
wird, eine ISR eine ordinäre C-Funktion, ein Hardware-Register einfach 
nur eine Speicherstelle - der Compiler stellt einen Satz von Werkzeugen 
bereit, mit denen man sich eine Anwendung zusammenbauen kann. Von der 
Struktur des Ergebnisses weiß der Compiler nichts. Daher kann der 
Compiler für eine Vielzahl an Controllern mit unterschiedlicher 
Hardware, in verschiedenen Konfigurationen (Bootloader, RAM, Flash...) 
benutzt werden. Hier passt es nicht hinein, dass der Compiler bestimmte 
Register "erkennt" und für die anderen Code generiert. C/C++ ist eben 
kein Rundum-Sorglos-Paket, und das ist auch gut so. Wenn du das willst 
schau dir mal http://www.stm32java.com/ an ...

von (prx) A. K. (prx)


Lesenswert?

STM32-User schrieb im Beitrag #3373350:
> beim AVR wurden die "Peripherie-Stati" (die ja angenehmerweise im Kern
> waren) automatisch zurückgesetzt.

Bei Baukastensystemen ist das wenig wahrscheinlich. Alle Microcontroller 
auf ARM Basis sind genau das (ebenso PIC32 auf MIPS Basis). Der 
Hersteller kombiniert einen eingekauften ARM Core mit allerlei 
Peripherie-Modulen, die entweder er selbst entwickelte, oder wiederum 
irgendwo einkaufte. Systeme aus einem Guss sind da nicht zu erwarten.

von STM32-User (Gast)


Lesenswert?

Gut, damit wäre das Problem eindeutig beim Hersteller des Chips zu 
suchen - bzw. in dessen lausiger Art das Systemverhalten zu 
dokumentieren.

Durch die immer schneller werdenden Produktzyklen hold man sich 
automatisch als Kunde immer mehr Kinderkrankheiten ins Haus.


Ich Danke euch für eure Einschätzung und daß ihr meine Fehleinschätzung 
"der compiler müßte es machen" korrigiert habt.

Damit rettet ihr mir - und hoffentlich vielen anderen Lesern dieses 
Threads einige der kostbaren Finger.

Euch einen angenehmen Abend
STM32-User

ps:
wie gut daß es Backups gibt- sonst müßte ich diesen Beitrag vermutlich 
mit der Nase verfassen - und selbst die wäre...  Autsch :)

von Peter D. (peda)


Lesenswert?

STM32-User schrieb im Beitrag #3373167:
> Die "IO-Problematik" bei AVRs kenne ich

Und sie ist auch im Datenblatt eindeutig dokumentiert:

"When reading back a software assigned pin value, a nop instruction must 
be inserted as indicated in Figure 10-4 on page 51. The out instruction 
sets the “SYNC LATCH” signal at the positive edge of the clock. In this 
case, the delay tpd through the synchronizer is one system clock 
period."

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.