Hallo, in einem Programm macht es Sinn, den AVR zu resetten. Wie kann man das anstellen (ohne WatchDog;-)? Programmiere unter WinAVR. Thx Frank
Da die AVRs keinen RESET Befehl kennen, bleibt sonst nur die Möglichkeit per Hardware. Direkt via Pin oder über 20 Ecken. Aber das hattest Du wohl auch nicht im Auge, oder? Wenn man allerdings alle möglichen Lösungen vorsorglich ausschliesst, landet man unweigerlich irgendwann im Unlösbaren.
Man könnte den Resetvektor in den PC laden. Allerdings wird dann die Hardware nicht zurückgesetzt, aber das Programm liefe wieder "von vorne" an.
Z.B. so: cli(); (((void(*)(void))0x0000)()); Allerdings mußt Du die neueste Version nehmen, ältere haben einen Bug, dann geht es nur so: cli(); __init(); Das hat auch den Vorteil, daß die Ausgänge nicht kurzzeitig floaten, wie es bei einem echten Reset der Fall wäre. Peter
Leider sind die oben beschriebenen Verfahren kein 100% korrekter Ersatz für einen sauberen Reset (kein Register wird auf seinen Defaultwert zurückgesetzt; bei manchen NichtAVR-Mikrocontrollern gibt auch sogen. WriteOnce-Register - damit hättest du dann auch ein Problem ohne richtigen Reset...). Was spricht gegen den Einsatz des Watchdogs? @Peter: Das mit dem Floaten darf ja bei einem 'normalen' Reset auch nicht zum Problem werden... ----, (QuadDash).
Hmm, dachte, da gibts einen Trick 17. Wenn der AVR also neu anlaufen soll, werd ich wohl doch den WatchDog von der Leine lassen. Danke, Frank
@QuadDash, zu einem sauberen Programierstil gehört, daß man sämtliche verwendeten Register initialisiert. Wenn man dann noch Angst hat, das ein Programmirrläufer falsche Interrupts freigibt, kann man zusätzlich noch sämtliche nicht benutzten Interrupts sperren. Und dann reicht durchaus ein simpler Restart aus. "Das mit dem Floaten darf ja bei einem 'normalen' Reset auch nicht zum Problem werden..." Meistens wird ein Verückspielen angeschlossener Hardware beim Einschalten toleriert oder durch eine Einschaltverzögerung verhindert. Inmitten eines Programms will man sowas aber nicht haben. Peter
> zu einem sauberen Programierstil gehört, daß man sämtliche verwendeten Register initialisiert. theoretisch schon - aber praktisch kann das beim guten Vorsatz bleiben, wenn beispielsweise Fremdmodule in den Code eingebunden werden usw.. Was wenn aber ein Bit eines Configregisters fälschlicherweise gesetzt wurde (z.B. durch Softwarebug), bzw. durch äußere Einflüsse sich selbständig gesetzt hat, dann bist du evtl. nach dem selbstgestrickten Reset noch genauso naß, da du dieses Register nicht initialisiert hast - oder etwa doch? Falls doch, dann ist es bedeutend weniger aufwendig einen Watchdogreset auszulösen, als jedes (auch unbenutzte) (Config-)Register zu initialisieren. Für kleine selbstgestrickte AVR-Software trifft das alles zu was du sagst - für größere Projekte nicht unbedingt. Und wenn wir schon bei eher theoretischen Betrachtungen (fernab von AVR) sind: Manche Mikrocontroller haben einen bidirektionalen Resetpin, der im Resetfall nach außen hin das ResetSignal treiben kann, sodaß daran angeschlossene Resetcontroller oder sonstige externe Hardware (z.B. SPI-Treiber) somit auch gleich zurückgesetzt werden kann. -> Es gibt einige Punkte, die für einen richtigen Reset sprechen. ----, (QuadDash).
> Verückspielen angeschlossener Hardware [] durch eine
Einschaltverzögerung verhindert.
Stimmt, das ist auch eine Möglichkeit.
----, (QuadDash).
> zu einem sauberen Programierstil gehört, daß man sämtliche > verwendeten Register initialisiert. Nein, das ist Verschwendung. Ein Register, für das mir der Hersteller einen bestimmten Wert nach Reset garantiert (oder eine Variable, für die mir der C-Standard das generiert), muss ich nicht nochmal selbst auf ebendiesen Wert setzen. Das vergeudet ROM und CPU-Zyklen, beides teuer auf einem Controller. Klar, wenn ich möchte, dass meine Applikation über einen Sprung auf 0 neu gestartet werden kann, dann muss ich all die IO-Register auf ihre Initialwerte setzen, die ich selbst verändere, aber dann war ich das auch selbst, der das so wollte. (C-Variablen werden auch in diesem Falle initialisiert.)
@Jörg Wunsch "Nein, das ist Verschwendung." Na na ! Wer beim GCC Erbsen (Bytes) zählen will, muß schon was anderes nehmen. Im GCC gibt es genügend anderen nicht optimalen Code, z.B. oft erzeugt er für 8Bit Operationen 16Bittigen Code (Switches). Da machen die paar Bytes Init-Code den Kohl auch nicht mehr fett. Und wenn es für die Funktion wichtig ist, schreibe ich auch: PORTB = 0x00; Damit dann ein anderer weiß, wenn er daran dreht, könnte es Folgen haben. Also bessere Lesbarkeit hat da den Vorrang. Natürlich ist der Sprung nach 0x000 nur sinnvoll, wenn es ein regulärer Zustand im Programm ist. Um irgendwelche Bugs oder Irrläufer zu verschleiern, taugt er nicht. Peter
Die Nichtoptimalitäten im GCC könnten sich aber reparieren lassen, die in deinem Code nicht. ;-) Für den gewünschten Dokumentationseffekt würde es genügen, die entsprechenden Anweisungen als Kommentar zu schreiben mit der Bemerkung, dass es sich um den Hardwarezustand handelt. Aber ich halte selbst das für überflüssig und würde es bestenfalls durch einen globalen Satz ersetzen, dass die Hardware sich im für Reset dokumentierten Zustand befinden muss. Wofür ist der denn exakt spezifiziert worden, wenn ich mich hinterher plötzlich nicht mehr drauf verlassen können soll?
>> Im GCC gibt es genügend anderen nicht optimalen Code, z.B. oft >> erzeugt er für 8Bit Operationen 16Bittigen Code (Switches). Hab' ich auch neulich mit tiefer Trauer zur Kenntnis genommen. Ist jemandem bekannt, ob geplant ist, diesen Umstand zu ändern? Oder gibt es eine Compiler-Option, die in switch( char ) nur ein Byte auswertet? Gruß, Michael
@Jörg Wunsch > Ein Register, für das mir der Hersteller einen bestimmten Wert nach > Reset garantiert Na du hast hast aber großes Vertrauen in die Hersteller. > ...bestenfalls durch einen globalen Satz ersetzen, dass die Hardware > sich im für Reset dokumentierten Zustand befinden muss Genau, sowas liebe ich! Die große Frage ist: wie ist dieser Zustand dokumentiert? Also Datenblatt raus, und alle Register nachlesen. Blödsinn! Sehr schön für Leute, die mit einem Prozessor nicht soo vertraut sind, die kriegen dann nämlich die Krise. Die Variante, alle verwendeten Register zu initialisieren, finde ich sehr sinnvoll. So weis jeder, welchen Zustand die Register haben. Spart viel Zeit und Unklarheiten. Thorsten
Da haste aber bei den neueren ATmegas mit ihren vielen Registern mächtig was vor... Davon abgesehen, eigentlich habe ich bei AVR bisher noch keine Verleztung des POLA (principle of least astonishment) bei den Initialwerten erlebt, d.h. die IO-Register kommen mit einer Voreinstellung daher, die man auch so erwarten würde. Portregister stehen alle auf Eingabe, Timer sind im Stop-Zustand, UARTs generieren, nachdem man ihnen die Baudrate auf die Reihe gibt 8N1-Frames, ... Ich habe wirklich noch keine Überraschung erlebt. Die Erweiterung vieler Werte auf einen `int' hat einfach erstmal den Grund, dass der C-Standard das so verlangt. Klar, der Compiler darf danach auch noch so intelligent sein festzustellen, dass sich nichts ändern würde, wenn man den Wert anschließend wieder auf ein Byte verkürzt, aber hier zeigt sich, dass der AVR als 8-Bit-Plattform einfach in der Entwicklerkapazität bei GCC völlig unterrepräsentiert ist. Die Hauptarchitekturen des GCC stört das überhaupt nicht, dass die Daten auf einen int erweitert werden, im Gegenteil, deren Prozessoren arbeiten typischerweise mit Registern, die selbst einen int (oder gar noch mehr) fassen können. > ,,...ob geplant ist, diesen Zustand zu ändern?'' Weiß nicht, planst du es denn, Michael? Mir dünkt, du hast noch nicht ganz verstanden, wie eine Opensource- Entwicklung so abläuft... Nein, wenn es keiner macht, wird es auch nicht passieren. Oder: wenn du es nicht machst, ich es nicht mache, ... es nicht macht -- dann macht es niemand.
@MSE: Nu, das gibt es doch schon. -mint8. Nur warum derjenige, dem wird die AVR-Portierung zu verdanken haben, dennoch in Version 3 unbedingt 64-Bit Datentypen brauchte (wodurch dann 32 Bit im schwarzen Loch verschwinden), erschliesst sich mir nicht. Wozu der GCC fähig ist, zeigt er erst mit -mint8. Nur die Lib kommt da teilweise nicht mit, aber wer benutzt schon printf wenn's arg auf die Grösse ankommt. Aber verwendbar ist es durchaus, man muss halt nur genau wissen was man von der Lib verwendet.
"Da haste aber bei den neueren ATmegas mit ihren vielen Registern mächtig was vor..." Ich initialisiere natürlich nur die IO-Register, die ich auch benutze. Bei allen anderen (z.B. AD-Wandler) gehe ich davon aus, daß sie nach dem Reset im inaktiven Zustand sind. Peter
> Bei allen anderen (z.B. AD-Wandler) gehe ich davon aus, daß sie nach > dem Reset im inaktiven Zustand sind. Das ist aber nach deinem sonstigen Misstrauen gegenüber dem Hersteller eine sehr mutige Annahme. :-))
Ich habe nirgends Mißtrauen geäußert. Ich habe nur gesagt: Wenn ich für eine Funktion benötige, daß Register X den Wert Y haben muß, dann schreibe ich das hin, um es zu dokumentieren, unabhängig davon, ob der Wert Y zufällig auch der Resetzustand ist. Wie gesagt, wirkt sich das nicht signifikant auf die Codegröße aus, und auf die Ausführungszeit schon gar nicht. Peter
Tja, und ich finde es eben völlig überflüssig. Schließlich setze ich auch nicht den PC extra auf 0, sondern vertraue darauf, dass der Hersteller ihn wirklich auf 0 gesetzt hat nach einem Reset. Da können wir uns halt nicht einigen, macht nix.
"Schließlich setze ich auch nicht den PC extra auf 0" .org irgendwo rjmp 0 Das ist wohl das einzige Register, welches man nicht in Software von einem unbekannten Wert auf einen bekannten setzen kann. "Da können wir uns halt nicht einigen" Zwingt uns ja niemand dazu. Peter
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.