Hallo zusammen,
ich habe gerade (d.h. den ganzen Sonntag) ein merkwürdiges Verhalten,
für das sich alle Erklärungsversuche als falsch herausgestellt haben.
Es handelt sich dabei um einen ATmega32 mit einem Grafik-Display mit
zwei KS0108 und einem normalen HD47800-kompatiblen Text-LCD (letzteres
soll durch ersteres ersetzt werden).
Dummerweise resetet sich der Controller ständig, oder besser: Häufig, in
sehr unregelmäßigen Abständen, wenn ich auf dem Grafik-Display einen
Text darstellen will.
Das merkwürdige ist, daß an anderer Stelle durchaus Texte problemlos
darzustellen gehen. Wenn ich eine Zeile einkommentiere, resetet sich der
Controller, nehme ich sie heraus, läuft alles problemlos durch.
Speicherprobleme aufgrund der Einbindung von snprintf/stdio schließe ich
mal aus, da an anderer Stelle weitaus längere Textstrings erzeugt
werden.
Auch lassen sich konstante längere Strings problemlos ständig
darstellen.
Mir sind die Ideen ausgegangen. Habt ihr neue?
So sieht's im Quelltext aus: (Die merkwürdige Stelle ist markiert).
Leider geht es nicht kürzer, weil ich die Ursache nicht eingrenzen kann.
1
/* Pulsgenerator
2
*
3
* HD44780-kompatibles LCDs im 4-Bit-Modus an PB0, PB3, PB4, PB5, PD4, PD5, PD6, PD7
Bist du sicher, dass du in strOut kein Zeichen hast bei dem du außerhalb
von FONT[] zu greifst?
Du hast da eine rel. unübersichtliche Zeichen=>Bitmap Umrechnung drin,
die ist mir suspekt.
> void glcd_putstr(char *zeichenkette)> void glcd_putchar(char c)> glcd_putdat(pgm_read_byte(&FONT[5*c-i-(31*5)]) );
Mir gefällt nicht, dass sowohl c als auch i an dieser Stelle den
Datentyp char haben und dass mit Zahlen außerhalb des char
Datenbereichs verglichen und zugewiesen wird
Bsp.: c bekommt der Funktion im switch den Wert "128" zugewiesen. Aber
tatsächlich steht in c der Wert -128 da char ein Vorzeichenbehafteter
Datentyp ist! Setze dann mal die -128 in die Formel 5*c-i-(31*5) ein...
Hallo ihr beiden,
erst einmal danke für's Anschauen, der Quelltext ist schon grob
unübersichtlich.
Die Vorzeichen in "putchar" gucke ich mir noch einmal in Ruhe heute
abend an. Es kann sein, daß da ein Schnellschuß drin ist. Vor allem eine
Abfrage für c < 0 habe ich einfach nicht bedacht. Daran wird es aber
auch wohl eher nicht liegen, da der Fehler ja sehr unregelmäßig auftritt
(nicht bei einem bestimmten Zählerstand).
Die Versorgungsspannung ist stabil und auch ausreichend abgeblockt an
beiden Displays und am ATmega, allerdings nicht wahnsinnig niederohmig.
Aber auch in der Richtung schaue ich heute abend mal nach, vielleicht
wird der Reset ja durch einen Dip in der Versorgungsspannung bewirkt.
Viele Grüße
Nicolas
Hallo zusammen,
MCUCSR wird als "0" ausgelesen- also ist der unfreiwillige Reset wohl
gar keiner (BODEN-Fuse ist aktiv, ein Brown-Out würde also auch als
solcher erkannt).
Die Versorgungsspannung ist stabil und keinerlei Einbruch feststellbar.
Ich habe mir allerdings auch die Reset-Leitung noch einmal vorgenommen
und dort auch in unregelmäßigen Anständen Oszillationen (siehe Bild im
Anhang) feststellen können, die auch in unregelmäßigen Abständen (5 - 15
s) auftreten. Allerdings ist keine Korrelation zwischen den
Oszillationen und dem Nicht-Reset festzustellen. Ein Abblocken mit 100nF
am Reset-Pin ändert auch nichts am Verhalten.
Nach dem Entfernen der "bösen" Zeile bleiben die Oszillationen und der
Nicht-Reset verschwindet.
Es bleibt mysteriös.
Viele Grüße
Nicolas
Hi,
ich hatte das gleiche Problem allerdings mit Bascom.
Die Lösung war seltsam aber ok ...
Ich darf einfach nicht mit 1,0 in die erste Zeile schreiben sondern mit
1,1 also ein Pixel von links weg. Dann funzt alles prima!
Vielleicht bringt das ja auch bei dir was.
Hallo Michael,
danke für den Tip, aber das war's leider auch nicht. Dafür habe ich den
Übeltäter enger eingrenzen können: In den extrem seltenen Fällen, wo
sich der ATmega32 aufhängt und nicht den Nicht-Reset schafft, bleibt er
an der folgenden Stelle stehen (in glcd_ks0108.c):
1
void glcd_wait()
2
{
3
//_delay_ms(1);
4
5
// Abfragen des Busy-Flags und warten
6
// Leider muessen nach dem Loeschen des Busy-Flags
Das erstaunliche ist, daß der High-Pegel nicht vom LCD ausgeht, sondern
vom ATmega. Und zwar ist der Ausgang sehr niederohmig auf High, obwohl
das Datenrichtungsregistern etwas anderes behauptet.
Ein Blick ins Assembler-Listing bring mich aber auch nicht weiter:
1
000006c6 <glcd_wait>:
2
//_delay_ms(1);
3
4
// Abfragen des Busy-Flags und warten
5
// Leider muessen nach dem Loeschen des Busy-Flags
Eigentlich alles so, wie es sein sollte: DDRC ist komplett auf 0x00, und
PORTC auch. So langsam habe ich das Gefühl bekloppt zu sein. Oder daß in
PORTC irgendetwas nicht stimmt. (JTAGEN ist aus, Fuses 0xD9BF).
Viele Grüße
Nicolas
Hast du den Code selbergeschrieben?
Soweit ich mich erinnere, sitzt das busyflag im statusregister, und das
musst du per "status_read" auslesen, um dessen aktuellen Wert zu
bekommen. "Einfach so" ändert sich der Pin am Dataport des LCD's nicht.
Generell ist es aber schneller und einfacher, das busyflag gar nicht
erst auszulesen, sondern einfach 0.5ms (oder so, ausprobieren) nach
jedem Befehl zu warten.
Oliver
Hallo Oliver,
ja, der Code ist selbstgeschrieben. Wenn ich einen Delay einbaue statt
der Abfrage des Statusbits läuft alles, nur sind meine Displays von
einem namhaften Resteverwurster aus Pförring und brauchen mindesten 3ms
delay.
Der Status wird auch korrekt abgefragt, wie im Datenblatt angegeben.
Momentan habe ich das unterklärliche Phänomen, daß der PD7 ein Ausgang
ist, obwohl er ein Eingang sein sollte. (Zumindest ist der Pegel auch
gegen einen Pull-Down-Widerstand High), obwohl er ein Eingang sein
sollte. Ich bin jetzt von PORTC auf PORTB umgezogen, und das Phänomen
läßt sich immer noch reproduzieren.
Viele Grüße
Nicolas
>Wenn ich einen Delay einbaue statt>der Abfrage des Statusbits läuft alles, nur sind meine Displays von>einem namhaften Resteverwurster aus Pförring und brauchen mindesten 3ms>delay.
Du meinst doch wahrscheinlich ein 3us Delay;)
3ms wäre schon extrem lang.
Einen funktionierenden Busy Check habe ich bei KS0108 bisher
noch nicht hinbekommen. Auch mehrere fremde Sourcecodes die vorgeben
einen Busy Check zu machen haben bei mir nie funktioniert.
Lag wohl daran das die Sourcen meist selber nur mit geringem Takt
liefen.
Wie lang das Delay ist hängt vom Takt des Displays ab.
Hier mal für meine Displays (in us):
#define KS108_E_DELAY 2 // Pollin Display TG12864B 596kHz FCLK
//#define KS108_E_DELAY 4 // Displaytech 64240A 395kHz FCLK.
Wenn du ein vernünftiges Display suchst das auch einen
Busy Check erlaubt dann nimm eines mit T6963C. Der KS0108 ist
einfach nur billiger Kram. Oder gleich ein DOGM mit SPI.
Die Dinger sind echt schnell.
Hallo Holger,
ein SPI-Display (z.B. Nokia-Display) wäre ein Traum, aber die alten
KS0108 müssen auch weg (und sind für meinen Zweck genau richtig wegen
der Größe und weil langsam kaum eine Rolle spielt).
Aber es ist zum heulen: Ich kriege den Fehler immer wieder reproduziert:
Wenn's abstürzt ist das Datenrichtungsregister vom LCD-Port falschherum.
Hier der Code:
PORT_GLCDCTRL &= ~(1 << GLCD_ECLK); // mehr als450ns warten
39
asm volatile ("nop");
40
:
41
:
42
asm volatile ("nop");
43
PORT_GLCDCTRL |= (1 << GLCD_RW);
44
PORT_GLCDCTRL &= ~(1 << GLCD_RS);
45
DDR_GLCDDATA = 0x00;
46
PORT_GLCDDATA = 0x00; // Pullups aus
47
asm volatile ("nop");
48
:
49
:
50
PORTA = DDR_GLCDDATA;
51
PORTD |= 1 << PD6; // DEBUG OUTPUT
52
while(bit_is_set(PIN_GLCDDATA,7)); // <----- Boese Zeile (Jetzt noch wissen warum)
53
PORTD &= ~(1 << PD6); // DEBUG OUTPUT
54
asm volatile ("nop");
55
:
56
:
57
asm volatile ("nop"); // keins zuviel!
58
}
Immer, wenn der ATmega abschmiert stehen alle Pins von PORTA auf High,
d.h. das Datenrichtungsregister von DDRB hat den falschen Wert
hinterlegt. Und ich weiß nicht warum. Es gibt keinen Interrupt mehr und
nichts, was dazwischen kommen könnte.
Viele Grüße
Nicolas
Hi
>Immer, wenn der ATmega abschmiert stehen alle Pins von PORTA auf High,>d.h. das Datenrichtungsregister von DDRB hat den falschen Wert>hinterlegt.
Was nun? PortA oder PortB?
MfG Spess
Nicolas S. schrieb:> while(PIN_GLCDDATA & 0x80); // <----- Boese Zeile (Jetzt noch wissen warum)Nicolas S. schrieb:> Der Status wird auch korrekt abgefragt, wie im Datenblatt angegeben.Nicolas S. schrieb:> wenn ich einen Delay einbaue statt> der Abfrage des Statusbits läuft alles,
Eine der drei Aussagen glaube ich dir nicht.
Um das noch zu erwähnen: Der Klassiker bei unerwarteten resets auf
Softwareseite ist eine fehlende ISR zu einem freigegeben Interrupt. Da
du deinen kompletten Code ja nicht zeigst, musst du das selber
überprüfen.
Oliver
Hallo nochmal,
ich habe die Lösung (?) gefunden. Um genau zu sein: Ich habe die MCU
gegen einen ATmega16 getauscht und jetzt funktioniert alles wie
erwartet. Also hatte wahrscheinlich der alte ATmega32 einen wech - naja,
hat ja auch schon einiges mitgemacht.
Oliver schrieb:> Da> du deinen kompletten Code ja nicht zeigst, musst du das selber> überprüfen.
Soviel hatte sich im Vergleich zum ersten Posting auch nicht geändert,
daß ich es für nötig gehalten hätte, es noch einmal zu posten. Um genau
zu sein nur die Zeilen, die ich auch gepostet habe.
Vielen Dank für die Tips und einen schönen Abend wünscht euch
Nicolas