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..
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...
>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.
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
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
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
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
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.
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.
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
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.
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..
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.
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. :-)
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
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.
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?
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.
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!!
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.
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. ;-)
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.
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 :)
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...
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 ?
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.
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.
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
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.
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 ...
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.
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 :)
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.