Hallo zusammen,
nun habe ich mein recht umfrangreiches Programm endlich fast fertig,
wird der Speicher knapp. AVR-GCC sagt:
Device: atmega328p
Program: 32410 bytes (98.9% Full)
(.text + .data + .bootloader)
Data: 1905 bytes (93.0% Full)
(.data + .bss + .noinit)
Optimieren kann ich den Code sicher noch, wird aber sehr schwierig. Ich
habe schon - soweit es mir möglich war - alle Register gezogen. Mit
PROGMEM habe ich experimentiert, das macht unter Data einiges frei,
allerdings brauche ich dafür extra Programmlogik für die wenig Platz
ist. Und am Verhalten konnte ich auch keine Veränderungen feststellen.
Das Seltsame: Flashe ich den Controller mit dem AVR-ISP II neu, startet
der Microcontroller einwandfrei und arbeitet das Programm ab. Nach einem
Reset ist er (meistens!) allerdings wie tot oder startet "seltsam" (z.B.
mit Verzögerung).
Das Programm gibt direkt am Anfang von main() einen Text auf einem LCD
aus.
Das nicht reproduzierbare Verhalten tritt schon auf, bevor der
Controller überhaupt diese Nachricht anzeigt. Man sieht dann lediglich
einen schwarzen Balken auf dem LCD.
Warum funktioniert das Programm dann aber nach dem Flaschen ohne
Probleme?
Über Tipps würde ich mich sehr freuen, ich würde nur ungern auf einen
anderen Controller (ATMega644) umsteigen ... Platinenlayout is schon
fertig und es ist kaum noch Platz für einen größeren Controller ... :-/
Viele Grüße
Sebastian
Du musst zu allererst auch bedenken, dass die RAM-Angabe sich rein auf
globale Variablen bezieht. Du brauchst noch RAM für lokale Variablen,
Stack, ...
Wenn voll, dann voll und dann passieren komische Dinge.
Bislang wurden für das Fehlverhalten nur Symptome am Display genannt.
Kannst du auch an anderen Komponenten Fehlfunktionen erkennen? Es kann
auch ein Timingproblem bei der Initialisierung des Displays sein, so daß
es mal unter bestimmten Vorbedingungen funktioniert und unter anderen
Bedingungen nicht mehr. Hast du eine oder mehrer Diagnose-LED oder einen
seriellen Anschluß als Kontrollmöglichkeit?
So Allgemein beschrieben ist eine zuverlässige Diagnose unmöglich! Da
hilft nur ein systematischer Test, Komponente für Komponente. Ein "es
funktioniert nicht" ist keine brauchbare Fehlerbeschreibung.
Es gibt hier irgendwo einen Codeschnipsel, mit dem man im laufenden
Betrieb den Minimalwert des noch freien RAMs bestimmen kann. Wenn da 0
rauskommt, braucht man eigentlich gar nicht weitersuchen.
Hallo zusammen,
herzlichen Dank für Euer Feedback!!!
Ich werde mit Euren Tipps heute Abend auf Fehlersuche/Optimierung gehen.
Ich werde den Speicherverbrauch messen und mal konsequent alles auf
PROGMEM umstellen.
Das mit der LCD-Initialisierung könnte auch stimmen. Denn da drüber
scheint der Controller nicht zu kommen. Wobei es auch sein könnte, dass
er gar nicht bis dahin kommt, denn das ist eigentlich das erste, was das
Programm macht. Vielleicht ist der Speicher so voll, dass das eine
Auswirkung auf das Timing hat.
Mir ist es nur ein Rätsel, warum alles nach einem Reset durch den
AVR-ISP (augenscheinlich) einwandfrei funktioniert. Incl. Timer, PWM,
EEPROM-Funktionen, usw. ... Also am Stack oder lokalen Variablen kann
das eigentlich nicht liegen.
Zum Debuggen habe ich ein Oszi, da sollte sich evtl. was machen lassen.
Ich kann den Code auch über Preprozesser-Direktiven auf eine serielle
Ausgabe umkonfigurieren (damit läuft die Firmware auf einem Arduino),
allerdings sind da einige Funktionen deaktiviert und der
Speicherverbrauch ist deutlich niedriger ...
Echt komisch, dieses nichtdeterministische Verhalten. Wirklich wohl ist
mir bei der Sache nicht! Vielleicht sollte ich das Ding als
Zufallszahlengenerator einsetzen. ;-)
Viele Grüße
Sebastian
Kommentier irgendwas optionales auf (z.B. die Display-Ausgabe). Wenn das
Programm dann stabil läft, hast du warscheinlich einen Stack-Überlauf
(also zu viel RAM belegt).
Das dein Programm direkt nach dem Flashen scheinbar ordnungsgemäß
funktioniert deutet eher nicht auf einen Stackoverflow hin. Klingt eher
nach nicht initialisierem Speicher oder sowas.
Sebastian M. schrieb:> Flashe ich den Controller mit dem AVR-ISP II neu, startet> der Microcontroller einwandfrei und arbeitet das Programm ab. Nach einem> Reset ist er (meistens!) allerdings wie tot oder startet "seltsam" (z.B.> mit Verzögerung).
Unterschiede im Startverhalten sind meist Initialisierungsfehler
(Reihenfolge, Zeitabläufe).
Sebastian M. schrieb:> Optimieren kann ich den Code sicher noch, wird aber sehr schwierig.
Aus Erfahrung kann ich Dir sagen, dass man da noch jede Menge rausholen
kann. Das fängt schon bei den Compiler-Optionen an (z.B. flto).
Wahrscheinlich magst Du Dein Programm hier nicht posten, aber ich bin
mir sicher, dass man 20-50% immer noch rausholen kann, wenn da mal ein
anderer auf den Code schaut.
Ich tippe nämlich auch auf einen Stacküberlauf - oder auf einen
Überschreiber im RAM.
Sebastian M. schrieb:> Ich habe schon - soweit es mir möglich war - alle Register gezogen.
Benutzt du hauptsächlich int statt char?
Viele globale Variable? Lokale Variable werden nur dann angelegt, wenn
sie auch beötigt werden. Danach ist der Speicher wieder frei.
Und eine ganze dumme Frage: Ist die Optimierung eingeschaltet?
Sebastian M. schrieb:> Das Programm gibt direkt am Anfang von main() einen Text auf einem LCD> aus.Sebastian M. schrieb:> Das Programm gibt direkt am Anfang von main() einen Text auf einem LCD> aus.
Bei der Länge von Texten sollte man sich auch einschränken. Meistens
sind einzelne Zeichen oder wenigstens Abkürzungen genauso
aussagekräftig.
Die Routinen, die für den Zugriff auf PROGMEM benötigt werden sind nicht
besonders umfangreich. Das hast Du bereits nach ein paar Zeilen Text
wieder reingeholt.
Auch wenn Du darauf achtest, dass DEINE Routinen schonend mit dem Stack
umgehen, muss das nicht heißen, das es fertige, eingeblendete
Fremdroutinen, auch tun.
Wie von anderen gesagt: Die Speicherberechnung erfasst nur den
"offensichtlichen" Speicher. Nicht den in den Routinen temporär
reservierten, und nicht den Stack. Besonders lecker ist eine Rekursion.
Viele Programmierer sichern, nach dem Einsprung in ihre Routinen, alle
Register, die sie plattmachen. Egal ob Du sie nutzt oder nicht. Eine
5-fache Verschachtelung von Unterroutinen mit jeweils 5 gesicherten
Registern ergibt ohne den program counter 25 Byte die keiner kennt. Ups!
Diese Programmierroutine ist aber nicht unbedingt als Fehler anzusehen,
sondern eher als Reflex.
@ Sebastian M. (cyberseb)
>Das Seltsame: Flashe ich den Controller mit dem AVR-ISP II neu, startet>der Microcontroller einwandfrei und arbeitet das Programm ab. Nach einem>Reset ist er (meistens!) allerdings wie tot oder startet "seltsam" (z.B.>mit Verzögerung).>Das Programm gibt direkt am Anfang von main() einen Text auf einem LCD>aus.>Das nicht reproduzierbare Verhalten tritt schon auf, bevor der>Controller überhaupt diese Nachricht anzeigt. Man sieht dann lediglich>einen schwarzen Balken auf dem LCD.
Das ist kein Speicherproblem sondern ein Initialisierungsproblem, dann
zu diesem Zeitpunkt sind ja noch keine großen Funktionen aufgerufen
worden. Wahrscheinlich fehlt ein Delay am Anfang, um das LCD korrekt zu
initialisieren. Vielleicht fehlt auch nur das Einschalten das Brown Out
Detektors bzw. einer großen Startup Zeit (AVR Fuses), damit die CPU erst
bei ausreichend Spannung losläuft. Das kann vor allem im Zusammenhang
mit dem LCD ein Problem sein. Der Controller kann auch mit 1,8V korrekt
arbeiten und rennt los, das LCD kann das nicht.
Hallo zusammen,
danke für Eure Tipps! Jetzt geht es weiter ...
Also, ich habe das Problem auf einem zweiten Gerät reproduziert. An ein
(einfaches) Initialisierungsproblem glaube ich nicht - es hängt
definitiv mit dem Speicher zusammen.
Ob es geht, oder nicht, ist von diesen zwei Codezeilen abhängig. Und die
sind mitten im Code, weit, weit weg von der Initialisierung:
screen_locate(1, 2);
screen_print("(Speed restored)");
Kommentiere ich die aus, läuft alles. Sind sie drin, funktioniert das
Programm direkt nach dem Flashen, aber nicht mehr nach einer
Stromunterbrechung.
Die LCD-Initialisierung funktioniert sonst ohne jegliche Probleme. Ich
könnte mir nur vorstellen, dass es evtl. aufgrund einer anderen
Speicherinitialisierung (ausgelöst vom AVR-ISP) "irgendwie" doch
funktionieren kann. Und mit dem o.g. Code startet das Programm auch
manchmal (selten), aber verzögert (mit schwarzen Balken).
Tja, ich werde wohl experimentieren und weiter optimieren müssen.
Diverse von Euch genannte Tipps hatte ich schon umgesetzt (z.B. CHAR
statt INT), ebenso sich widerholende Aufrufe in Schleifen/Funktionen
gepackt (hat alles ein paar Byte gebracht).
Jetzt werde ich das LCD mal "abschalten" und schauen, ob das Programm
soweit läuft. Ebenso werde ich mal testhalber Codeblöcke deaktivieren.
Den Code möchte ich nicht zeigen, da es eine Firmware für ein DIY-Kit
werden soll. Nicht um richtig Geld zu machen, sondern um Geld in die
Hobby-Kasse zurückfließeb zu lassen. Darum gibt es auch eine freie
Arduino-Version für die DIY-Community.
Wen es interessiert, es geht um einen frequengeregelten Sinus-Inverter
zur Geschwindigkeitsregelung von Plattenspielern:
http://mate-labs.de/magicquartz/
Viele Grüße
Sebastian
Jupp - nehme ich einen Programmteil raus (direkt mit einem "return;" am
Anfang einer größeren Funktion), funktioniert es einwandfrei.
Es liegt also am Speicherverbrauch!
Das Verhalten mit dem Reset durch den AVR-ISP macht mich aber ganz kirre
...
Gruß, Sebastian
Sebastian M. schrieb:> screen_print("(Speed restored)");
Hast du mehrere Code-Zeilen dieser Art? Speicher kannst du dann sparen
indem du den String im Flash lässt und dir eine screen_print-Variante
schreibst, die auch einen String aus dem Flash schreiben kann, z.B.:
1
//fuer den Zugriff auf den Flashspeicher
2
#include<avr/pgmspace.h>
3
...
4
screen_print_p(PSTR("(Speed restored)");
5
...
6
//funktion zum Schreiben von Strings aus dem Flash
7
voidscreen_print_p(constchar*stringFromFlash){
8
registercharzeichen;
9
while(zeichen=pgm_read_byte(stringFromFlash++)){
10
//lcd_put_char sei die Funktion, die generell nur ein Zeichen schreibt.
11
screen_print_char(zeichen);
12
}
13
}
14
...
Auf ähnliche Weise kann man auch das EEPROM nutzen wenn man es sonst
nicht braucht, der RAM aber knapp wird.
Hallo zusammen,
@Gerhard: danke, das freut mich!!!
@Tom: Um die 450-500 Bytes sind jetzt frei im Betrieb nach der von
sylaina vorgeschlagenen Änderung.
@sylaina: Gerade gemacht, danke! Ich bekomme jetzt:
Program: 32468 bytes (99.1% Full)
(.text + .data + .bootloader)
Data: 1517 bytes (74.1% Full)
(.data + .bss + .noinit)
Das hat wohl einiges gebracht.
Aber - trotz der ganzen Änderungen am Programmcode - ändert das am
Verhalten absolut nichts! Sobald ich das hier einbaue ...
screen_locate(1, 2);
screen_print("(Speed restored)");
... startet das Ding nicht mehr. Ich habe schon versucht die Klammern zu
ersetzen (man weiß ja nie?) und ein Delay vor die LCD-Init-Routine
gepackt, bringt alles nichts.
Das muss irgendwie mit dem Speicher zusammenhängen. Mir wird wohl nichts
anderes übrig bleiben, den Code kleiner zu bekommen.
Vielleicht sollte ich das EEPROM-Wearleveling (wird von Zeit zu Zeit um
ein Byte weitergeschoben) raushauen, das wird keinen stören! ;-)
Viele Grüße
Sebastian
@ Sebastian M. (cyberseb)
>Aber - trotz der ganzen Änderungen am Programmcode - ändert das am>Verhalten absolut nichts! Sobald ich das hier einbaue ...> screen_locate(1, 2);> screen_print("(Speed restored)");>... startet das Ding nicht mehr.
Tja, es ist immer noch ein Initialisierungsproblem ;-)
> Ich habe schon versucht die Klammern zu>ersetzen (man weiß ja nie?) und ein Delay vor die LCD-Init-Routine>gepackt, bringt alles nichts.>Das muss irgendwie mit dem Speicher zusammenhängen.
Nö. Du hast doch gerade das GEGENTEIL bewiesen!!
> Mir wird wohl nichts>anderes übrig bleiben, den Code kleiner zu bekommen.
Nö. Einfach mal nachdenken und eine systematische Fehlersuche
betreiben.
Sebastian M. schrieb:> Das Seltsame: Flashe ich den Controller mit dem AVR-ISP II neu, startet> der Microcontroller einwandfrei und arbeitet das Programm ab. Nach einem> Reset ist er (meistens!) allerdings wie tot oder startet "seltsam" (z.B.> mit Verzögerung).
Und wenn die Versorgung fur 1-2 Minuten abgeschaltet wird ?
Nach RESET werden nur die I/O Register auf Initial Values gesetzt -
aber RAM bleibt unverandert.
Ich glaube, dass irgendeine Routine (deine oder Library) falsch
annimmt, dass irgendeine RAM-Adresse auf 0 ist.
Nach flashen oder Stromabschalten stimmt das auch, aber nach einem
RESET nicht.
P.S.
Check mal: ' screen_print("(Speed restored)"); '
(Assembler listing)
@ Marc Vesely (Firma: Vescomp) (logarithmus)
> Ich glaube, dass irgendeine Routine (deine oder Library) falsch> annimmt, dass irgendeine RAM-Adresse auf 0 ist.
Nicht unbedingt 0, ggf. aber ein SINNVOLLER Wert.
> Nach flashen oder Stromabschalten stimmt das auch,
Nein. Nach einem Power Up Oder Flashen ist der SRAM ebenso undefiniert.
Er kann aber besonders beim Flashen durch das vorherige Programm auf
einen zufällig brauchbaren Wert gesetzt worden sein.
> Check mal: ' screen_print("(Speed restored)"); '
Ja.
> (Assembler listing)
Nein. Der Fehler liegt mit an Sicherheit grenzender Wahrscheinlichkeit
NICHT im Compiler oder Assembler sondern beim Entwickler der Funktionen.
Eine Sichtung des C-Quelltextes reicht vollkommen aus. Und man sollte
die Compilerwarnungen ernst nehmen. Sowas wie "variable x may be
uninitialized" ist sowas. Im Zweiflesfall setzt man ALLE lokalen
Variabelen bei der Definition in der Funktion erstmal auf 0.
Hallo zusammen,
oha - jetzt wird es interessant!
Ich will den Fehler undbedingt finden, aus Interesse. Leider habe ich
den problematischen Code nicht gesichert (ich Depp), aber der sollte
sich aus dem backup vom Vortag wieder herstellen lassen. Viel hatte ich
nicht geändert seit dem.
Also an unitialisierten Variablen liegt es nicht. Es gibt auch keine
Compiler-Warnungen.
Und der o.g. Codeschnipsel ist m.E. auch nicht direkt schuld an dem
Problem, da der bei dem von mir beschriebenen Fehlverhalten gar nicht
ausgeführt wird (auch nicht zwischen dem Neustart). Der ist "tief" im
Code vergraben und muss explizit vom User über eine Funktion aufgerufen
werden.
Ich glaube eher, dass das Problem auftritt, wenn die Programmgröße einen
gewissen Wert überschreitet.
Vielleicht liegt es doch am Compiler. Ich glaube ich verwende eine
ältere Version von 2012 oder 2013, weil mit der aktuellen mein Eclipse
Probleme hatte, den ATMega328 korrekt zu erkennen.
Heute Abend gehts weiter - aber viel Hoffnung, das zu finden, habe ich
nicht ... :-/
Gruß, Sebastian
tolles projekt.
Ich hatte seinerzeit eine dds (32.5kHz) aufgesetzt, die 60hz Sinus
erzeugt und das über Mosfettreiber / Halbbrücken mit einem Printtrafo
auf 110Volt hochtransformiert. Spielt (im "Schuhkarton") ganz toll, war
ruckzuck fertig und spielte etwas Geld in die Hobbykasse zurück.
man kann die Sache aber auch aufblasen und natürlich auch n Display
anschliessen :)
Axelr.
DG1RTO
@Sebastian M. (cyberseb) (Gast)
>Ich will den Fehler undbedingt finden, aus Interesse.
Gut!
>Leider habe ich>den problematischen Code nicht gesichert (ich Depp),
Schlecht!
>Also an unitialisierten Variablen liegt es nicht. Es gibt auch keine>Compiler-Warnungen.
Sind die alle eingeschaltet?
>Und der o.g. Codeschnipsel ist m.E. auch nicht direkt schuld an dem>Problem, da der bei dem von mir beschriebenen Fehlverhalten gar nicht>ausgeführt wird (auch nicht zwischen dem Neustart).
Dannhast du uns aber schön veralbert!
>Ich glaube eher, dass das Problem auftritt, wenn die Programmgröße einen>gewissen Wert überschreitet.
Welche theoretische Überlegung würde denn DAFÜR sprechen?
Du macht hier genau das Gegenteil einer systematischen Fehlersuche. Du
stellt wilde Theorien ohne Begründung auf. :-(
>Vielleicht liegt es doch am Compiler.
Möglich, aber unwahrscheinlich.
>Heute Abend gehts weiter - aber viel Hoffnung, das zu finden, habe ich>nicht ... :-/
Mit DER Einstellung sicher nicht.
Falk B. schrieb:>> Check mal: ' screen_print("(Speed restored)"); '>> Ja.>>> (Assembler listing)>> Nein. Der Fehler liegt mit an Sicherheit grenzender Wahrscheinlichkeit> NICHT im Compiler oder Assembler sondern beim Entwickler der Funktionen.
Genau das habe ich auch behauptet.
'screen' wird (auch wenn er erst später aufgerufen wird) am Anfang
initialisiert.
Wie das alles genau gemacht wird und was 'screen_print' für sich
reserviert und danach erwartet, sieht man nur aus Assembler listing.
Sebastian M. (cyberseb) schrieb:> Ich glaube eher, dass das Problem auftritt, wenn die Programmgröße einen> gewissen Wert überschreitet.
Na dann mache mal eine Dummy-Funktion, die genauso lang ist wie
'screen', werfe 'screen' raus und...
Wetten, dass es keine Probleme mehr gibt ?
@Falk:
>>Also an unitialisierten Variablen liegt es nicht. Es gibt auch keine>>Compiler-Warnungen.>> Sind die alle eingeschaltet?
Standard-Einstellungen. Ich schaue mal, ob sich da noch etwas machen
lässt! Guter Tipp - danke!
>>Und der o.g. Codeschnipsel ist m.E. auch nicht direkt schuld an dem>>Problem, da der bei dem von mir beschriebenen Fehlverhalten gar nicht>>ausgeführt wird (auch nicht zwischen dem Neustart).>> Dannhast du uns aber schön veralbert!
Warum denn? Ich hatte oben doch klar geschrieben, dass dieser Code weit
weg von der Initialisierung ist. Sorry, falls ich da nicht präzise genug
war - als Hilfesuchender möchte ich Euch auf keinen Fall veralbern!
>>Ich glaube eher, dass das Problem auftritt, wenn die Programmgröße einen>>gewissen Wert überschreitet.>> Welche theoretische Überlegung würde denn DAFÜR sprechen?> Du macht hier genau das Gegenteil einer systematischen Fehlersuche. Du> stellt wilde Theorien ohne Begründung auf. :-(
Halten wir fest, die Fakten:
- Der Code hat scheinbar Auswirkungen auf das Programmverhalten, obwohl
er gar nicht ausgeführt wird.
- Es macht einen Unterschied, ob der Controller vom AVR-ISP geflasht und
resettet wird oder er per Stromunterbrechung neu startet.
Daraus folgen meine Überlegungen:
Der o.g. C-Code macht das Programm größer. Teile des Binärcodes landen
an anderen Stellen im Flash. Allerdings sollte das keinen Einfluss auf
das Initialisieren von irgendwelchen Variablen (die ich ja eh alle
initialisiere) oder auf das Timing in der LCD-Initialisierung haben. Das
könnte vielleicht wirklich ein Compiler-Bug sein. Andererseits glaube
ich das aber nicht (unwahrscheinlich) und das Verhalten im Zusammenhang
mit dem AVR-ISP spricht auch dagegen.
M.E. ist es kein einfaches Initialisierungsproblem des LCDs - die
Routine hat immer einwandfrei funktioniert. Es muss irgend ein Mist im
RAM liegen (Werte von Variablen), die es verhindern, dass das Programm
über die LCD-Initialisierung kommt.
Wie würdest Du denn dann "systematisch" vorgehen? Ich werde heute Abend
noch ein paar von Euren Vorschlägen durchgehen.
@DG1RTO: Danke! Ja, das Ding ist wirklich aufgeblasen, da hast Du Recht.
:-)
Gruß, Sebastian
@ Sebastian M. (cyberseb) (Gast)
>Wie würdest Du denn dann "systematisch" vorgehen?
Hab ich das nicht schon mehrfach getan?
Zuerst mal die Brown Out Fuse setzen, ebenso die längste Wartezeit für
den Oszillator (beim 328er glaub ich 64ms).
Damit ist die Spannungsversorgung für das LCD! schon mal OK, wenn das
Programm losläuft.
Dann kann man mal den Großteil des Programms (im main) auskommentieren
und nur die IO-Initialisierung und die fragliche Funktion stehen lassen
und testen.
ICh vermute, daß dann das Problem immer noch da ist.
So wird das nichts! Du hast dich entschieden zu glauben, daß es an der
Codegröße liegt und willst das nun beweisen. Wenn der Fehler woanders
liegt, kann dieses Vorgehen nur scheitern.
Die Code-Größe an sich hat definitiv keine Auswirkung auf das Problem.
Allenfalls wenn der Programmspeicher nicht ausreichen würde, aber dann
kommst du gar nicht erst soweit den Flashvorgang abzuschließen.
Allenfalls der Rambedarf könnte Einfluß haben, aber der hängt nicht mit
der Codegröße zusammen! Außerdem ist der Rambedarf in der Regel nicht
davon abhängig wie resettet wurde.
Allenfalls wenn du eine Routine hättest die den Resetgrund auswertet,
könnte das Verhalten diesbezüglich unterschiedlich sein. Ansonsten ist
das Verhalten des Codes/der Software immer die gleiche. Solange keine
Eingaben in den Bootvorgang eingebaut werden, ist das Startverhalten
dann immer identisch. Dann bleibt nur ein Unterschiedliches Verhalten
der Hardware.
Gehe es systematisch durch.
Nehme alles raus bis auf die Displayroutinen und füttere die mit
Dummydaten zur Ausgabe. Bleibt das Problem?
Suche eine alternative Ausgabemöglichkeit, Serieller Port, LED etc
Bevor wir mit On-Chip-debugging bzw JTAG loslegen würde ich im Program
an den entscheiden Punkten eine Einfache Ausgabefunktion zur Kontrolle
einfügen. Dann kannst du sehen wie weit das Programm kommt und ob die
Reihenfolge und Inhalte der Ausgaben vom Erwarteten Verhalten abweichen.
Sebastian M. schrieb:> Das Seltsame: Flashe ich den Controller mit dem AVR-ISP II neu, startet> der Microcontroller einwandfrei und arbeitet das Programm ab. Nach einem> Reset ist er (meistens!) allerdings wie tot oder startet "seltsam" (z.B.> mit Verzögerung).GANZ ENTSCHEIDENDE FRAGE
Was exakt verstehst du in diesem Falle unter einem Reset?
Strom aus, Strom an?
Strom aus, Pause, Strom an?
Benutzung eines Resettasters am Reset-Pin?
Oder oder oder...
Falls du einen Resettaster nutzt, wie ganau sie die komplette
Beschaltung des Pins exakt und absolut vollständig bei dir aus?
Welches Display verwendest du?
Hallo Falk & Carsten (und alle),
danke weiterhin für Eure Hilfe - ich hoffe, dass bei der Sache
wenigstens neue Erkenntnisse für das Forum herauskommen. (Ja, vermutlich
sitzt das Problem vor dem Computer, aber ein Ideal-Standard-Fehler ist
das glaube ich auch nicht ...)
Ihr habt Recht, meine Vorgehensweise bisher war sicher nicht
systematisch genug. Vermutlich weil ich mit meinem Latein bei der Sache
einfach am Ende bin.
Ich konnte einen älteren Code wiederherstellen, der das Problem hat. An
dem Display-Aufruf (Codeschnipsel oben) liegt es hier nicht, es muss
also etwas Anderes sein.
Viele der Dinge, die Ihr genannt habt, waren schon immer OK:
- Kein Watchdog
- Verwende Brown-Out-Detection
- Wartezeit auf Maximum
Und hier hast Du Dich geirrt, Falk: Kommentiere ich einen Codeblock in
der main() aus (der niemals zur Auführung kommt und was das Programm
kleiner macht), funktioniert es! Weiß der Kuckuck, warum.
Ich habe nun meine Tools (Eclipse AVR Plugin) und den Compiler
geupdated. WOW, das hat noch einiges an der Programmgröße eingespart,
mit dem Ergebnis, dass es mit allen Update-Kombinationen funktioniert.
Eclipse Alt + Compiler Alt: Fehler vorhanden
Eclipse Neu + Compiler Alt: OK
Eclipse Alt + Compiler Neu: OK
Eclipse Neu + Compiler Neu: OK
("Eclipse" meint hier das AVR-Plugin)
Die Ergebnisse hängen an. Was ich so gesehen habe, verwendet das Eclipse
AVR Plugin z.B. die Optionen -ffunction-sections -fdata-sections. Aber
das ist nicht alles; auch wenn ich diese deaktiviere, ist das Programm
kleiner.
Dafür hat der neue Compiler doch noch uninitialisierte Variablen
gefunden. Ich werde nun auf die Alt/Alt-Kombi zurückwechseln und
weitertesten.
Viele Grüße, Sebastian
Sebastian M. schrieb:> Das Verhalten mit dem Reset durch den AVR-ISP macht mich aber ganz kirre> ...
Dir ist schon bewußt daß der AVRISP einen häßlichen Bug hat der dafür
sorgt daß eine Sekunde nach dem Einschalten nochmal grundlos ein Reset
gegeben wird? Vielleicht erklärt das das seltsame Verhalten das Du beim
Einschalten beobachtest. Stöpsel den mal ab und probier es ohne.
Tom, danke! -Wextra hat tatsächlich noch ein paar unbenutzte an
Funktionen übergebene Parameter gefunden. Das dürfte den Code kleiner
machen, aber das ursprüngliche Problem sollte das auch nicht lösen ...
:-(
Bernd, ach, das ist ein Bug? (Man gewöhnt sich dran :-D) Leider startet
der Mega ohne den ISP auch nicht ...
Also die uninitalisierten Variablen sind unkritisch. Einmal handelte es
sich tatsächlich um ungenutzten Code (lustig, was für einen Mist man bei
vielen kleinen Änderungen so produziert), das andere ist das Auslesen
des ADCW-Registers in der ADC_Init()-Routine. Der Compiler weiß nicht,
dass das nötig ist.
Sebastian M. schrieb:> Tom, danke! -Wextra hat tatsächlich noch ein paar unbenutzte an> Funktionen übergebene Parameter gefunden. Das dürfte den Code kleiner> machen, aber das ursprüngliche Problem sollte das auch nicht lösen ...> :-(
Willst du nicht hören oder ist das ignore ?
Unbenutzte Parameter sind NICHT dein Problem, sondern Variablen die
BENUTZT, aber vorher nicht initialisiert sind.
Sogar die Reihenfolge der Variablendeklarationen kann dein Problem zum
Verschwinden bringen.
Von mir aus kannst du weiter stur annehmen, dass Compiler daran schuld
ist und dein Program keine Initialisierungfehler enthält.
Ich bin raus.
Marc,
ich habe keine uninitialisierten Variablen! Sorry, falls ich das nicht
explizit gesagt habe. Natürlich versuche ich Eure Ratschläge und Tipps
zu berücksichtigen und mich zu melden, aber ich kann auch nur Schritt
für Schritt vorgehen ...
Jedenfalls danke für Deine Hilfe und Zeit!!!
Gruß, Sebastian
Nachtrag: Das mit "unitialisiert" von mir oben ist tatsächlich falsch.
---------------
../main.c: In function 'ADC_Init':
../main.c:815:15: warning: variable 'result' set but not used
[-Wunused-but-set-variable]
unsigned int result = 0;
---------------
Kommt von:
---------------
void ADC_Init(void) {
unsigned int result = 0;
...
result = ADCW;
}
---------------
Das hat nichts mit "uninitialisiert" zu tun, sondern dass die Variable
nicht mehr verwendet wird, der GCC aber nicht weiß, dass ich ADCW
auslesen muss.
Sorry, war mein Fehler. Ich will Euer Feedback absolut nicht ignorieren,
sondern schätze die Zeit, die Ihr aufbringt, SEHR.
Gruß, Sebastian
Spätestens -Wextra aktiviert -Wuninitialized
Wenn da nix kommt (ich sehe oben in den angehängten Ausgaben nix), ist
es scheinbar ok?
Oder verwendest du irgendwo __attribute__((section(".noinit"))) oder
sowas?
Carsten R. schrieb:> GANZ ENTSCHEIDENDE FRAGE> Was exakt verstehst du in diesem Falle unter einem Reset?
Eine Antwort darauf wäre hilfreich. Ich habe das nicht ohne Grund fett
geschrieben.
Sebastian M. schrieb:> ich habe keine uninitialisierten Variablen! Sorry, falls ich das nicht> explizit gesagt habe. Natürlich versuche ich Eure Ratschläge und Tipps> zu berücksichtigen und mich zu melden, aber ich kann auch nur Schritt> für Schritt vorgehen ...
Ok, dann vergiss FLASH und konzentriere dich auf RAM.
Was ich mit Reihenfolge der Deklaration meinte, ist folgendes:
1
intArrPtr;
2
intDummyArr[20];
3
intSehrWichtigeVar1,SehrWichtigeVar2;
kann sehr lange funktionieren, muss aber nicht.
1
DummyArr[ArrPtr]=12345;
ist OK, wenn ArrPtr < 20 ist, was aber wenn ArrPtr > 20 ist ?
Deine SehrWichtigeVar1 hat plotzlich einen Wert von 12345.
Wenn du aber so deklarierst:
1
intSehrWichtigeVar1,SehrWichtigeVar2;
2
intArrPtr;
3
intDummyArr[20];
4
intUnwichtigeVar1,UnwichtigeVar2;
kann das sehr lange gut gehen und unentdeckt bleiben.
So etwas wiederum:
1
intSehrWichtigeVar1,SehrWichtigeVar2;
2
intDummyArr[20];
3
intArrPtr;
4
intUnwichtigeVar;
kann richtiges Chaos verursachen - muss aber nicht.
Marc V. schrieb:> Check mal: ' screen_print("(Speed restored)"); '> (Assembler listing)
Wie funktioniert diese Routine (wird RAM benutzt, wenn ja, wieviel RAM,
woher, etc.)
Nur als Beispiel - ich kenne dein Programm nicht.
EDIT:
Soviel ich weiß, überprüft C die Arraygrenzen nicht, deswegen...
@Tom: -Wuninitialized sagt, dass alles OK ist.
@Carsten: "Strom aus, Pause, Strom an". Ich habe auch schon längere
Pausen (mehrere Minuten) probiert, erfolglos.
Der Reset-Pin hängt über einen 10kOhm-Widerstand an VCC. Sollte
eigentlich passen.
Als nächstes werde ich mal mit dem Oszi schauen, ob das Programm im
Fehlerfall überhaupt irgendetwas macht. Könnte mit meinem alten Hameg
205 schwierig werden.
@Marc: Danke für Deine anschauliche Erklärung! Ich kann nicht 100%ig
ausschließen, dass ich in irgend einem Array einen derartigen Fehler
habe. Werde ich prüfen.
Die Funktion screen_print() ist nichts Besonderes, sondern nur ein
Wrapper, damit ich die Ausgabe auf die serielle Schnittstelle für die
Arduino-Version umleiten kann:
1
voidscreen_print(constchar*s){
2
#ifdef LCDDISPLAY
3
lcd_text((u8*)s);
4
#endif
5
#ifdef SERIAL
6
uart_puts(s);
7
#endif
8
}
9
10
...
11
12
voidlcd_text(u8*t){
13
while(*t){
14
lcd_data(*t);
15
t++;
16
}
17
}
Das ASM-Listing kann ich auch noch liefern, aber bis Sonntag ist erstmal
Schluss (geht nicht, bin bei der Family eingespannt ...).
Viele Grüße
Sebastian
Marc V. schrieb:> Was ich mit Reihenfolge der Deklaration meinte, ist folgendes:> int ArrPtr;> int DummyArr[20];> int SehrWichtigeVar1, SehrWichtigeVar2; kann sehr lange funktionieren,> muss aber nicht.> DummyArr[ArrPtr] = 12345;> ist OK, wenn ArrPtr < 20 ist, was aber wenn ArrPtr > 20 ist ?> Deine SehrWichtigeVar1 hat plotzlich einen Wert von 12345.
Frage interessehalber: Wenn DummyArr nur 20 Felder lang ist, sollte der
Compiler doch meckern wenn man versucht auf Feld 20 oder größer
zuzugreifen, oder? Also zumindest bei mir sagt dann der Compiler (ist
"nur" ein Warning): Array subscript is above array bounds.
OK, ich hab auc -Werror an und entferne auch alle Warnings.
@Sebastian M. (cyberseb)
>Als nächstes werde ich mal mit dem Oszi schauen, ob das Programm im>Fehlerfall überhaupt irgendetwas macht. Könnte mit meinem alten Hameg>205 schwierig werden.
Dazu braucht man kein Oszi. Eine LED kann man immer blinken lassen, auch
so langsam, das man als Mensch was sieht. Z.B. nach jedem größeren
Funktionsblock die LED toggeln.
>Das ASM-Listing kann ich auch noch liefern,
Das interessiert keinen. Poste VOLLSTÄNDIGEN Code als Anhang. Siehe
Netiquette.
M. K. schrieb:> Frage interessehalber: Wenn DummyArr nur 20 Felder lang ist, sollte der> Compiler doch meckern wenn man versucht auf Feld 20 oder größer> zuzugreifen, oder?
Das kann der Compiler nur in den alleroffensichtlichsten Fällen
feststellen, wenn überhaupt. Der Compiler wird jedoch NICHT versuchen
das Programm solange zu simulieren bis er alle möglichen Werte von allen
Variablen zu irgendeinem späteren Zeitpunkt kennt, das ist nicht
praktikabel oder stellenweise gar nicht möglich. Nur offensichtliche
Sachen die er in kürzester Zeit vollständig beweisen kann werden
angemeckert.
Es gibt jedoch Compiler die können (auf expliziten Wunsch)
Laufzeit-Checks in den Code einbauen wenn Array-Grenzen, Stack-Grenzen
oder andere Grenzen überschritten werden und dann an Ort und Stelle
unverzüglich eine aussagekräftige Laufzeitfehlermeldung werfen bevor
es im halbzerstörten Zustand noch 2 Minuten weiterläuft und dann erst
crasht. Aber sowas geht natürlich auf die Performance und auf die
Codegröße.
Und ich wüßte jetzt auch nicht ob der gcc das überhaupt kann oder
irgendein ein anderer C-Compiler, ich kenn das von verschiedenen Pascal
Compilern, sowohl historischen als auch aktuellen, da war das schon
immer ein bemerkenswertes optionales Zusatz-Feature das es von den
meisten anderen Compilersprachen unterschied.
Falk B. schrieb:>>Das ASM-Listing kann ich auch noch liefern,>> Das interessiert keinen. Poste VOLLSTÄNDIGEN Code als Anhang. Siehe> Netiquette.
Warum so ausschliesslich ?
Mich würde das (vielleicht) interessieren.
Vielleicht auch nicht...
Oder doch ?
Posten geht heutzutage ziemlich einfach, man muß es nicht selbst
zum Forum tragen, also ja, kannst posten.
Oder auch nicht, wie du willst...
Bernd K. schrieb:> Und ich wüßte jetzt auch nicht ob der gcc das überhaupt kann oder> irgendein ein anderer C-Compiler, ich kenn das von verschiedenen Pascal> Compilern, sowohl historischen als auch aktuellen, da war das schon> immer ein bemerkenswertes optionales Zusatz-Feature das es von den> meisten anderen Compilersprachen unterschied.
Und natürlich die Klarheit, Übersichtlichkeit etc.
Auch nach Monaten (oder Jahren) weiss man noch, was da läuft, im
Gegensatz zu manch anderen Sprachen (wer hat was von C gesagt ?)
Sebastian M. schrieb:> @Carsten: "Strom aus, Pause, Strom an". Ich habe auch schon längere> Pausen (mehrere Minuten) probiert, erfolglos.
Das ist kein Reset sondern ein Neustart. Der Reset des Programmerst
zupft einmal an der Resetleitung, während die Spannung stabil bleibt.
Viele ICs erwarten vorab eine Pause nachdem de Spannung stabil ist,
bevor initialisiert werden kann. Du merkst an dieser Stelle den
Unterschied zwischen dem Reset durch den Programmer und deinem "reset"?
Noch einmal:
Welches Display wird verwendet?
Carsten R. schrieb:> bevor initialisiert werden kann. Du merkst an dieser Stelle den> Unterschied zwischen dem Reset durch den Programmer und deinem "reset"?
Kläre mich auf, bitte.
Carsten R. schrieb:> Sebastian M. schrieb:>> @Carsten: "Strom aus, Pause, Strom an". Ich habe auch schon längere>> Pausen (mehrere Minuten) probiert, erfolglos.>> Der Reset des Programmerst> zupft einmal an der Resetleitung, während die Spannung stabil bleibt
Marc V. schrieb:> Kläre mich auf, bitte.
Hat er schon gemacht. Etwas genauer:
Bei deinem Reset mit Strom aus, Pause, Strom an sind bis zum
Programmstart möglicher Weise noch nicht alle Baugruppen (UART, ADC und
Co) im µC mit ausreichend Spannung versorgt, auch das LCD ist
möglicherweise noch nicht bereit wenn der µC die ersten Befehle an das
LCD schickt.
Wenn der ISP den µC resetet wird im Prinzip nur der Befehlszeiger wieder
an den Start gesetzt, aber alle Komponenten sind da schon startklar.
M. K. schrieb:> Frage interessehalber: Wenn DummyArr nur 20 Felder lang ist, sollte der> Compiler doch meckern wenn man versucht auf Feld 20 oder größer> zuzugreifen, oder?
Nein, der Compiler kann das im Allgemeinen nicht, bzw nur unter
bestimmten Voraussetzungen, z.B. wenn du beim Kompilieren den Zugriff
mit einem konstanten Index im Code stehen hast. Es muß zum Zeitpunkt des
kompilierens schon erkennbar sein, daß ein Zugriff außerhalb der Grenzen
erfolgt, bzw. erfolgen könnte.
Bei einem variablen Index müßte sowohl der Compiler entsprechend
intelligent, als auch aus dem Code heraus der Wertebereich der Variablen
exakt vorhersehbar sein. Das ist nicht immer grundsätzlich gegeben.
Bei einer einfachen for-Schleife wäre zum Beispiel machbar. Stattdessen
kann man den Zugriff an sich in eine Funktion einbetten die zur Laufzeit
prüft ob der Zugriff korrekt erfolgt. Das kostet natürlich Ressourcen,
erfordert aber keine so speziellen Vorbedingungen.
Hallo zusammen,
@Falk: Klar kann man das auch mit einer LED machen. Aber hier müsste ich
ggf. den Code anpassen, was ich vermeiden möchte. Das mit dem Oszi
sollte schon klappen, es ist ja ein digitales Speicheroszi und für eine
One-Shot-Messung sollte es taugen. Nur um zu sehen, dass das Programm
irgendetwas tut.
Mir ist es klar, dass es "pikant" ist, um Euren Rat zu fragen, ohne den
Quellcode zeigen zu wollen. Wenn ich gewusst hätte, dass wir derart tief
einsteigen, hätte ich vermutlich den Thread gar nicht erst gestartet.
Ich war halt der Hoffnung, dass das vielleicht auf dieses Phenomen
schonmal gestoßen ist. Ich bin jedoch guter Dinge, dass noch etwas
Interessantes für das Forum herauskommt.
@Carsten: Das Display ist das "DISPLAYTECH 126C" von Reichelt
(http://www.reichelt.de/LCD-162C-LED/3/index.html?&ACTION=3&LA=446&ARTICLE=31653&artnr=LCD+162C+LED&SEARCH=displaytech+162c).
An das Display wird nur geschrieben, nichts wird gelesen. Also dass mein
Programm auf irgendeine Antwort vom LCD wartet ist damit ausgeschlossen.
Auch ein Delay vor dem Initialisieren des Displays brachte nichts.
Abgesehen vom Display macht mein Programm im Fehlerfall sonst auch
nichts. Normalerweise müssten die PWM-Timer (Sinus-Erzeugung)
anspringen. Tun sie aber nicht. Das Programm startet m.E. gar nicht.
Mit dem Neustart hast Du Recht, es ist kein Reset. Um es noch mal klar
dazurstellen, das ist der Ablauf:
1. Schaltung läuft bereits (mit oder ohne Fehler, je nachdem, was vorher
passiert ist)
2. Flashen mit AVR-ISP, incl. Reset durch den AVR-ISP
3. Programm startet korrekt => Kein Fehler
4. Schaltung ausschalten
5. Schaltung einschalten (Neustart) => Fehler, Programm startet nicht
Dabei können 2. und 3. bzw. 4. und 5. beliebig wiederholt werden; das
Verhalten ist reproduzierbar auf einem 2. Gerät.
Der Grundaufbau des Programms in main() ist dabei so:
1. LCD initialisieren
2. Willkommensnachricht anzeigen
3. Timer konfigurieren und starten (Sinus-Erzeugung mit PWM, 1/10
Millisekunden-Zeitmessung)
4. ADC initialisieren (optischer Sensor, Strommessung)
5. Betriebsparameter aus dem "virtuellen" EEPROM (für Wear-Leveling
geshiftet) auslesen
6. Sinus-Amplitde hochfahren
7. Hauptschleife für "Hauptmenü", in der ggf. der Benutzer Funktionen
mit umfangreicherer Programmlogik startet, sowie "nicht
echtzeitkritische" Routineaufgaben (Stromüberwachung)
Über "1" kommt das Programm im Fehlerfall wohl nicht hinaus, sonst würde
ich einen leeren Bildschirm sehen und keinen schwarzen Balken.
Selbst wenn ich irgendwo Mist mit Arrays verzapft habe (z.B. über deren
Grenzen hinausschreibe), kann das vor "7" gar nicht passieren (ich kann
aber noch nicht ausschließen, dass ich bereits ab "3" einen Fehler drin
habe). Und bei meinem oben beschrieben Ablauf wurden niemals Funktionen
durch den User (also mich) aufgerufen.
Lösche ich dagegen Programmteile aus der Hauptschleife (6) heraus (die
ich während der Tests nicht benötige oder gar aufrufe), startet das
Programm jedoch einfwandfrei!
Ich werde an dem Code morgen weiterdebuggen, und will dabei wie folgt
vorgehen:
1. Mit dem Oszi die LCD-Datenleitungen überprüfen, ob irgendetwas im
Fehlerfall gesendet wird.
2. (Quick&Dirty): Schauen, ob das Umsortieren der globalen
Variablendeklarationen einen Einfluss auf das Verhalten hat.
4. Schauen, ob ich die Schaltung resetten kann, z.B. über den AVR-ISP
oder einen Schalter (um den Neustart zu umgehen).
3. Alle Array-Operationen prüfen, ggf. noch eine explizite Routine in
z.B. die For-Schleifen einbauen, die die Grenzen überwacht und einen
Fehler über das Display meldet. Könnte tricky werden, weil ich hier den
Code verändere ...
Viele Grüße
Sebastian
@Sebastian M. (cyberseb) (Gast)
>ggf. den Code anpassen, was ich vermeiden möchte. Das mit dem Oszi>sollte schon klappen, es ist ja ein digitales Speicheroszi und für eine>One-Shot-Messung sollte es taugen.
Warum jammmerst du dann rum?
"Als nächstes werde ich mal mit dem Oszi schauen, ob das Programm im
Fehlerfall überhaupt irgendetwas macht. Könnte mit meinem alten Hameg
205 schwierig werden."
>anspringen. Tun sie aber nicht. Das Programm startet m.E. gar nicht.
Merkwürdig.
>1. Schaltung läuft bereits (mit oder ohne Fehler, je nachdem, was vorher>passiert ist)>2. Flashen mit AVR-ISP, incl. Reset durch den AVR-ISP>3. Programm startet korrekt => Kein Fehler>4. Schaltung ausschalten>5. Schaltung einschalten (Neustart) => Fehler, Programm startet nicht
Das ist schon mal eine wichtige Aussage. Klingt nach wie vor nach einem
Initialisierungsproblem. Vielleicht hängt ein wichtiger Eingangspin in
der Luft, weil ein Pull-Up Widerstand fehlt.
>Der Grundaufbau des Programms in main() ist dabei so:
Spar dir die Lyrik, zeig den Quelltext sowie den Schaltplan!
>Über "1" kommt das Programm im Fehlerfall wohl nicht hinaus, sonst würde>ich einen leeren Bildschirm sehen und keinen schwarzen Balken.
Also ist schon mal was Grundlegendes falsch. Möglicherweise eine
IO-Initialisierung. Für ein bisschen LCD-Ansteuerung reichen ein paar
Bytes RAM meistens aus, wenn man nicht mit printf() & Co arbeitet.
>Lösche ich dagegen Programmteile aus der Hauptschleife (6) heraus (die>ich während der Tests nicht benötige oder gar aufrufe), startet das>Programm jedoch einfwandfrei!
Hmmm.
>1. Mit dem Oszi die LCD-Datenleitungen überprüfen, ob irgendetwas im>Fehlerfall gesendet wird.
Sinnvoll.
>2. (Quick&Dirty): Schauen, ob das Umsortieren der globalen>Variablendeklarationen einen Einfluss auf das Verhalten hat.
Wenig sinnvoll.
>4. Schauen, ob ich die Schaltung resetten kann, z.B. über den AVR-ISP>oder einen Schalter (um den Neustart zu umgehen).
?
>3. Alle Array-Operationen prüfen, ggf. noch eine explizite Routine in>z.B. die For-Schleifen einbauen, die die Grenzen überwacht und einen>Fehler über das Display meldet. Könnte tricky werden, weil ich hier den>Code verändere ...
Wenig sinnvoll. Wenn der Fehler reproduzierbar ist, muss man die Stelle
finden, wo das Programm GENAU hängen bleibt!
Wenn du nicht magst, reicht eventuell auch schon der komplette Code
zumindest bis einschließlich des LCD-Inits.
Vielleicht "initialisiert" du ja manche Register mit &= oder |= oder so.
Setzt also gewisse Anfangszustände voraus.
Hallo Tom & Falk,
danke für Eure Hilfe!
Vielleicht mache ich wirklich Mist mit dem Initialisieren des LCDs. Ich
muss das morgen mal in Ruhe durchgehen und testen. Ich werde berichten -
und mich (vermutlich) schämen ... :-/
Wobei mir immer noch nicht wirklich klar ist, wie ein ungenutzter Code
(weiter unten in main, der auch nichts an den Ports macht) Einfluss auf
die LCD-Initialisierung haben kann, je nachdem, ob er auskommentiert
ist, oder nicht. Und die Rolle des AVR-ISPs ... Ich hoffe, das wird noch
interessant.
Schaltplan hängt an! (Der AVR-ISP könnte da ja Einfluss darauf haben,
wenn sich das LCD mit dem AVR-ISP Leitungen teilen würde. Tut er aber
nicht ...)
Gruß, Sebastian
@Tom: Am freien RAM sollte es nicht liegen. Ich habe den mit der o.g.
Routine intervallmäßig per Timer in verschiedenen Programmteilen auf dem
LCD ausgegeben.
Das waren bei dem alten (fehlerhaften) Code um die 500 Byte frei. Tiefe
Rekursionen habe ich ebenfalls nicht.
Ich werde das aber noch weiter im Auge behalten, erstmal schau ich mir
die LCD-Initialisierung an ...
Gruß, Sebastian
Tom schrieb:> Neben VCC oder AVCC? xD Fällt dir was auf?
Es müsste nur noch jemand einen passenden Schluss erklären können warum
dann das Programm läuft wie gewünscht, wenn der nicht benutzte Code
auskommentiert wird. Für mich ist das irgendwie nicht wirklich
schlüssig.
Hallo Tom,
bei mir hängen VCC, AVCC und AREF an +5V, die über 100n gegen Masse
gehen.
Nach https://www.mikrocontroller.net/articles/Datei:Mega8_Tutorial.png
sollte AREF jedoch über einen Kondensator auf Masse gehen.
Ich dachte, ich verwende die +5V als Referenzspannung, darum hängt der
an +5V.
Scheinbar ist das doch komplizierter, als ich dachte. Ich werde wohl den
Thread hier durcharbeiten müssen:
Beitrag "AREF = AVCC ????" ...
Gruß, Sebastian
Mit "versauter" Versorgung ist alles möglich. Da reicht es schon, wenn
eine Flash-Zelle falsch gelesen wird, weil die Spannung gerade einen
Einbruch hat. Die Zelle ist in der einen Code-Variante vielleicht in
Verwendung und bei der anderen nicht.
Löte mal SMD-Kerkos direkt an die Pins des Käfers dran. Zwischen VCC und
GND sowie zwischen AVCC und GND.
Wie du AREF beschaltest, hängt davon ab, wie du es benutzen willst! Wenn
interne Referenz -> Nur Kerko nach Masse.
Wenn eine externe Spannung als Referenz, hängst du eben diese dran (und
Kerko nach Masse).
Was du machen willst, das weißt nur du. Deinen Code kennen wir ja nicht.
Ultrawichtig ist aber, dass du jeweils VCC und AVCC je einen Kerko
spendierst!! Und zwar direkt am Chip, möglichst wenig Abstand.
M. K. schrieb:> Es müsste nur noch jemand einen passenden Schluss erklären können warum> dann das Programm läuft wie gewünscht, wenn der nicht benutzte Code> auskommentiert wird. Für mich ist das irgendwie nicht wirklich> schlüssig.
Geht mir genau so.
Ich habe tatsächlich auskommentierte "defines" in meiner LCD.h gefunden:
Zwar werden die Ports direkts in meiner main.c als Ausgänge gesetzt
(nicht aber sämtliche o.g. platzhalter wie LCD_DDR_D4). Mir ist nicht
klar, warum das überhaupt funktioniert. WAS setzt er auf "1", z.B. bei
[c]LCD_DDR_D4 = 1;[c]
?
Irgendwas anderes im RAM? Das könnte evtl. das beschriebene Problem
auslösen. Dann dürfte das LCD m.E. aber überhaupt nicht funktionieren
und es wundert mich auch, warum der Compiler nicht meckert (auch nicht
nach einem "make clean"). Woher nimmt der also diese Definitionen?
Ich muss das morgen mal an meiner Schaltung ausprobieren.
Wow, was da alles für Probleme zum Vorschein kommen. ICH DANKE EUCH!!!
@Tom: Danke für den Hinweis auf den extra Kondensator! Das werde ich
noch ändern. Auch die Erklärungen hier:
https://www.mikrocontroller.net/articles/AVR-Tutorial:_ADC#Referenzspannung_AREF
sind nützlich - z.B. sollte ich für die gewollte 5V Referenzspannung
einfach die interne nehmen.
Gruß, Sebastian
Sebastian M. (cyberseb) schrieb:> Scheinbar ist das doch komplizierter, als ich dachte. Ich werde wohl den> Thread hier durcharbeiten müssen:> Beitrag "AREF = AVCC ????" ...
Bevor du dich in sinnlosen Versuchen verlierst...
Stellen wir mal fest, was überhaupt passiert:
A) Nach flashen läuft alles.
B) Nach Reset oder Stromabschalten aber nicht mehr.
C) In der Zwischenzeit macht er keine Probleme.
Richtig so ?
Wenn ja, dann überlege mal was sich zwischen Flashen und Reset
verändert hat ?
Flash kann sich nicht verändern und I/O Register werden auch nach
Reset auf Initialwerte gesetzt.
Bleibt nur - RICHTIG - RAM.
Beim LCD-Init wird nichts gelesen, stimmt das ?
Da es nach Flashen richtig startet, aber nach Reset nicht mehr, sind
nur die Variablen interessant, die beim Initialisieren gebraucht
werden.
Sind wir uns soweit einig ?
Wenn ja, dann setze alle Variablen, die beim Init gebraucht werden
ganz vorne (oder ganz hinten, egal) und probiere es mal so.
Anbei ein Excel mit Werten nach ISP-Flashen und flashen mit Boot-
loader. Was interessant ist - bestimmte Bereiche im RAM behalten
immer die gleichen Werte - sind zwar von uC zu uC verschieden, aber
ab Adresse 269 z.B. behalten die immer den gleichen Wert.
P.S.
Es sind RAM-Adressen, nicht physikalische Adressen.
Hallo zusammen,
vergesst das, was ich über die Defines geschrieben habe. Die sind
natürlich nicht auskommentiert, sondern werden mit einem "#"
eingeleitet. Ouch!
Marc, Deine Annahmen sind richtig. Danke für das interessante Dokument!
Marc V. schrieb:> Wenn ja, dann setze alle Variablen, die beim Init gebraucht werden> ganz vorne (oder ganz hinten, egal) und probiere es mal so.>> Anbei ein Excel mit Werten nach ISP-Flashen und flashen mit Boot-> loader. Was interessant ist - bestimmte Bereiche im RAM behalten> immer die gleichen Werte - sind zwar von uC zu uC verschieden, aber> ab Adresse 269 z.B. behalten die immer den gleichen Wert.
Ich habe aber noch Probleme, das zu verstehen:
Was meinst Du mit "setzen"? Also den Variablen einen Wert zuweisen? Das
mache ich doch. Sollten die entsprechenden Speicherstellen bei einem
erneuten Start (egal ob mit oder ohne ISP) nicht automatisch dazu
führen, dass diese mit den gewünschten Variablenwerten befüllt werden?
Oder meinst Du mit "setzen" die Position im Code? Was meinst Du mit
"hinten"? D.h., ich sollte über die Position im Code erzwingen, dass die
Variblen im RAM vor Adresse 269 landen?
Heißt das, dass alles nach einem ISP-Flash nach dieser Position im RAM
erhalten bleibt? Was passiert dann aber mit dem Code, mit dem ich die
Variablen setze? Wird der ignoriert?
Gruß, Sebastian
Du solltest deine Register beim Start ordentlich initialisieren. Keine
Bits gezielt löschen/setzen, sondern einfach einen definierten Wert
reinschreiben. Du weißt ja nicht, was vorher drin war.
Sebastian M. (cyberseb) schrieb:> Oder meinst Du mit "setzen" die Position im Code? Was meinst Du mit
Ja, die Position war gemeint. Compiler wird wahrscheinlich die Adressen
im RAM entsprechend der Reihenfolge der Deklarationen zuweisen.
Falls du Arrays hast, deklariere ein paar Dummy-Variablen dahinter,
deklariere Pointer als volatile und integer etc.
> "hinten"? D.h., ich sollte über die Position im Code erzwingen, dass die> Variblen im RAM vor Adresse 269 landen?
Nicht unbedingt, ich wollte nur sagen, dass die RAM-Inhalte bei
bestimmten Speicherzellen bzw. Adressen nicht ganz zufällig sind, nach
flashen einen bestimmten Wert haben, aber nach Ausschalten und Reset
wiederum einen ganz anderen.
Ich arbeite selten mit C, bin mir also nicht sicher wie der Compiler
das genau macht, aber ich könnte mir vorstellen, dass beim include
schon RAM reserviert wird, falls du - wenn auch später - irgendwelche
Routinen aus diese library benutzst.
Wie gesagt, C ist nicht meine Stärke, wird es auch nie werden, ist
also nur eine Vermutung. Auf jeden Fall sollte der Compiler das
merken, ist also unwahrscheinlich, aber Arraygrenzen (Laufzeit) prüft
er ganz bestimmt nicht.
Tom: Wird morgen gemacht. Bei einigen Register setzt ich tatsächlich nur
die Bits, die ich benötigte. Auf solche möglichen Seiteneffekte (wenn
man einzelne Bits nicht explizit setzt) wäre ich nicht gekommen.
Marc: Danke, jetzt ist es mir klar, was Du gemeint hast. Ich werde als
nächstes den Code durchgehen, vermutlich laufe ich irgendwo über eine
Array-Grenze hinweg. Das könnte solche Effekte, wie Du sie beschrieben
hast, zum Fehlerfall führen lassen.
Herzlichen Dank!
Ich werde Euch auf dem Laufenden halten.
Gruß, Sebastian
Das müsste alles richtig verbunden sein. Ich glaube eher, da sind zu
viele "überflüssige" grüne Punkte drin, weil ich mir beim Erstellen des
Plans auch nicht ganz sicher war, wie KiCad das verarbeitet. Beim
Erstellen des PCBs bzw. beim "Check" wären die aber aufgeflogen. Ja, den
Plan muss ich auch noch schöner machen, bevor das Ding mal fertig wird
... :-)
Danke für den Hinweis!
Gruß, Sebastian
Bau mal ne Verzögerungsschleife ein von ein paar dutzend Millisekunden,
ganz am Anfang bevor Du anfängst das Display zu initialisieren.
Beim Aus- und Einschalten vorher den ISP-Stecker abziehen sonst spuckt
Dir der AVRISP möglicherweise in die Suppe, dem wird nämlich schwindelig
wenn das Gerät eingeschaltet wird während er dransteckt und er übergibt
sich dann über die Reset-Leitung.
Marc V. schrieb:> Ich arbeite selten mit C, bin mir also nicht sicher wie der Compiler> das genau macht, aber
Warum ergehst Du Dich dann in wilden Spekulationen und Behauptungen
darüber?
So, nun bin ich wieder zuhause. Wegen dem "Strom aus, Pause, Strom an"
vs reset über Resetpin hatte ich vergessen zu sagen.
Pack gleich in in die Startroutine zuallererst, also so das wirklich
absolut nichts anderes vorher ausgeführt wird und werden kann, ein Delay
bzw. eine Warteschleife die den Start um ein paar Hundert Millisekunden
verzögert, so daß sichergestellt ist daß die Spannung sich stabilisiert
hat und zusätzlich noch etwas mehr Zeit verstrichen ist für die von den
Chips geforderte Wartezeit !nach! anliegen einer stabilen Spannung.
Normalerweise braucht das nicht so lange sein, aber wir hkennen die
Qualität deiner Spannungsversorgung nicht.
Nachtrag:
Bernd war schneller mit dem Absenden. Ich würde glatt ein Bier auf die
Warteschleife verwetten. :D
Hallo zusammen,
danke für den Hinweis - ich hatte weiter oben aber schon geschrieben,
dass ich das auch schon probiert hatte:
Sebastian M. (cyberseb) schrieb:> An das Display wird nur geschrieben, nichts wird gelesen. Also dass mein> Programm auf irgendeine Antwort vom LCD wartet ist damit ausgeschlossen.> Auch ein Delay vor dem Initialisieren des Displays brachte nichts.
Naja, ich kann noch mal mit anderen Werten experimentieren.
Mein Buchgefühl sagt mir aber, dass es nicht am LCD liegt. Da wird ja
nur geschrieben und nicht gewartet. D.h, der AVR würde "drüberumpeln"
und mit dem Programm weitermachen, z.B. die PWM aktivieren. Macht er
aber nicht.
Carsten, das mit dem Delay schaue ich morgen an. Aber ich glaube nicht,
dass es daran liegt. Dafür ist das ganze Verhalten zu zufällig, und das
gefällt mir absolut gar nicht ... Vor allem, dass sich das Vorhandensein
von ungenutztem Programmcode irgendwie auswirkt! :-/
So wild finde ich Bernds Spekulationen gar nicht. Ich kann mir gut
vorstellen, dass ich über eine Arraygrenze hinausschreibe, und die von
Bernd beschrieben Effekte eine Auswirkung auf den Fehler haben. Fehlt
der unbenutzte Code, werden vielleicht die Variablendeklarationen vom
Compiler anders sortiert und der Fehler fällt nicht auf.
Inzwischen habe ich alle for-Schleifen und Array-Operationen überflogen,
sieht (leider!) gut aus. Relevant sind sicher nur die, die auch während
des Tests liefen. Das sind eigentlich nur die für das Abfahren der
Sinus-Tabelle und die zum Anpassung der Spannung bzw. Soft-Start (durch
Hochskalieren der Werte). Die erste ist etwas komplizierter, die zweite
ist wohl OK. Ich werde das morgen in Ruhe durchgehen und debuggen.
Seit den Updates (Compiler, Eclipse-AVR-Plugin) ist der Fehler ja
verschwunden und bleibt das hoffentlich auch. Vielleicht war das
wirklich ein Bug in der Toolchain (glaube ich aber nicht). Ich will den
Fehler aber trotzdem finden (alte Toolchain kann ich auch noch
verwenden).
Viele Grüße, Sebastian
Bernd K. schrieb:> Marc V. schrieb:>> Ich arbeite selten mit C, bin mir also nicht sicher wie der Compiler>> das genau macht, aber>> Warum ergehst Du Dich dann in wilden Spekulationen und Behauptungen> darüber?
Erstens, es sind keine wilden Behauptungen und Spekulationen, sondern
logisches denken - was bei dir ja scheinbar fehlt.
Zweitens, weil es bestimmte Regeln gibt, die ein Compiler ganz einfach
befolgen muss, egal ob Pascal oder C.
Drittens, du als attestiertes Genie weisst natürlich bis ins kleinste
Detail wie der Compiler das macht ?
Schweig still, wenn du nichts gescheites zu sagen hast, ausser zu
meckern.
Marc V. schrieb:> Flash kann sich nicht verändern und I/O Register werden auch nach> Reset auf Initialwerte gesetzt.> Bleibt nur - RICHTIG - RAM.
Oder interne Register der Peripherie. Möglicherweise gibt es beim AVR
auch Register die sich bei POR anders verhalten als bei einem manuellen
Reset über den Reset-Pin. Ich arbeite zwar mit PICs, aber da ist das so.
Das Datenblatt unterscheidet bei Initialwerten zwischen POR-BOR und
manuellem, WDT oder Softreset. Und bei einigen Registern macht das
Unterschiede. Vielleicht gibts sowas ja auch beim AVR.
Bad U. schrieb:> Oder interne Register der Peripherie. Möglicherweise gibt es beim AVR> auch Register die sich bei POR anders verhalten als bei einem manuellen> Reset über den Reset-Pin. Ich arbeite zwar mit PICs, aber da ist das so.
Nö.
Beim AVR macht es keinen Unterschied, es gibt 4 Arten von Reset,
bei allen ist das Verhalten nach dem Reset genau dasselbe.
Funktionert sogar ohne Clock.
Ok. Dann kann man das schonmal als Fehlerursache ausschließen :)
Ich wollte das auch nur mal in den Raum werfen, weil ich da auch schon
drüber gestolpert war.
Hallo zusammen,
also, ich habe weiter debuggt und das sind meine Ergebnisse:
- Der Controller startet im Fehlerfall gar nicht (und "rumpelt" auch
nicht über die LCD-Initialisierung drüber), denn die PWM wird nicht
aktiviert.
- Schleifen und Array-Zugriffe sind OK, ich habe die Grenzen zur
Laufzeit überwacht (Fehler wären auf dem LCD ausgegeben worden).
- Verschiedene Delays vor der Display-Initialisierung haben keinen
Einfluss.
Und ich habe interessante neue Erkenntnisse, die wohl belegen dürften,
dass dies kein Standardfehler ist!
Dazu habe ich mein Programm wie folgt abgeändert:
Das Delay dient dazu, dass ich einen Reset bzw. Neustart des Programms
machen kann, ohne dass der Code darunter zur Ausführung kommt. Außerdem
wird der Code darunter nicht wegoptimiert und damit kleiner.
Auch hier lässt sich der Fehler wie oben beschrieben reproduzieren! Das
Programm startet korrekt nach dem Flashen, nicht aber nach einem
Neustart (Strom aus, Strom an). Bei dem Test wurde niemals Befehl 4
ausgeführt, weil ich den Neustart immer während Befehl 3 ausgeführt
habe.
Also dass mein Code nach Befehl 3 irgendetwas im RAM ändert, kann ich
damit ausschließen, da er nie zur Ausführung kommt.
Interessant: Kommentiere ich jedoch Befehl 4 aus, tritt der Fehler nicht
auf.
Ich kann mir absolut keinen Reim daraus machen, wie nicht ausgeführter
Code einen Einfluss auf das Verhalten haben kann! Doch ein Compiler-Bug?
:-(
Gruß, Sebastian
Tom, mir wird wohl nichts anderes übrigbleiben, wenn ich den Fehler
finden werde. Ich hab mit dem Simulator noch nie etwas gemacht, aber ich
werde mich einarbeiten.
Ach ja, um Fehler bei der Stromversorgung (Ripple durch Schaltregler,
usw.) auszuschließen, habe ich folgendes Gemessen:
DC: 4,98V (Multimeter)
Ripple: ca. +/- 30mV (Soweit ich das mit dem Oszi beurteilen kann)
Sollte also passen ... Meh! :-(
Gruß, Sebastian
Ne, die Ripple, die den uC durcheinanderbringen, kannst du im
Zweifelsfall gar nicht messen. Wie sieht es denn an der Kerkofront aus?
Hast du da mal welche drangelötet (VCC-GND, AVCC-GND, AREF-GND)? Die
sind wichtig. Also, angenommen, ich wäre dein Kunde. Dann würde ich da
welche sehen wollen!
Das war gerade mein nächster Versuch ...
Brachte leider auch nichts. Allerdings sind das keine
Keramikkondensatoren, sondern Wima MKS-02, 100nF. Müssen das unbedingt
Keramikkondensatoren sein?
Die kommen aber auf jeden Falls ins finale Schaltungsdesign.
Als nächstes würde ich die Schaltung auf dem Breadboard nachbauen bzw.
eine Minimalbeschaltung, um zu schauen, ob das Programm dann startet ...
Oder hey, ich probiere einen Arduino. Zumindest die PWM sollte ich
messen können! :-)
Gruß, Sebastian
Sebastian M. schrieb:> Also dass mein Code nach Befehl 3 irgendetwas im RAM ändert, kann ich> damit ausschließen, da er nie zur Ausführung kommt.
Dem Compiler steht es durchaus frei Teile von 4 vor 3 zu machen, wenn
das das Gesamtergebnis aus der Sicht des Compilers nicht beeinflusst.
Es ist also unzulässig anzunehmen, dass nichts von 4 ausgeführt wurde.
Woher weißt Du das die vierte Zeile nie zur Ausführung kommt? Wenn du es
daraus schließt, daß der Text nicht erscheint, sollte man prüfen ob der
Fehler nicht in der Routine selbst liegen könnte. Diesen Schluß würde
ich daraus ziehen.
Sebastian M. schrieb:> An ein> (einfaches) Initialisierungsproblem glaube ich nicht - es hängt> definitiv mit dem Speicher zusammen.>> Ob es geht, oder nicht, ist von diesen zwei Codezeilen abhängig. Und die> sind mitten im Code, weit, weit weg von der Initialisierung:>> screen_locate(1, 2);> screen_print("(Speed restored)");
Das ist ein Trugschluß. Initialisierungsproblem bedeutet nicht, daß das
Problem zwangsläufig während der Initialisierung auftritt, sondern nur
daß sie nicht korrekt durchgeführt wird. Das kann sofort zu Problemen
führen, muß aber nicht. Initialisierung ist kein Selbstzweck, sondern
dient der Vorbereitung, damit nachfolgende Operationen korrekt auf einer
sauber definierten Basis durchgeführt werden. War die Initialisierung
fehlerhaft, so kann der Fehler später bei den Funktionen auftreten die
sich auf die Initialisierung stützen. Es muß auch nicht unbedingt diese
Hardware sein, es kann natürlich auch eine nicht definierte
Speicherstelle sein, welche je nach Startbedingung eventuell etwas
anders aussieht.
Mit screen_print_p funktioniert es aber. Worin besteht der Unterschied
der beiden Funktionen? Verwendet screen_print_p auch lcd_text oder
lcd_data? Wie sieht lcd_data aus?
Sebastian M. schrieb:> Den Code möchte ich nicht zeigen,
Dann können wir dir auch nicht helfen! Was nützen uns lustige
Methodennamen und Codefitzelchen, wenn wir nicht wissen dürfen was sie
bedeuten? Wir können keinen Code debuggen den wir nicht sehen dürfen.
Arduino Duemilanove (China-Clone) mit Quarz (kein Keramik-Resonator),
gleicher AVR-Typ:
Gleiches Verhalten (fast).
Ich habe zwar kein LCD dran, aber die PWM startet brav nach einem Flash
(über den AVR-ISP). Nach einem Reset über den Reset-Button startet sie
nicht.
Nehme ich dem Arduino kurz seine 5V (USB-Stecker ziehen), so:
- startet das Programm, wenn der AVR-ISP angeschlossen ist
- startet das Programm nicht, wenn der AVR-ISP nicht angeschlossen ist.
Im ersten fall könnte das mit dem zusätzlichen Reset durch den AVR-ISP
zusammenhängen (der resettet auch nochmal, wenn die Schaltung wieder
Strom kriegt). Wildes Rumdrücken auf dem Reset-Taster hilft auch nichts.
:-)
Seeeehr seltsam ...
Gruß, Sebastian
Sebastian M. schrieb:> Wildes Rumdrücken auf dem Reset-Taster hilft auch nichts.
Was macht der Reset-Taster? RESET auf GND ziehen? Mehr macht der ISP
auch nicht.
blablablubb schrieb:> Dem Compiler steht es durchaus frei Teile von 4 vor 3 zu machen, wenn> das das Gesamtergebnis aus der Sicht des Compilers nicht beeinflusst.> Es ist also unzulässig anzunehmen, dass nichts von 4 ausgeführt wurde.
Interessante Überlegungen - könnte durchaus wohl sein ...
Carsten R. schrieb:> Woher weißt Du das die vierte Zeile nie zur Ausführung kommt? Wenn du es> daraus schließt, daß der Text nicht erscheint,
Weil ich den Controller innerhalb des 10-Sekunden-Delays neu starte ...
Carsten R. schrieb:> Mit screen_print_p funktioniert es aber. Worin besteht der Unterschied> der beiden Funktionen? Verwendet screen_print_p auch lcd_text oder> lcd_data? Wie sieht lcd_data aus?
Das verwendet den Program-Space (PROGMEM). Kommt aber in der
fehlerhaften Version zuletzt gar nicht mehr zum Einsatz.
Carsten R. schrieb:> Dann können wir dir auch nicht helfen! Was nützen uns lustige> Methodennamen und Codefitzelchen, wenn wir nicht wissen dürfen was sie> bedeuten? Wir können keinen Code debuggen den wir nicht sehen dürfen.
Klar ... Aber um Deine Überlegungen mit der Initialisierung weiterführen
zu können, habe ich den relevanten Code angehängt - ich hoffe, der ist
ausreichend. Ich würde mich freuen, wenn Du drüberschauen könntest.
Viele Grüße
Sebastian
Dieser Code compiliert mit Sicherheit nicht. Bitte Code posten, der das
Problem aufzeigt und funktioniert.
Aber ansonsten:
Warum dieser Quatsch mit der Bitstruktur? Einfach Bitoperatoren, die der
Compiler vernünftig optimieren kann, wäre wohl zu einfach gewesen.
Das include guard #endif zu #ifndef lcd_drv_h steht mitten im Header.
Die Hälfte des Headers ist also nicht geschützt.
const wegcasten ist keine gute Idee. Das kann zu undefiniertem Verhalten
führen. Mache ein const u8* bei lcd_text.
Deine Nibble-Funktion löscht auch Bits vor dem Setzen kurz. Wenn D4 z.B.
high war, wird es, wenn es nach dem Aufruf wieder high sein soll, kurz
auf low getoggelt. Eigentlich kein Problem, aber total unschön.
blablablubb & Tom, ihr seid super!
Fragt mich nicht, aus welchen Codeschnipsen ich die LCD-Routinen vor
Jahren zusammengebastelt habe ... Die hatten sich bisher bewährt,
jahrelang funktioniert und ich habe sie nie hinterfragt.
Die Routinen fliegen raus und werden von Grund auf neu geschrieben.
Tom schrieb:> Das heißt, das Erste, das man messen könnte, wäre ein High-Pegel auf D4> und D5, gefolgt von einem kurzen Impuls auf E0?
Die sind schon von Beginn auf High und bleiben dann dort (im Fehlerfall)
Fritz G. schrieb:> Hast du dir das Quarz Signal angesehen, vielleicht schwingt der nicht> sauber?
Sollte passen, nachdem der Fehler auf einem Arduino auch auftritt ...
Gruß, Sebastian
Also, die LCD-Rotinen sind ausgetauscht. Ich habe im Prinzip die hier
verwendet:
https://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/LCD-Ansteuerung#Die_LCD_Routinen
und entsprechend angepasst und erweitert.
Das Problem besteht weiterhin.
Ich glaube auch langsam, dass wir an einem Punkt angekommen sind, an dem
Ihr mir ohne den Quellcode nicht helfen könnt. Wenn ich die Ursache
nicht finde, kann ich nur darauf hoffen, dass der neure
speicherplatzoptimierte Code (mit dem neueren GCC kompiliert)
einwandfrei läuft. Bis jetzt tut er es ...
Ansonsten habe ich noch die Variablen, die in den Interrupt-Routinen
verwendet werden, überprüft. Da waren tatsächlich zwei noch nicht auf
volatile gesetzt. Das brachte aber auch nichts.
Tom, das ist eine gute Idee. Ich schaue mal, ob ich den kompletten
Build-Prozess einmal mit dem alten und einmal mit dem neuen Compiler
GLEICH (d.h., ohne andere Compiler-Optionen, was über Eclipse gar nicht
so einfach geht) durchziehen kann.
Wenn ich auf etwas stoße, lasse ich es Euch wissen.
Auf jeden Fall: HERZLICH DANK - ich hätte nicht damit gerechnet, dass
Ihr so hilfsbereit bei einem closed-source Projekt seid. Vielleicht kann
ich der Community ja doch noch etwas zurückgeben, falls ich die Ursache
finde.
Viele Grüße
Sebastian
Ja, oder du nimmst nur den alten Compiler und entfernst dann die "nicht
genutzten" Programmteile, sodass die Initialisierung klappt (wie du es
mal beschrieben hast) und nimmst dann dieses Kompilat für den Vergleich.
Das Entscheidende müsste ja gleich an Anfang stehen...
Tom, Du bist genial! Danke! :-)
So hab ichs gemacht. Und tatsächlich gibt es am Programmanfang einen
Unterschied, je nachdem ob weiter unten im Code etwas auskommentiert ist
(was wie gesagt nie ausgeführt wird).
Und zwar macht er im fehlerbehafteten Code ein "push r0" bevor es
losgeht.
Im Diff-Screenshot links hellblau markiert.
Ich verstehe das noch nicht - ich habe ehrlich gesagt noch nie Assembler
programmiert. Ich bleibe aber dran und werde mal schauen, was die
neueren Compiler mit dem Code anstellen.
Gruß, Sebastian
Sebastian M. schrieb:> Carsten R. schrieb:>> Woher weißt Du das die vierte Zeile nie zur Ausführung kommt? Wenn du es>> daraus schließt, daß der Text nicht erscheint,>> Weil ich den Controller innerhalb des 10-Sekunden-Delays neu starte ...
Ich habe eine begrenzte Ahnung was du machst. Es wäre hilfreich wenn du
das was du beschreibst noch einmal kontrollierst ob es für jemanden
nachvollziehbar ist, der nicht sieht was du tust. Du nimmst zuviel als
gegeben an.
Entweder er kommt in beiden Fällen zum Delay und du startest vor Zeile 4
manuell neu. Das bedeutet es Funktioniert in beiden Fällen, Reset durch
Programmer und Manuelle Stromunterbrechung. Dann kannst du mangels
unterschied aber nicht diesen Schluß ziehen.
Sebastian M. schrieb:> Auch hier lässt sich der Fehler wie oben beschrieben reproduzieren!
Oder das Teil kommt tatsächlich ins Schleudern und die Ausgabe durch
Zeile 2 erfolgt nicht. Aber dann startest du auch nicht innerhalb des 10
Sekunden Delays sondern nur irgendwann nach 10 Sekunden ohne zu wissen
wo genau die CPU sich befindet.
Sebastian M. schrieb:> Carsten R. schrieb:>> Mit screen_print_p funktioniert es aber. Worin besteht der Unterschied>> der beiden Funktionen? Verwendet screen_print_p auch lcd_text oder>> lcd_data? Wie sieht lcd_data aus?>> Das verwendet den Program-Space (PROGMEM). Kommt aber in der> fehlerhaften Version zuletzt gar nicht mehr zum Einsatz.
Das ist nett, beantwortet aber leider meine Frage(n) nicht. Ich habe
lcd_text oder lcd_data im Verdacht, beziehungsweise etwas das bei denen
in der Nahrungskette liegt, die wir leider nicht nachverfolgen können.
Mittlerweile wird es aber anstrengend sich die Bröckchen
zusammenzustückeln weil man ständig im Dunkeln tappt.
Vermutlich ist auch der Code interessant, der VOR main() abläuft.
Tatsächlich gibt es auch hier Unterschiede: in <__do_copy_data> macht er
etwas anderes.
Nur wildes Raten, da ich wie gesagt noch nie ASM programmiert habe: In
dem auskommentierten Text (der eh nie ausgeführt wird), sind keine
Strings (korrekt gesagt char-Arrays) oder ähnliches, nur if-Vergleiche,
Zahlenoperationen und ein paar Funktionsaufrufe. Sollten mit "data" in
"<__do_copy_data>" z.B. Strings gemeint sein, so würde es für mich Sinn
ergeben, wenn die irgendwie an der Stelle in den RAM geladen werden. Der
alte Compiler könnte einen Bug haben, der hier irgendetwas falsch macht.
Tatsächlich habe ich das gefunden, keine Ahnung, ob das damit
zusammenhängt:
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=18145
Sebastian
Sebastian M. schrieb:> ergeben, wenn die irgendwie an der Stelle in den RAM geladen werden. Der> alte Compiler könnte einen Bug haben, der hier irgendetwas falsch macht.
LOL.
Wie ist der Wert für deine High Fuse ?
BOOTSZ1 und BOOTSZ0 auf 1 setzen.
Carsten, sorry, falls ich mich nicht klar ausgedrückt habe. Ich bin auch
schon ganz kirre und müde. Nochmal ganz einfach beschrieben:
[c]int main(void) {
lcd_init(); // Befehl 1
screen_print("Hello World"); // Befehl 2
_delay_ms(10000); // Befehl 3
screen_print_twoLines(("Begrüßungs"), 1, ("Text"), 2); // Befehl 4
// Timer und alles andere initialisieren
// Programm-Hauptschleife [c]
Nach einem Compilieren und einem Flashen mit dem AVR-ISP (und dem damit
einhergehenden Reset) läuft dieser Code zunächst einwandfrei. Auch über
Befehl 4 hinweg.
Schalte ich die Stromversorgung des AVRs nun aber ab und wieder ein,
funktioniert er nicht mehr. Der AVR kommt dabei nicht nichtmal über bzw.
zu Befehl 1.
(Das mit dem Delay war wirklich Quatsch. Das sollte unterbinden, dass
sich der RAM-Inhalt durch den späteren Code ändert. Schalte ich den AVR
aber ab, sollte der RAM-Inhalt ja ohnehin schwinden.)
Kommentiere ich "Befehl 4" aus und flashe neu, startet der AVR immer.
Auch nach einer Stromunterbrechung.
In dem Fall bleibt der ASM-Code für main() gleich (also Befehl 4
auskommentiert vs. nicht, hängt an), im Gegensatz dazu, wenn ich weiter
unten etwas im Code auskommentiere (was die vorherigen Posts von mir
zeigen).
Gruß, Sebastian
Marc V. schrieb:> LOL.> Wie ist der Wert für deine High Fuse ?>> BOOTSZ1 und BOOTSZ0 auf 1 setzen.
Warum LOL? (Klär mich auf!)
Die High Fuse ist auf "DE", BOOTSZ1=1 und BOOTSZ0=1. Eclipse sagt: "Boot
Flash size=256 words start address $3F00".
Sollte passen, oder?
Gruß, Sebastian
Sebastian M. schrieb:> Marc V. schrieb:>> LOL.>> Wie ist der Wert für deine High Fuse ?>>>> BOOTSZ1 und BOOTSZ0 auf 1 setzen.>> Warum LOL? (Klär mich auf!)>
Sorry, war nicht böse gemeint und war für mich selbst gedacht.
> Die High Fuse ist auf "DE", BOOTSZ1=1 und BOOTSZ0=1. Eclipse sagt: "Boot> Flash size=256 words start address $3F00".> Sollte passen, oder?
Ja.
Zu deinen Routinen:
Da werden Daten aus Flash ins RAM kopiert und zwar kopiert die Routine
links (alte ?) 1462Bytes von der Flashadresse 31004 nach RAMadresse
0x100 (da fangen Variablen an).
31004 + 1462 = 32466
Die Routine rechts kopiert genauso viele Bytes aber von der
Flashadresse 29674 nach RAMadresse 0x100.
29674 + 1462 = 31136
Deswegen dachte ich, dass die Boot Flash Size größer ist.
Aber auf jeden Fall bleiben dir somit nur 586 Bytes für Stack und
andere Variablen.
Ob das genug ist ?
Oder andere Variablen die du später deklarierst, überschreiben das.
OH GOTT, BOOTRST war auf 1. Setze ich das Bit auf 0, funktioniert es.
Ich glaube, dass es das war.
Und mir ist das nicht aufgefallen weil avrdude immer ein Problem mit dem
Auswerten des zurückgelesenen Flashs hat (siehe unten) und anschließend
nicht mehr die Fuses setzt ...
Aber warum hat sich das nicht früher bemerkbar gemacht?
Marc, herzlichen Dank für Deine Erklärungen - ich werde das morgen
versuchen zu verstehen und nachzuvollziehen. Im Moment ist mein Hirn
ziemlich am Ende.
Die 586 Byte sollten reichen, habe wenig Rekursion drin und den (neuen)
Code inzwischen schon stark optimieren können.
Viele Grüße,
Sebastian
Der falsche Resetvektor springt halt da hin, wo der Bootloader wäre.
Wenn dein Programm kleiner ist, ist da bis zum Ende FF. Dann ist das
kein Problem...
Wenn dein Programm größer ist, steht da Code. Und dann hängt sich der
Chip auf, stürzt ab, oder läuft mittendrin uninitialisiert an.
Sebastian M. schrieb:> Nach einem> Reset ist er (meistens!) allerdings wie tot oder startet "seltsam" (z.B.> mit Verzögerung).
Freut mich, daß das Rätsel gelöst wurde. Mir ist nur nicht klar wie das
damit zusammenpasst. Oder wurde da zwischendurch eine neue Version
geflasht und nicht einfach nur neu gestartet?
Für die Zukunft solltest Du dir angewöhnen systematisch alle
Detailänderungen zu überprüfen. Wenn etwas plötzlich nicht mehr
funktioniert hilft eine allgemeine Beschreibung nicht. Erstelle eine
präzise Schritt für Schritt Anleitung, so daß jeder sie nachvollziehen
kann ohne Dinge hellseherisch anzunehmen. Das ist nicht nur für uns,
sondern in erster Linie für Dich. Der Teufel steckt ja bekanntlich im
Detail. Dies ist da mal wieder ein Beispiel dafür.