Hallo zusammen, in meiner Freizeit programmiere ich gerne mit kleinen Mikrocontrollern (bislang ausschließlich 8-Bit-AVR), dabei verwende ich C und Assembler. Für letzteres verwende ich als Umgebung bzw. Simulator "Gerds AVR-Simulator" (http://www.avr-asm-tutorial.net/avr_sim/avr_sim-download.html). Leider hat dieser ein paar Probleme, insbesondere der Watchdog sowie der Schlafmodus scheinen im Simulator nicht zu funktionieren und es gibt noch ein paar andere Unzulänglichkeiten. Dennoch ist dieser Simulator zumindest für mich überaus hilf- und lehrreich. Mangels Windows kann ich das AVR-Studio nicht nutzen. Allerdings bin ich jetzt an einem Punkt, an dem ich nicht weiterkomme. Anbei ein kleines Assembler-Programm welches zwar erst mal funktioniert wie es soll, aber nach einer unvorhersehbaren Zeit den Betrieb einstellt. D.h. die LEDs bleiben in einem Status stecken und auf den Taster erfolgt ebenfalls keine Reaktion mehr. Manchmal nach wenigen Sekunden, manchmal erst nach einer halben Stunde oder länger. Nach einem Reset ist alles wieder normal. Laut Tutorial kommen solche Fehler dann vor, wenn ein Register oder ein Flag im Statusregister von anderer Stelle überschrieben wird. Ich habe in allen Interrupthandlern das Statusregister sowie andere verwendete Register gesichert und wiederhergestellt. Bei den Subroutinen werden auch die Register auf den Stack geschoben und wieder von dort abgeholt. Ich habe das Gefühl daß es irgendwo in den Interrupts hakt, denn das Problem tritt unabhängig von der Programmnummer (siehe Quelltext) auf. Ich habe sie -zig mal durchgeschaut, finde dort aber leider nicht die mögliche Ursache (sofern sie überhaupt dort liegt). Leider habe ich weder Debugger noch sonst irgendwelche bessere Möglichkeiten als den eingangs erwähnten Simulator, welcher mir keine Probleme gezeigt hat. Vielleicht kann hier ein Profi mal drüberschauen und mir einen Tipp geben? Anbei der vollständige Quellcode. Er läuft auf einem attiny13a, welcher den internen 128KHz-Oszillator verwendet. Angeschlossen sind neben dem ISP-Programmer, welcher auch die Stromversorgung übernimmt, 100n zwischen VCC und GND sowie zwei LEDs mit passenden Vorwiderständen an PB0 bzw. PB1 und ein Taster an PINB4.
Der attiny13 lässt sich mit DebugWire ansteuern; d.h. Du könntest mit einem Debugger nachsehen, was Dein Programm treibt, wenn es sich so verhält. DebugWire nutzt beim Tiny13a PB5, was normalerweise der Reset-Pin ist.
Stephan E. schrieb: > Anbei ein kleines Assembler-Programm welches zwar erst mal funktioniert > wie es soll, aber nach einer unvorhersehbaren Zeit den Betrieb > einstellt. Du solltest nicht für main() bzw. die von dort aufgerufene(n) Funktion(en) und für die Interrupthandler das selbe Register zum sichern der Statusflags nutzen -- oder zumindest direkt vor dem Sichern der Flags aus main() heraus die Interrupts sperren. Grüßle, Volker
:
Bearbeitet durch User
> Du solltest nicht ...
Denn am Ende von 'write2eeprom' wird u.U. (per rSreg) der Inhalt von
SREG aus einer ISR geladen, d.h. mit gesperrtem 'Global Interrupt Flag'.
Nur am Rande: weshalb soll überhaupt in 'write2eeprom' SREG gesichert
werden?
> Nur am Rande: weshalb soll überhaupt in 'write2eeprom' SREG gesichert > werden? Stimmt, Du hast Recht - mein Fehler. @kirnbichler - von DebugWire habe ich ehrlich gesagt noch nie gehört und mir den hiesigen Artikel mal angeschaut. Das klingt sehr interessant, werde ich mir genauer anschauen. @vobs - auch an Dich danke für den Hinweis, das werde ich testen.
Stephan E. schrieb: > @vobs - auch an Dich danke für den Hinweis, das werde ich testen. Die Interrupts dann aber auch erst wieder freigeben, wenn das Statusregister zurückgeschrieben wurde. Grüßle, Volker P.S.: Eine Hochsprache, wie C, hat doch auch ihre Vorteile :-)
Deine EEPROM-Write-Verwaltung mit PROGRAMHASCHANGED und SAVENEEDED halte ich für unnötig kompliziert. Warum nicht so: Bei jedem Main-Durchlauf wird geprüft, ob gerade ein EEPROM-Schreibvorgang läuft. Wenn ja: Nichts machen; wenn nein, folgendes machen: Das EEPROM-Datenbyte auslesen (das kostet keine Zeit und nutzt die EEPROM-Zelle nicht ab) und mit programmnummer vergleichen. Wenn gleich: Nichts machen; wenn ungleich: EEPROM-Schreibvorgang mit der aktuellen programmnummer triggern. Irgendwelche Wartereien auf die Beendigung eines EEPROM-Schreibvorgangs sind dann überflüssig, also verzichte darauf und nutze den sich daraus ergebenden Vorteil aus: Du kannst alles prima in einem Timer-Interrupt mit konstanter Periode unterbringen, wo die Interrupts sowieso gesperrt sind.
Martin J. schrieb: > Warum nicht so: Bei jedem Main-Durchlauf wird geprüft, ob gerade ein > EEPROM-Schreibvorgang läuft. Wenn ja: Nichts machen; wenn nein, > folgendes machen: Das EEPROM-Datenbyte auslesen (das kostet keine Zeit > und nutzt die EEPROM-Zelle nicht ab) und mit programmnummer vergleichen. "Main" läuft ohnehin nur ein mal, danach kommt der eigentliche Loop. Dort muß ich nur ein Bit prüfen und anhand dem wird entschieden, ob die programmnummer geschrieben werden muß. Das mit dem Vergleich der programmnummer wollte ich tatsächlich noch einbauen, aber erst nachdem alles andere erst mal ordentlich läuft. Und das scheint es jetzt zu tun. Zumindest ist der Controller bis jetzt nicht mehr hängen geblieben (Sicherung des Statusregister aus write2eeprom entfernt sowie alle Interruptfreigaben/-sperren nochmal überprüft). > Irgendwelche Wartereien auf die Beendigung eines EEPROM-Schreibvorgangs > sind dann überflüssig, also verzichte darauf und nutze den sich daraus > ergebenden Vorteil aus: Du kannst alles prima in einem Timer-Interrupt > mit konstanter Periode unterbringen, wo die Interrupts sowieso gesperrt > sind. Das hingegen ist ein gutes Argument für Deine Vorgehensweise. Danke für den Denkanstoß. @vobs: Ja, C wird vermutlich spätestens dann praktisch alternativlos, wenn es mal um komplexere Dinge geht. Aber ich muß sagen, daß ich Assembler ein ganzes Stück weit interessanter und faszinierender finde. Man schiebt halt wirklich extrem hardwarenah die einzelnen Bits umher - Schritt für Schritt, genau so wie es der Mikrocontroller dann abarbeitet. Bei C laufen die Sachen mehr oder weniger unsichtbar im Hintergrund. Mir geht und ging's bei meinem Hobby in erster Linie darum, den Mikrocontroller so gut zu verstehen wie es eben für Laien machbar ist. Danach kann ich immer noch mein bißchen C vertiefen. Der Weg ist das Ziel. Wie auch immer - meinen Dank an alle, die geantwortet haben!
Moin, ich schreibe auch gerne rein aus Hobby in Assembler. Eine Möglichkeit, den Fehler zu finden, ist eine kleine Erweiterung in Deiner Hauptschleife zu schreiben, um z.B. auf PB2 eine LED zum Blinken zu bringen. Als Indikator. Danach nacheinander rcall’s ausschalten bzw. zuschalten, bis der Fehler weg ist. Das Programm braucht ja dafür nicht mehr zu funktionieren, aber Du siehst, wo es hängen bleibt. Du nutze viele Register, wie z.B. r15, um sreg zu sichern. Kann man so machen. Ist ja auch schneller, aber wenn die Register mal knapp werden kann man das auch auf den Stack packen. push r16 in r16,SREG push r16 push r17 ;tuwas pop r17 pop r16 out SREG,r16 pop r16 reti Ich versuche immer die Register ab r16 nicht zu blocken. Jeder, wie er möchte. Gruß Carsten
Stephan E. schrieb: > Ja, C wird vermutlich spätestens dann praktisch alternativlos, wenn es > mal um komplexere Dinge geht. Ja, sicher, irgendwann ist die Grenze erreicht, wo es zu komplex wird, um eine Sache komplett in Assembler abzuhandeln. Aber auf einem Tiny13 ist es praktisch unmöglich, dass ein Programm diese Komplexitätsgrenze erreicht. Der hat nur 1kB Flash, da passen schon rein theoretisch maximal 512 AVR8-Assembler-Instruktionen rein. Praktisch werden es wegen konstanter Daten, die ja auch im Flash liegen müssen, eher weniger sein. Sachen in diesem Umfang sind noch ziemlich problemlos überschaubar. Bei so knappen Resourcen wie bei einem Tiny13 schafft die Verwendung einer Hochsprache eher Probleme, als dass es sie zu lösen vermag.
Ob S. schrieb: > Aber auf einem Tiny13 ist es praktisch unmöglich, dass ein Programm > diese Komplexitätsgrenze erreicht. Der hat nur 1kB Flash, da passen > schon rein theoretisch maximal 512 AVR8-Assembler-Instruktionen rein. Ich bin immer wieder erstaunt, was sich mit 1k Flash alles erreichen läßt, und genau das macht für mich die Faszination aus und freue mich wie ein kleines Kind, wenn hinterher alles so funktioniert wie ich mir das vorgestellt habe. :) Als Experiment habe ich mal verglichen - wenn ich über c die rand()-Funktion der stdlib verwende, ist die Hälfte des Flashs belegt, nur damit ich eine pseudo-Zufallszahl bekomme. Ich weiß nicht, was die rand-Funktion genau wie macht - aber in Assembler bekomme ich meine pseudo-Zufallszahlen über ein 32-bit-lfsr mit wesentlich weniger Flash (es waren sechs, sieben Prozent belegt, wenn ich mich recht erinnere)
Stephan E. schrieb: > Ich weiß nicht, was die rand-Funktion genau wie macht - aber in > Assembler bekomme ich meine pseudo-Zufallszahlen über ein 32-bit-lfsr > mit wesentlich weniger Flash Wenn die stdlib-funktion zufällige Äpfel, deine aber zufällige Birnen liefert, hinkt das halt heftig, und das nicht nur zufällig. Oliver
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.