Attiny13a stürzt ab

OP #8035750
Lesenswert?

Hallo in die werte Runde,

Es geht um einen attiny13a, welcher ein Lauflicht aus sechs LEDs (Charlieplexing) abhängig von der Umgebungshelligkeit ein- oder ausschaltet. Anbei ein handgezeichnetes Schaltbild.

Die Schaltung existiert zwei mal. Einmal auf einem Steckbrett und einmal fest verlötet auf einer Lochrasterplatine. Erstere wird direkt aus dem AVR-Programmer mit Strom versorgt (3.3V), letztere aus einem kleinen einzelligen Li-Ion-Akku, welcher wiederum an einem TP4056-Modul hängt.

Für Tests ist zusätzlich ein rs232-Pegelwandler-Modul (MAX3232) angeschlossen: Gnd und Vss direkt vom Programmer bzw. Akku, PB3 als serieller Ausgang des Mikrocontrollers (bitbanging). Zwischen Gnd und Vcc ist ein 100n-Keramikkondensator, zwischen Gnd und PB4 eine Fotodiode mit der Kathode an Gnd und der Anode am PB4.

Das Programm ist auf beiden Umgebungen dasselbe (siehe Anhang, Kommentare stehen direkt im Quellcode. Entwickelt wurde das ganze im avr-Simulator von Gerhard Schmidt).

Wenn ich das Programm starte (egal ob Steckbrett oder Lochraster), funktioniert es so wie erwartet. Das Lauflicht wird abhängig von der Helligkeit ein- bzw. ausgeschaltet. Den ADC-Wert bekomme ich alle zehn Sekunden am seriellen Ausgang ausgegeben, alles gut so weit.

Allerdings hängt sich der Mikrocontroller nach einiger Zeit auf. Manchmal erst nach mehreren Stunden, manchmal nach schon vielleicht 30 Minuten. Konkret reagiert er nicht mehr, wenn es dunkel oder hell wird, und es kommen auch keine seriellen Daten mehr raus. Ich weiß leider nicht, warum. Ich vermute einen Programmfehler, denn das Problem tritt sowohl auf dem Steckbrett als auch der Lochrasterplatine im fest verlöteten Zustand auf, allerdings nach nicht reproduzierbaren Zeitabständen.

Für sachdienliche Hinweise wäre ich sehr dankbar.

Angehängte Dateien:
Moderator Persönliche Seite #8035771
Lesenswert?

Einen internen Pullup haben die AVRs. Ist nicht gerade extrem störsicher, aber sollte funktionieren – insbesondere kann das eher nicht zum beobachteten Verhalten (Firmware fährt sich fest) führen, sondern würde ja eher zu einem Reboot führen.

Watchdog ist standardmäßig aus.

Ich habe allerdings keine Lust, mich durch 500 Zeilen Assemblercode zu wuseln.

OP #8035782
Lesenswert?

Rainer W. schrieb:

Stephan E. schrieb:

Für sachdienliche Hinweise wäre ich sehr dankbar.

Wie hast du den Watchdog konfiguriert?

Der Watchdog ist als "interrupt-only" konfiguriert, er macht keinen reset. Er wird alle 0.125 Sekunden aufgerufen. Danach läuft die Hauptschleife ein mal durch und geht am Ende dieser Schleife in den Schlafmodus. Bis zum nächsten aufwecken durch den Watchdog.

Nicht jeder µC mag es, wenn sein Reset-Pin frei in der Luft hängt. Ziehst du den durch einen internen Pull-Up definiert auf High-Pegel?

Der Reset-Pin hängt auf der verlöteten Lochraster-Platine tatsächlich in der Luft. Am Programmer ist der Reset-Pin aber angeschlossen und wird mutmaßlich durch den Programmer oben gehalten.

OP #8035787
Lesenswert?

Jörg W. schrieb:

Einen internen Pullup haben die AVRs. Ist nicht gerade extrem störsicher, aber sollte funktionieren – insbesondere kann das eher nicht zum beobachteten Verhalten (Firmware fährt sich fest) führen, sondern würde ja eher zu einem Reboot führen.

Watchdog ist standardmäßig aus.

Ich habe allerdings keine Lust, mich durch 500 Zeilen Assemblercode zu wuseln.

Das würde ich natürlich auch nicht verlangen. Allerdings sieht das Forum vor, daß Quellcodes mitgeliefert werden - falls doch mal jemand einen Blick riskieren möchte. Vielleicht hat jemand mit Erfahrung einen Tipp für mich, der beim beschriebenen Problem der übliche Verdächtige sein könnte? Ggf. gibt's auch eine KI, die den Code mal durchschauen könnte.

#8035797
Lesenswert?

  • µC zusätzlich zum 100n KeKo noch mit einem kleinen Elko (Richtwert 47µ) puffern
  • Reset mit RC Glied 10n gegen Masse und 10K gegen Ub beschalten
  • serielle Schnittstelle mal probeweise im Code auskommentieren. Der Tinny hat die serielle Schnittstelle nicht in Hardware, sondern sie muß in SW emuliert werden. Da gibt es Implementierungen, die hängen sich gern auf.
  • die Fotodiode könnte man auch noch durch ein kleines RC-Glied beruhigen

Immerhin hat er nicht nur Prosa, sondern überhaupt einen Schaltplan, der kein Wimmelbild ist und keine 6 MB groß ist. Also fast alles richtig gemacht ;-)

#8035800
Lesenswert?

Stephan E. schrieb:

Am Programmer ist der Reset-Pin aber angeschlossen und wird mutmaßlich durch den Programmer oben gehalten.

Das wäre aber sehr ungewöhnlich. Wenn der Programmieradapter inaktiv ist, dann ist der Pin am Programmieradapter normalerweise hochohmig. Und dann reichen ein paar cm Leitung schon zum Empfang von Radiowellen.

Der interne Pullup des Mikrocontrollers ist schwach, zudem reagiert er wesentlich empfindlicher als normale I/O Pins, da er anders definierte High/Low Pegel hat.

Moderator Persönliche Seite #8035803
Lesenswert?

Hans W. schrieb:

Und dann reichen ein paar cm Leitung schon zum Empfang von Radiowellen.

Ja, aber dann würde der Controller einen Reset machen, statt in einer Endlosschleife hängen zu bleiben.

Gerald B. schrieb:

serielle Schnittstelle mal probeweise im Code auskommentieren. Der Tinny hat die serielle Schnittstelle nicht in Hardware, sondern sie muß in SW emuliert werden. Da gibt es Implementierungen, die hängen sich gern auf.

Wäre natürlich ein Punkt.

Wenn Stephan einen Logikanalysator hat, könnte man damit ein paar Testmuster stattdessen ausgeben und so ungefähr nachvollziehen, an welchen Stellen die Software noch lang kommt, bevor sie klemmen bleibt.

OP #8035811
Lesenswert?

Gerald B. schrieb:

  • µC zusätzlich zum 100n KeKo noch mit einem kleinen Elko (Richtwert 47µ) puffern
  • Reset mit RC Glied 10n gegen Masse und 10K gegen Ub beschalten
  • serielle Schnittstelle mal probeweise im Code auskommentieren. Der Tinny hat die serielle Schnittstelle nicht in Hardware, sondern sie muß in SW emuliert werden. Da gibt es Implementierungen, die hängen sich gern auf.
  • die Fotodiode könnte man auch noch durch ein kleines RC-Glied beruhigen

Vielen Dank für die Tipps! Ich werde sie allesamt ausprobieren, testen und mich dann nochmal melden.

@Jörg W.: Einen Logikanalysator besitze ich leider nicht. Ich bin nur ein kleiner Hobbybastler ohne nennenswerte Ausstattung (hat man ja schon am Schaltbild gesehen....).

(Firma: matzetronics) #8035829
Lesenswert?

Einen Watchdog in der ISR zu bedienen, ist zu 95% kontraproduktiv. Es kann nämlich durchaus sein, das das Hauptprogramm hängt, die WD ISR aber munter weiterläuft. Wenn ich mir das Programm so anschaue - warum einfach, wenns auch kompliziert geht?

: Bearbeitet durch User
Moderator Persönliche Seite #8035832
Lesenswert?

Matthias S. schrieb:

Einen Watchdog in der ISR zu bedienen, ist zu 95% kontraproduktiv.

Ist halt ein Timer mehr – nicht als Watchdog im eigentlichen Sinne verwendet. Der ATtiny13 hat ja nun nicht so eine üppige Hardware-Ausstattung. (Allerdings würde ich ihn schon deshalb nicht unbedingt hobbymäßig nehmen. Es gibt bessere Alternativen, die deutlich mehr Hardware-Komfort bieten, auch bei AVR.)

Gast #8035841
Lesenswert?

Wastl schrieb:

Jörg W. schrieb:

Der ATtiny13 hat ja nun nicht so eine üppige Hardware-Ausstattung.

Ja, aber es gibt soooo wenig Alternativen, und die sind so teuer.

Für Kinkerlitz nehm ich die immer mal wieder, aber auch nur weil mir vor Jahren ein Rest-Reel in die Hände fiel...

#8035864
Lesenswert?

Habe mir die Frechheit herausgenommen, das Gerhard Schmidt'sche Programm einmal ins Studio 4 zu laden. (Ja, der mit dem Tutorial. Die Webseite ist aber jetzt anderweitig vergeben, Links stimmen nicht mehr.) Also Studio 4 Simulator bleibt schon direkt in der Loop hängen.

Rein syntaxmäßig sieht es ja recht gut aus: ATtiny13A memory use summary [bytes]: Segment Begin End Code Data Used Size Use% [.cseg] 0x000000 0x00022c 556 0 556 1024 54.3% [.dseg] 0x000060 0x00006f 0 15 15 64 23.4% [.eseg] 0x000000 0x000000 0 0 0 64 0.0%

0 Errors 0 Warnings.

Tipp: Wirf den Watchdog raus, und programmiere "vernünftige" Zeitschleifen. (Wurde oben schon angedeutet.)

ciao gustav

Angehängte Dateien:
: Bearbeitet durch User
Moderator Persönliche Seite #8035870
Lesenswert?

Wastl schrieb:

Einfach mal die Scheuklappen abnehmen und über den Teller-Rand hinausschauen ....

Muss man nichtmal, schrieb ich aber schon. Bereits ein ATtiny25 (fast genauso uralt wie der originale ATtiny13) würde schon deutlich mehr bieten. Gut, wenn es unbedingt ein DIP-8 als Gehäuse sein muss, dann hört es bei diesen (und den größeren Geschwistern des 25) auf. Wenn es auch ein SOIC-8 sein darf (um bei 8 Pins zu bleiben), dann hätte man mit ATtiny202 oder ATtiny212 dann immerhin schon MCUs, die man mit UPDI viel einfacher programmieren kann als die alten AVRs mit ISP – und selbst bei Reichelt sind die nur halb so teuer wie ein ATtiny13A.

(Firma: 1984now) #8035871
Lesenswert?

Stephan E. schrieb:

Vielleicht hat jemand mit Erfahrung einen Tipp für mich, der beim beschriebenen Problem der übliche Verdächtige sein könnte?

Ziemlich wahrscheinlich Konflikte bei der Registernutzung. Warum? Wenn schon der Kommentar zur Registernutzung offensichtlich widersprüchlich ist, dann wird's im Programm selber sicher nicht ordentlicher zugehen...

#8035881
Lesenswert?

Jörg W. schrieb:

Er ist schrecklich (vor allem extrem pixelig klein skaliert und mit schlechtem Kontrast), aber die wesentlichen Details enthält er schon.

Sind Versorgungsspannung kein "wesentliches Detail"? Von einem Schaltplan erwarte man z.B. auch, dass man die Funktion von Signalen anhand einer sinnvoll gewählten Bezeichnung erkennen kann und nicht so einen locker, mit einer Leitung an irgendeinen Pin angeklöppelten Max32?2, der ansonsten bezugslos in der Luft hängt :-(

#8035882
Lesenswert?

Ob S. schrieb:

Registernutzung

Sprichst mir aus dem Herzen: Was ich bei Gerhard S. Programmen so "schrecklich" finde, sind diese Abkürzungen in "Denglisch". Beim seinem DCF77 Decoder-Programm sind sogar ein paar Registerdefinitionen im Deklarationsteil angegeben, die im Programm selbst garnicht mehr auftauchen, also hätte man sie ganz weglassen können.(Das Programm, das mit steigenden und fallenden Flankeninterrupts arbeitet, und wahrscheinlich deswegen nicht mehr startet, wenn nach einer Empfangspause das Signal wieder decodierfähig wäre.)

Mir drängt sich der Verdacht auf, dass jeder ASM-Programmierer eben so seinen ganz persönlichen "Stil" pflegt. Nicht unbedingt für "Bastler" schnell zu durchschauen.

ciao gustav

OP #8035945
Lesenswert?

Ob S. schrieb:

Stephan E. schrieb:

Vielleicht hat jemand mit Erfahrung einen Tipp für mich, der beim beschriebenen Problem der übliche Verdächtige sein könnte?

Ziemlich wahrscheinlich Konflikte bei der Registernutzung. Warum? Wenn schon der Kommentar zur Registernutzung offensichtlich widersprüchlich ist, dann wird's im Programm selber sicher nicht ordentlicher zugehen...

Das habe ich auch vermutet. Ich bin das gesamte Programm schon mehrmals Schritt für Schritt durchgegangen, finde das Problem aber leider nicht. Der etwas weiter oben erwähnte Pullup am Reset-Pin hat das Problem leider nicht behoben. Der Test ohne die serielle Ausgabe läuft noch.

OP #8035949
Lesenswert?

Jörg W. schrieb:

Wenn es auch ein SOIC-8 sein darf (um bei 8 Pins zu bleiben), dann hätte man mit ATtiny202 oder ATtiny212 dann immerhin schon MCUs, die man mit UPDI viel einfacher programmieren kann als die alten AVRs mit ISP – und selbst bei Reichelt sind die nur halb so teuer wie ein ATtiny13A.

Ich bleibe lieber bei DIP. SMD ist für meine zwei linken Hände nur sehr bedingt geeignet. Trotzdem wollte ich mir die Series 0 mal irgendwann genauer anschauen - aber nicht heute. Die Kosten für einen Controller stufe ich für meine reinen Hobby- und Freizeitzwecke als eher vernachlässigbar ein. Da geht's in erster Linie um Lernerfolge und den Spaß am reinen "doing".

Moderator Persönliche Seite #8036037
Lesenswert?

Stephan E. schrieb:

Ich bleibe lieber bei DIP. SMD ist für meine zwei linken Hände nur sehr bedingt geeignet.

SOIC mit 1,27 mm Pinraster ist ja nun für SMD-Verhältnisse noch richtig grobschlächtig. Auch Adapter von da auf DIP-8 gibt es ja zur Genüge.

Die einfachere Programmiermöglichkeit via UPDI ist auf jeden Fall angenehm, im Prinzip brauchst du nicht mehr als einen USB-Seriell-Wandler und zwischen TxD und RxD noch einen Widerstand von 1 kΩ.

Gast #8036039
Lesenswert?

Jörg W. schrieb:

Die einfachere Programmiermöglichkeit via UPDI ist auf jeden Fall angenehm, im Prinzip brauchst du nicht mehr als einen USB-Seriell-Wandler und zwischen TxD und RxD noch einen Widerstand von 1 kΩ.

Wenn die Versorgungsspannung des µC passt. Ansonsten halt noch einen Pegelwandler, bidirektional.

Moderator Persönliche Seite #8036044
Lesenswert?

H. H. schrieb:

Wenn die Versorgungsspannung des µC passt.

Ansonsten muss man sie passend machen :-) oder einen USB-Seriell-Wandler mit passender Spannung suchen. Zumindest 3,3 V und 5 V sind ja beide gängig, teilweise kann man sie auch umjumpern oder umlöten.

Ich habe aber auch schon einen FTDI mit 5 V genommen und einfach eine rote LED vor die Spannungszuführung geschaltet, weil ein auf der Schaltung befindlicher Sensor nicht mehr als 3,6 V haben möchte. Theoretisch ist dann zwar der Signalpegel von der MCU zum Wandler etwas niedrig, funktioniert aber trotzdem.

Gast #8036045
Lesenswert?

Jörg W. schrieb:

Ich habe aber auch schon einen FTDI mit 5 V genommen und einfach eine rote LED vor die Spannungszuführung geschaltet, weil ein auf der Schaltung befindlicher Sensor nicht mehr als 3,6 V haben möchte. Theoretisch ist dann zwar der Signalpegel von der MCU zum Wandler etwas niedrig, funktioniert aber trotzdem.

Schweizer Taschenmesser und Kaugummi geht bestimmt auch. ;-)

#8036325
Lesenswert?

Stephan E. schrieb:

Die serielle Ausgabe habe ich unverändert schon in vielen anderen Programmen verwendet - sie hat nie Probleme gemacht. Ich vermute, daß sich vielleicht die Interrupts in die Quere kommen. Ich werde dort weiter nachforschen.

Möglicherweise hängt dein nicht funktionierender Watchdog, wenn die Übertragung im ungünstigen Moment startet oder zu lange dauert. Schon witzig, ein Programm mit Watchdog, das festhängt. Finde den Fehler.

#8036347
Lesenswert?

Ich sag mal, daß das Programm an der Stelle hier endgültig zu Ende sein wird:

sbr rmp, (1<<SM1)|(1<<SE) ; sleep-mode: powerdown out MCUCR, rmp

loop_ende: sleep

Aus power down bräucht es einen Watchdog-Reset, einen brown-out-Reset, oder INT0 bzw pin change Interrupts zum wieder aufwecken.

Keiner davon ist enabled.

Oliver

Moderator Persönliche Seite #8036384
Lesenswert?

Oliver S. schrieb:

Aus power down bräucht es einen Watchdog-Reset, einen brown-out-Reset, oder INT0 bzw pin change Interrupts zum wieder aufwecken.

Du solltest das Datenblatt richtig lesen lernen. ;-)

Ja, mit "watchdog" war was (und natürlich befreit jeder Reset ihn aus dem Schlaf) – aber neben INT0 / PCINT kann eben auch ein Watchdog-Interrupt wieder aufwecken, und einen solchen hat er 8mal pro Sekunde.

Ansonsten wäre es ja auch völlig unlogisch, dass die Firmware überhaupt erstmal läuft und erst nach längerer Zeit einfriert.

OP #8036387
Lesenswert?

Oliver S. schrieb:

Ich sag mal, daß das Programm an der Stelle hier endgültig zu Ende sein wird:

sbr rmp, (1<<SM1)|(1<<SE) ; sleep-mode: powerdown out MCUCR, rmp

loop_ende: sleep

Aus power down bräucht es einen Watchdog-Reset, einen brown-out-Reset, oder INT0 bzw pin change Interrupts zum wieder aufwecken.

Der Watchdog-Interrupt (kein reset) reicht. Und der macht das ja auch. Ich verwende den Watchdog nicht als Watchdog, sondern nur als zweiten timer, welcher einen Interrupt auslöst. Die loop-Schleife wird somit jede 0.125 Sekunden ein mal durchlaufen.

: Bearbeitet durch User
#8038449
Lesenswert?

Stephan E. schrieb:

Der Watchdog-Interrupt (kein reset) reicht. Und der macht das ja auch. Ich verwende den Watchdog nicht als Watchdog, sondern nur als zweiten timer, welcher einen Interrupt auslöst. Die loop-Schleife wird somit jede 0.125 Sekunden ein mal durchlaufen.

Und du hoffst, dass es niemals dadurch zu einem Problem kommt, dass du in beiden Interrupt-Routinen dasselbe Register zum Retten des Status benutzt?

(Firma: 1984now) #8038596
Lesenswert?

Oliver S. schrieb:

Beim AVR wird defaultmässig beim Eintritt in eine ISR das globale Interrupt-Enable flag gelöscht. Da gibt es damit keine Probleme.

Das ist zwar richtig, aber natürlich müssen ein paar weitere Bedingungen erfüllt sein, damit es wirklich keine Probleme gibt.

  • innerhalb aller ISRs, die das Register benutzen, darf nicht mit "sei" rumgespielt werden
  • zwischen dem "in" zu Begin und dem "out" am Ende der ISRs darf das Register natürlich nicht für andere Zwecke verwendet werden.
  • Und natürlich darf das Register auch nicht in main verwendet werden, jedenfalls nicht ohne zusätzliche Schutzmaßnahmen

Allerdings: Wenn ich nichts übersehen habe, sind für rSreg/R15 alle diese Bedingungen erfüllt. Sollte also tatsächlich kein Problem sein.

#8038901
Lesenswert?

Ob S. schrieb:

Allerdings: Wenn ich nichts übersehen habe, sind für rSreg/R15 alle diese Bedingungen erfüllt.

Siehst du, du gehst davon aus, dass es womöglich doch nicht ok sein könnte.

Eine Prüfung auf mögliche versteckte Fehler kostet unnötig Zeit, und solange man den Fehler nicht gefunden hat, muss man womöglich immer wieder mal drüber nachgrübeln. Zeit, die verschwendet ist.

Ich programmiere aus Erfahrung*) grundsätzlich "defensiv". Solange der Speicher nicht bis zum allerletzten Byte ausgeknautscht ist, nehme ich in diesem konkreten Fall kein Register, sondern eine RAM-Zelle pro ISR.

*) Die letzten Programme in Assembler habe ich vor Jahrzehnten geschrieben. Die liefen auch in Fabrikhallen in anderen Erdteilen. Jeder Stillstand beim Kunden war eine Katastrophe. "Defensiv codieren" war also Pflicht.

(Firma: 1984now) #8038920
Lesenswert?

Rolf schrieb:

Ob S. schrieb:

Allerdings: Wenn ich nichts übersehen habe, sind für rSreg/R15 alle diese Bedingungen erfüllt.

Siehst du, du gehst davon aus, dass es womöglich doch nicht ok sein könnte.

Du übersiehst die Einschränkung meiner Einschätzung auf rSreg/R15. Dafür bin ich sicher, dass dessen Verwendung OK ist.

Nur werden aber blöderweise auch noch etliche andere Register in dem Code benutzt.

Ich programmiere aus Erfahrung*) grundsätzlich "defensiv". Solange der Speicher nicht bis zum allerletzten Byte ausgeknautscht ist, nehme ich in diesem konkreten Fall kein Register, sondern eine RAM-Zelle pro ISR.

Das ändert doch garnix, außer das jede ISR-Instanz mindestens vier Takte länger braucht. Erstens muß man für diese RAM-Zelle dann ganz genauso auf korrekte und exklusive Benutzung prüfen und zweitens braucht man immer noch ein MCU-Register zum Sichern, weil es keine Instruktionen gibt, mit der man SREG direkt in den RAM sichern bzw. von dort laden könnte.

"Defensiv codieren" war also Pflicht.

Richtig programmieren ist noch viel besser als defensiv programmieren. Bezüglich der MCU-Registernutzung bietet der Assembler mit der Möglichkeit zur Vergabe von Aliasnamen sehr gute Voraussetzungen dafür. Man muss sie nur konsequent auch in diesem Sinne nutzen. Das ist im vorliegenden Code für rSreg/R15 geschehen (weswegen sich die Sache hier auch leicht nachprüfen ließ), für andere Register hingegen leider nicht.

#8038929
Lesenswert?

Moin, um den Fehler einzugrenzen, würde ich die LEDs erstmal über größere Widerstände anschließen. Dann in der Hauptschleife alles rausnehmen und mit CBI und SBI einen Pin toggeln und mit einem Oszilloskope den Pin beobachten. Wenn das längere Zeit stabil läuft nacheinander init, ADC, ISR, watchdog usw. dazu nehmen. Viel Erfolg Carsten

Persönliche Seite #8038957
Lesenswert?

Ob S. schrieb:

Erstens muß man für diese RAM-Zelle dann ganz genauso auf korrekte und exklusive Benutzung prüfen und zweitens braucht man immer noch ein MCU-Register zum Sichern, weil es keine Instruktionen gibt, mit der man SREG direkt in den RAM sichern bzw. von dort laden könnte.

Kann man doch einfach PUSH / POP nehmen, so wie es zum Beispiel avr-gcc macht.

#8038963
Lesenswert?

Johann L. schrieb:

Kann man doch einfach PUSH / POP nehmen, so wie es zum Beispiel avr-gcc macht.

Das Problem mit Buffer Underrun. Der Stapel wandert rückwärts in den Programmbereich rein, wenn zu viel push und pop. Oder pop vergessen wurde. Einrichtung von Stapelzeigerbereich lautet ja bekanntlich RAMEND. Zählt also runter. Wann der Crash erfolgen könnte, müsste man im Simulator (built and run) nachvollziehen können.

ciao gustav

OP #8038966
Lesenswert?

Stephan E. schrieb:

Wollte nochmal Rückmeldung geben - seit die serielle Ausgabe deaktiviert ist, keine Probleme mehr.

Ich muß mich korrigieren. Die serielle Ausgabe ist nicht das Problem. Nach etlichen Tests bin ich mir jetzt zu 99% sicher, daß das Problem mit dem deep-sleep zusammenhängt. Wenn ich statt dem deep-sleep nur den sleep mode "idle" nehme, läuft alles (läuft immer noch, inzwischen schon vier Tage, serielle Ausgabe ist aktiv).

Die einzige Programmänderung: statt

1
sbr rmp, (1<<SM1)|(1<<SE)   ; sleep-mode: powerdown
1
sbr rmp, (1<<SE)

Alles andere ist unverändert.

#8039127
Lesenswert?

Die einzige Programmänderung ... Alles andere ist unverändert.

Pardon, aber ich sehe zusätzlich ein gutes Dutzend auskommentierte Zeilen.

Eigentlich hatte ich vor, das Ganze mit/ohne Absturz nachzuvollziehen (das aktuelle Programm (mit etwas Mühe) auf den nur verfügbaren ATtiny85 umgesetzt), dazu eben diese eine Zeile 'sbr rmp ...' umschaltend; aber jetzt kommen mir doch Zweifel.

OP #8039145
Lesenswert?

Ja, der deep-sleep ist auskommentiert. Es wird nicht mehr zwischen den Fällen "hell" und "dunkel" unterschieden, deshalb die Auskommentierungen. Stattdessen wird generell nach "loop_ende:" der idle-Modus aktiviert. Im Endeffekt läuft es darauf hinaus, daß nur noch der sleep-idle-Modus aktiviert wird.

Ich habe die Gegenprobe bereits gemacht - mit deep-sleep steigt der Controller nach einer unbestimmten Zeit wieder aus. Ohne deep-sleep nicht mehr. Zumindest läuft er damit jetzt schon eine ganze Weile.

Der Vollständigkeit halber noch diese kleinen Änderungen, die mit dem Absturz aber nichts zu tun haben dürften: Vorher ab Zeile 172:

1
rcall get_from_sram
2
 mov rmp, sramvalue
3
 andi rmp,0x07 ; drei lsb aus unterem nibble
4
 in temp, DDRB
5
 or temp, rmp
6
 out DDRB, temp

Nachher ab Zeile 172:

1
rcall get_from_sram
2
 mov rmp, sramvalue
3
 andi rmp,0x07 ; drei lsb aus unterem nibble
4
 in temp, DDRB
5
 cbr temp,0x07 ; letzte drei Bit löschen        <==== neu
6
 add temp, rmp ; und aus dem sram neu setzen    <==== statt "or"
7
 out DDRB, temp

Analog dazu für PORTB etwas weiter unten.

in "init_watchdog:" ein cli und sei rein, ein Versuch war's wert. Wie schon von Walter S. geschrieben können die wieder raus, die machen dort wirklich keinen Sinn.

in "Main:" zwei Initialisierungen

1
clr watchdogcounter
2
clr zero
#8039146
Lesenswert?

Ob S. schrieb:

Erstens muß man für diese RAM-Zelle dann ganz genauso auf korrekte und exklusive Benutzung prüfen

Du hast es nicht verstanden. Ich habe gesagt "eine Zelle pro ISR". Und prüfen muss man da lediglich im Editor, ob der Name dieser Zelle noch anderswo auftaucht (was er natürlich nicht darf). Register dagegen, für die ist es normal, an x Stellen benutzt zu werden.

zweitens braucht man immer noch ein MCU-Register zum Sichern, weil es keine Instruktionen gibt, mit der man SREG direkt in den RAM sichern bzw. von dort laden könnte.

Ja und? Dafür kann man ein Register nehmen, welches in der ISR ohnehin benutzt wird.

Richtig programmieren ist noch viel besser als defensiv programmieren. ... Möglichkeit zur Vergabe von Aliasnamen sehr gute Voraussetzungen dafür. Man muss sie nur konsequent auch in diesem Sinne nutzen

Du hast es wirklich nicht verstanden. Es geht beim defensiven Programmieren darum, dass man möglichst alles vermeidet, was nur funktioniert, wenn man es richtig (dein "konsequent") macht. Auf Deutsch: Denkbare Schlampereien gar nicht erst ermöglichen.

Aliasnamen sind da eine eher schlechte Lösung. Wenn man jedem Register nur einen Aliasnamen gibt, dann ist der im Kontext A vielleicht passend zur Bedeutung des gespeicherten Werts, im Kontext B aber nicht. Falls es nicht genügend Register für alle Kontexte gibt, muss man also manchen Registern mehr als einen Alias geben. Dann ist das Programm vielleicht korrekt, sicher aber unübersichtlich und fehlerisiko-behaftet. Oder man gibt dann einigen der Register gar keinen Alias - ist das wirklich besser? Und wo bliebe dabei deine Konsequenz?

#8039151
Lesenswert?

Stephan E. schrieb:

Ich habe die Gegenprobe bereits gemacht - mit deep-sleep steigt der Controller nach einer unbestimmten Zeit wieder aus. Ohne deep-sleep nicht mehr. Zumindest läuft er damit jetzt schon eine ganze Weile.

Wobei man aber nicht wissen kann, ob das DIREKT an dem Sleep-Modus liegt. Ja nach Sleep-Modus ändern sich ja Timing-Verhältnisse, die auch die Interrupts betreffen.

(Firma: 1984now) #8039155
Lesenswert?

Johann L. schrieb:

Kann man doch einfach PUSH / POP nehmen, so wie es zum Beispiel avr-gcc macht.

Nö. Auch ein C-Compiler kann natürlich nur die Instruktionen nutzen, die das Target zur Verfügung stellt. D.h.: auch der avr-gcc wird nicht sowas wie etwa "push SREG" erzeugen können. Nö, der wird, wie auch der Asm-Programmierer, temporär ein MCU-Register beschäftigen und die Sache so umsetzen müssen:

in reg, SREG push reg

Auch wenn C-Gläubige immer wieder die fantastischsten Behauptungen über die immensen Fähigkeiten der Compiler verbreiten, müssen diese sich letztlich doch der normativen Kraft des Faktischen beugen...

(Firma: 1984now) #8039172
Lesenswert?

Rolf schrieb:

Wobei man aber nicht wissen kann, ob das DIREKT an dem Sleep-Modus liegt.

Tut es nicht. Es liegt daran, dass diverse Initialisierungsroutinen innerhalb der Hauptschleife immer mal wieder aufgerufen werden.

Diese Initialisierungsroutinen sind allerdings so geschrieben, wie man sie für die Initialisierungsphase schreiben würde. Sprich: mit der stillschweigenden Annahme, das der Ausgangszustand der Hardware der Reset-Zustand ist und Interrupts noch nicht erlaubt sind. Hier müsste also nachgebessert werden.

Am sinnvollsten wäre allerdings, gleich die gesamte Programmstruktur umzubauen. Alles sollte in den ISRs passieren und die Hauptschleife so aussehen:

mainloop: sleep rjmp mainloop

Diese Programmstruktur würde den größten Teil der potentiellen Probleme von ganz alleine lösen. Eins allerdings nicht: Re-Initialisierungen der Hardware müssten natürlich trotzdem noch explizit berücksichtigen, dass sich "ihre" Hardware halt nicht im Reset-Zustand befindet.

(Firma: 1984now) #8039181
Lesenswert?

Rolf schrieb:

Aliasnamen sind da eine eher schlechte Lösung.

LOL. Was glaubst du denn, was eine "Variable" ist? Nix anderes als ein Aliasame für eine Speicherstelle. Naja und ggf. eine Vereinbarung, dass da mehr als eine Speicherstelle dranhängen.

Wenn man jedem Register nur einen Aliasnamen gibt, dann ist der im Kontext A vielleicht passend zur Bedeutung des gespeicherten Werts, im Kontext B aber nicht.

Das ist richtig. Genau deswegen gibt es die Möglichkeit, Register lokal mit einem anderen Alias zu belegen und am Ende der lokalen Bedeutung wieder mit dem ursprünglichen zu versehen. Man kann dies über entsprechende Makros sogar mit einer Sicherung der Registerinhalte verbinden (sollte sowas aber möglichst selten, am besten aber nie tun).

sicher aber unübersichtlich

Ja, sowas macht das Programm zunächst mal unübersichtlicher. Es ermöglicht aber eine gezielte (ggf. sogar automatisierte) Suche nach fälschlicher konkurrierender Nutzung.

Was aber vielleicht noch viel wichtiger ist: Bei diesem primitiven Programm wird man bei sinnvoller Programmierung überhaupt noch nicht auf die Situation treffen, dass Register mehrfach benutzt werden müssen. Es gibt halt schlicht und einfach mehr als genug für dieses simple Programm.

#8039194
Lesenswert?

Ob S. schrieb:

LOL. Was glaubst du denn, was eine "Variable" ist? Nix anderes als ein Aliasame für eine Speicherstelle.

Für wie blöd hältst du mich?

Register haben native Namen, die sind aus Bitmustern gebildet. Weil man sich diese Muster schlecht merken kann, haben die Register vom Assembler vergebene Aliasnamen (z. B. "R16"). Diese Namen nennt man aber in der Fachsprache üblicherweise nicht so: Wenn man da Alias sagt, meint man einen Alias, der eine Stufe höher ist (z. B. kann "Zähler" ein Alias für "R16" sein).

Und nur von den letztgenannten Aliassen war bisher die Rede. :-P

#8039203
Lesenswert?

Ob S. schrieb:

Tut es nicht. Es liegt daran, dass diverse Initialisierungsroutinen innerhalb der Hauptschleife immer mal wieder aufgerufen werden.

Diese Initialisierungsroutinen sind allerdings so geschrieben, wie man sie für die Initialisierungsphase schreiben würde. Sprich: mit der stillschweigenden Annahme, das der Ausgangszustand der Hardware der Reset-Zustand ist und Interrupts noch nicht erlaubt sind. Hier müsste also nachgebessert werden.

Dann mal Butter bei die Fisch: Welche Zeilen genau meinst du damit?

Denn irgendwie scheinst du über ein anderes Programm zu sprechen, als ganz oben angehängt ist.

Oliver

#8039267
Lesenswert?

an Stephan E.:

Das kann jetzt lange dauern, und vielleicht tritt der Fehler auf einem ATtiny85 gar nicht auf. Schau'n wir mal ...

Dies allerdings kann ich fast nicht glauben:

Das Original ist das im ersten Posting

Laden Sie mal exakt diese Programmdatei von hier aus dem Forum herunter, assemblieren und laden Sie in den ATtiny13A, und dann schreiben Sie uns, was die sechs LEDs anzeigen - also nach "Lauflicht" sieht das bei mir nicht aus ...

#8039538
Lesenswert?

an Stephan E.:

nach "Lauflicht" sieht das bei mir nicht aus

Entschuldigung, mein Fehler: ich hatte übersehen, dass REFS0/1 beim ATtiny85 eine andere Bedeutung haben.

Ansonsten läuft es bei mir seit 14 Stunden; und solange hier kein Fehler auftritt, möchte ich mich ungern nur theoretisch in Ihr Programm einarbeiten.

#8057333
Lesenswert?

Nun habe ich mir doch, etwas widerstrebend, einen ATtiny13A zugelegt - also:

Es scheint, als liege das Hängenbleiben daran, dass dem laufenden Timer0 (mit gesetztem OCIE) per PRR der Takt ab- und zugeschaltet wird (egal was das Datenblatt dazu schreibt). Eigentümlich ist, dass es beim ATtiny13A relativ häufig, beim ATtiny85 hingegen nur äußerst selten auftritt. Schalte ich den Timer0 ab vor Setzen von PRTIM0 und nach Löschen von PRTIM0 wieder an, tritt das Hängenbleiben auch nach vielen Stunden auf dem ATtiny13A nicht auf.

Moderator Persönliche Seite #8057425
Lesenswert?

Coole Analyse!

Könnte natürlich auf einen Bug in der Implementierung hindeuten, aber dafür müsste man das Hängenbleiben mit einem Minimalbeispiel reproduzierbar bekommen.

ATtinyX5 werden einfach mal andere Implementierungen haben, auch wenn der Ursprung vielleicht dem des ATtiny13 ähnelt. Selbst bei gleichem RTL-Code im Digitalbereich kann sich schon aus dem unterschiedlichen Layout ja ein leicht anderes Verhalten ergeben.

(Firma: Gast) #8057598
Lesenswert?

Haben wir irgendwo auch hier im Forum beackert. Sir Landolt, war auch dabei, unter seinem alten Namen, so wie ich auch. Finde es leider so ad hock nicht wieder.

Aufgefallen ist es in einer Arduino Anwendung. Es sollte ein Timer Interrupt mit einstellbarer Zeit verwendet werden. Das misslang mit allen Timern von ATMega328P und auch ATMega2560. Bin mir nicht mehr sicher das auch ATMega32U2 und ATTiny85 getestet wurden.

Fehlerbeschreibung, aus dem Gedächtnis: Arduino stellt in seiner Initialisierung alle Timer für PWM ein. Die AVR verwenden dann für z.B. OCR1A Schattenregister. Stellt man den Timer nur auf CTC um, versagt die korrekte Verwendung des Schattenregisters.

Der Effekt ist folgender: Der Interrupt kommt immer zu der zuvor in OCR1A eingestellten Zeit (default ist nach dem Reset 0). Man kann in OCR1A einstellen was man will. Es ändert sich nichts. Es wird weiter der Wert aus dem Schatten Register verwendet. Obwohl dieses laut Doku im CTC Mode gar nicht verwendet wird. Liest man OCR1A aus, sieht man den gewünschten, selbst gesetzten, Wert, der aber nicht vom Timer genutzt wird.

Die Abhilfe war: Den Timer erst händisch auf seine Default Reset Werte setzen, dann den CTC Mode setzen. Dann funktioniert OCR1A wie in der Doku beschrieben.

Nachtrag: Habe noch ein Testprogramm gefunden, siehe Anhang.

Angehängte Dateien:
: Bearbeitet durch User
#8057685
Lesenswert?

Ihr Elan steht dem resignierten Alter gegenüber.

das Datenblatt

Es betrifft mindestens zwei, nämlich ATtiny13A und ATtiny_5. Beide Typen sehr alt, ich glaube kaum, dass Microchip dafür nochmal aktualisierte Datenblätter herausgibt. Und, nur nebenbei, ich selbst wäre nie auf die Idee gekommen, einen laufenden Timer per PRR ein- und ausschalten zu wollen.

War jetzt ein (halbwegs) interessanter Exkurs, dabei möchte ich es belassen. Ich wünsche angenehmen Feiertag oder frohes Schaffen, je nach Bundesland.

Moderator Persönliche Seite #8057691
Lesenswert?

S. L. schrieb:

ich glaube kaum, dass Microchip dafür nochmal aktualisierte Datenblätter herausgibt.

Sie geben "Silicon errata and datasheet clarification"-Dokumente heraus. Dort sollte sich sowas finden, wenn sie es als Problem verifizieren können.

Und, nur nebenbei, ich selbst wäre nie auf die Idee gekommen, einen laufenden Timer per PRR ein- und ausschalten zu wollen.

Ich auch nicht.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren