Hallo Leute,
nachdem ich lange Zeit stiller Mitleser bin (und weiß wie verhasst
LCD-Display Threads sind !) hab ich jetzt ein Problem wo ich einfach
nicht mehr weiter weiß.
Das angehängte Programm gibt 'Hello World' auf einem LCD-Display aus.
Das LCD-Display ist dabei von Gleichmann (GE-C1602B), Controller-Chip
müsste ST7066U sein. Er hält sich aber an die Vorgaben des HD44780 und
lässt sich so auch ansteuern (über die Arduino LiquidCrystal Library
habe ich das getestet).
Benutzes Board ist also ein Arduino UNO, Atmel Chip ist AtMega328P.
Sollte tatsächlich jemand irgendein Timing oder so überprüfen wollen,
das Datenblatt des Displays gibt es hier:
http://www.msc-ge.com/download/displays/dabla_allg/ge-c1602b-tmi-ct-r.pdf
(Die Timing-Sachen sind aber wohl wahrscheinlich aus dem Datenblatt des
Controller Chips 1zu1 übernommen, dieses gibt es hier:
http://www.crystalfontz.com/controllers/ST7066U.pdf)
Nun aber zu meinem Problem: Es funktioniert.
Nur leider nur wenn ich das Programm gerade mit AVRDude über den ISP
übertrage. Dann läuft es und das LCD wird richtig initialisiert. Ich
kann dann auch resetten (auf dem Arduino ist ein Reset-Knop eingebaut)
so oft ich will, es funktioniert stabil und immer wieder.
Das initialisieren schlägt aber fehl wenn ich die Stromversorung abhänge
und neu anstecke. Egal ob das Board dann nun über USB oder den ISP
versorgt wird, es initialisiert sich nichts. Auch nicht wenn ich
resette.
Ich hab es auch schon mit zwei verschiedenen Displays getestet. Beide
mucken (ich habe also beim Löten der Buchsenleiste nichts gebraten,
hoffe ich).
Ich kann mir nur vorstellen dass die Versorgungsspannung für das LCD
noch nicht ausreicht damit es seinen internen Reset durchgeführt hat
wenn ich meine Befehle sende. Was nur dagegen spricht:
a) Ich warte doch wirklich lang, und habe auch schon Wartezeiten im
Sekundenbereich ausprobiert.
b) Warum geht es nach dem Reset nicht ? Nur wenn ich davor gerade mit
AVRDude das Programm gesendet habe ?
c) Das gleiche Verhalten trat auch bei meinen Tests mit der Arduino
LiquidCrystal Library auf (bilde ich mir ein, ich kann es jetzt gerade
nicht testen)
Ich bin mittlerweile ziemlich am verzweifeln und wäre um ein paar
Stupser in die richtige Richtung echt dankbar !
Mfg,
Thomas
Hallöchen
Sorry. Aber den Assemblercode zu analysieren ist mir zuviel aufwand aber
:
Initialisiert Du die im Programm verwendeten Variablen und Register
korrekt ?
Beim Programmeinspielen werden normalerweise diese auf den Wert 0
gesetzt, was bei einem PowerUp nicht zuverlässig gemacht wird.
bG
Mandi
Sollte alles stimmen so warte die Funktion '326404 x 0x10' Zyklen, also
5222464 Zyklen, bei 62.5 Nanosekunden pro Zyklus (16 Mhz) sind das
immerhin 326404000 Nanosekunden, also beinnahe 0,33 Sekunden. Das müsste
doch eigentlich eine Welt für das LCDDisplay sein, vorallem weil das
Datenblatt von 40 ms after 4,5 Volt spricht. (Ich hab ja immerhin 326
ms).
Aber auch wenn ich den Wert exorbitant in die Höhe schraube (~16
Sekunden) ändert es nix...
Sitzt der wait an der evtl. an der falschen Stelle ???
Thomas
@Mandi:
hust Ini---was ???
Ich werd mal ein paar Initialisierungen einbauen, wäre toll wenns das
wäre...
Thomas
PS: Der Assemblercode ist ja nur als Referenz da, damit ihr eventuell
was nachschauen könnt, ich erwarte nicht dass den jemand komplett
studiert :-)
Also auch das initialisieren aller Register führt zu keinem Ergebnis.
Variablen nutze ich garkeine (der Atmel hat ja wahrlich genug Register).
Die Port-Register habe ich mal auf LOW geschalten vor dem ersten Befehl,
mal nicht -> Scheint auch nichts an dem Verhalten zu ändern.
Thomas
HI
Noch etwas: Du benutzt für die Initialisierung dein UP 'prepcommand',
das das Busy-Flag abfragt. Das Flag ist aber erst, je nach Interface
erst nach dem zweiten bzw. dritten 'Function Set' verfügbar.
Kommentare sollen erläutern, warum man etwas macht. Aber nicht in
Romanform.
Ramadressen kann man mit Labels versehen:
1
.dseg ; RAM
2
3
xyz: .Byte 1 ; reserviert 1 Byte an der Speicherstelle
@Holger:
zweimal, dreimal, viermal... es macht keinen Unterschied -> Nach
Übertragen des Programmes geht es, nach abstecken und anstecken geht es
nicht.
@spess53:
Prepcommand setzt die Datenleitungen entsprechend der Befehle - es mag
nicht schön aussehen, aber es funktioniert ja (nach dem Übertragen).
Das Busy-Flag frage ich nicht ab.
Was die Roman-Kommentare betrifft: Es ist halt nunmal eines der
anfänglichen Assembler-Programme, da wollte ich noch alles so gut wie
möglich kommentieren, sonst bin ich nicht so.
Ich glaube ja dass der Programmcode nicht sonderlich schön, kompakt oder
schnell ist - das würde ich alles mal verbessern (und auch die
Kommentare stehen auf meiner Liste !) wenn er denn stabil funktionieren
würde.
Ich kann mir eben nicht erklären warum er jedesmal nachdem ich ihn mit
AVRDude übertrage funktioniert, und nach dem abstecken nicht mehr.
Thomas
PS: Danke für den Tipp mit den Labels für die Ramadressen !
Hast du mal überprüft ob nur das LCD nicht will oder das ganze Programm
dann nicht tut?
Ich hab hier nen Programmer rumliegen den ich jedesmal neu flashen muss
wenn ich mal vergessen hab ihn abzustecken und er dann rückwärts
versorgt wird.
@snowfly:
Das scheint es auch nicht zu sein, anhand des Timings kann ich sehen
dass die LED wieder genauso nach X Sekunden angeht, wie bei den
Versuchen wo gerade programmiert wurde.
Außerdem habe ich ein zweites LCD Display und ein zweites Arduino Board
getestet.
Thomas
Guten Morgen,
hier mal der aktuelle Programmcode. Lasse nun die Register auf 0
initialisieren, außerdem werden die Pins jetzt zuerst auf Output
geschalten, und dann nochmal extra mit LOW initialisiert.
Noch dazu ist mir aufgefallen dass ein Interrupt-Vektor ja zwei
Instruction Words lang ist, deshalb noch die 'nop's vor dem 'reti' in
der Interrupt-Vektoren Tabelle.
Problem bleibt dabei aber bestehen wie eh und je.
Was ist denn anders zwischen:
a) Einem ganz neu starten des Atmel über externe Spannungsversorunge,
und
b) Einem neu starten des Atmel nach Übertragung des Programmcodes.
Lustigerweise kann ich nach dem übertragen des Programmcodes den Reset
auf LOW halten solange ich will (und während des Resets sogar die
Spannungsversorgung des LCDs abstecken) und sobald ich den Reset wieder
auf HIGH gebe geht alles.
Ich kapiers einfach nicht....
Thomas
Hi
>Ich kapiers einfach nicht....
Und wer soll dein 'Programm' kapieren? Niemand hat Lust an Hand des
Datenblattes zu kontrollieren, ob die IO-Adressen (Ports usw.) auf die
du zugreifst, richtig sind. Zumal noch nicht einmal klar ist, für
welchen Controller das Programm geschrieben ist. Für jeden Controller
gib es eine Include-Datei in der symbolische Adressen vereinbart sind,
mit denen ein Programm wesentlich lesbarer wird.
Du hast auch noch Fehler in deinem Code. Z.B. lädst du mit
lds r16, 0x0B
r16 mit dem Inhalt von r11. Gewollt?
MfG Spess
ThomasC schrieb:> 40 ms after 4,5 Volt spricht. (Ich hab ja immerhin 326> ms).
Und wie ist die Versorgungsspannung am LCD tatsächlich?
Wie ist der Verlauf bei Verwendung einer Batterie?
Wird die Mindestanstiegsgeschwindigkeit im Datenblatt des LCD erreicht?
(Seite 31 ST7066U-Datenblatt)
Ist im ATMEGA die Fuse für Brown-Out aktiviert oder ab welcher Spannung
läuft der Prozessor bereits los?
Ist die Versorgungsspannung im ausgeschalteten Zustand < 1V?
Ich hatte mal das Problem daß ich einen FTDI mit TTL-Schnittstelle am
ATMEGA dran hatte (über 2*1K Serienwiderstand). Der Strom aus dem FTDI
am RXD-Eingang über die Eingangsschutzdiode auf die Versorgung hat
gereicht um den Reset des LCD zu verhindern.
Gruß Anja
Hi
>> Leider können wir unser Register SPH und SPL nicht direkt adressieren>WAS? =-O>Versuch mal out sph, ...
Wenn das .include "m328pdef.inc" fehlt, kann man natürlich SPH, SPL...
nicht benutzen.
MfG Spess
Das ist ja nicht lesbar ...!
> Leider können wir unser Register SPH und SPL nicht direkt adressieren
WAS? =-O
Versuch mal out sph, ...
Verhält sich angehängtes File anders?
Edit: Update, hatte noch einen kleinen bug inne ..
spess53 schrieb:> Zumal noch nicht einmal klar ist, für> welchen Controller das Programm geschrieben ist.
Doch, steht oben:
ThomasC schrieb:> Benutzes Board ist also ein Arduino UNO, Atmel Chip ist AtMega328P.
Gruß
Jobst
@Spess:
Ich will ja garnicht dass jemand das ganze Programm durchsieht.
(wie gesagt, es ist nur der Vollständigkeit halber dabei)
Da es nach dem übertragen funktioniert gehe ich davon aus dass es ja
formal richtig sein muss.
Der Fehler den du entdeckt hast - Hut ab, der ist mir entgangen - ist
tatsächlich ein Fehler, er wirkt sich aber nicht aus,
da damit allerhöchstens andere Port-Bits verstellt werden, und da ich
noch nichts anderes angeschlossen habe ist das wohl egal.
Was die Include-Datei und die Benahmung der Ports betrifft, die habe ich
absichtlich weggelassen.
Ich will den Chip verstehen und deswegen so Hardwarenah wie möglich
bleiben.
Bei meinen ersten Programmen habe ich die Opcodes und die Sprung-Offsets
noch manuell im Hexeditor getippt.
Auch das geht :-)
@Anja:
Als externe Spannungsversorgung nimmt der Arduino die USB-Schnittstelle.
Das mit den Fuses und Brown-Out werde ich mal checken, ich habe etwas
von 2,7 Volt gelesen.
Eigentlich dachte ich aber dass mein 'ich warte mal 4 Sekunden und
schicke dann erst Befehle an das LCD-Display' ausreichen sollte -
egal was Brown-Out macht, bzw. wieviel Volt ich beim Start des
Programmes habe.
Dass die Spannung eventuell nicht steil genug ansteigt könnte sein.
Eventuell könnte ich testen die Versorgungsspannung für das LCD direkt
über einen I/O-Pin anzuschalten.
Was die Versorgungsspannung im ausgeschaltenen Zustand betrifft so ziehe
ich das USB-Kabel ab. So müsste es definitiv unter 1 Volt sein :-)
Übrigens habe ich auch schon mal über ein Labornetzgerät direkt 5 Volt
an den Atmel gegeben. Das hat auch nicht geholfen.
Vielen Dank, das sind mal ein paar Tipps und Dinge die ich probieren
könnte...
Thomas
spess53 schrieb:> Wenn das .include "m328pdef.inc" fehlt, kann man natürlich SPH, SPL...> nicht benutzen.
Stimmt natürlich ... ;-)
Haben wir hier jetzt ein bischen Kuddelmuddel gemacht? :-D
Gruß
Jobst
Hallo Leute,
ich hab den Fehler endlich gefunden. Es ist mir peinlich das zuzugeben,
aber es ist ein stinknormaler Programmierfehler.
Hier erstmal die Fehler, die beide in der Unterfunktion 'prepcommand'
waren:
1. In Zeile 413 lade ich PORTD nach r16, hier habe ich die falsche
Adresse genommen, es hätte nicht 0x0B sondern 0x2B sein sollten. Den
Fehler hat ja spess53 gefunden. Wow !
2. In Zeile 415 möchte ich die Bits im PORTD Register auf 0 setzen
welche meinen Datenleitungen entsprechen. Leider mach ich aber ein AND
mit '00001111' und nicht mit '11000011'. Somit habe ich die falschen
Bits geleert.
Warum ist mir das nicht aufgefallen ?
Da Fehler 2 keine Auswirkungen hat solange Fehler 1 existiert.
Wie ich drauf gekommen bin ?
Dank der Hilfe hier, dem gefundenen Fehler von spess53 (sollten wir uns
jemals im RL treffen so ist dir ein Bier oder gleich ein ganzer
Schweinebraten sicher !) und einem Logik Analysator der gezeigt hat dass
ein paar Lines auf HIGH bleiben.
Und warum bin ich nicht früher drauf gekommen ?
Weil ich mich viel zu sehr darauf versteift hatte dass es irgendwas
damit zu tun hätte das es nach dem frischen Übertragen geht und später
nicht mehr.
Jetzt hätte ich aber noch eine kleine Frage die wirklich nicht mehr weh
tut...
Ich nehme an nach dem übertragen ging alles gut, da das Register r11
immer 0 ist und somit Fehler 2 keine Auswirkungen hat. Wenn man aber
über eine externe Stromquelle den Atmel neustartet ist das Register r11
scheinbar nicht mit 0 initialisiert. Korrekt ?
Bringt mich jedenfalls zur Frage: Auf was stehen die Register direkt
nach dem einschalten ? Grundrauschen ? Unbestimmt ? ... Weiß das jemand
?
Jedenfalls ist das ganze sehr ärgerlich. Ich hab das Programm X-mal
debuggt und konnte da den Fehler nicht finden weil im AVRStduio
Simulator natürlich alle Register mit 0 initialisiert werden.
Tut mir also leid den nächsten Idioten-LCD-Thread gestartet zu haben.
Ich gelobe Besserung !
Mfg,
Thomas
Hi
>Bringt mich jedenfalls zur Frage: Auf was stehen die Register direkt>nach dem einschalten ? Grundrauschen ? Unbestimmt ? ... Weiß das jemand>?
Der Zustand der Register ist unbestimmt. Haben also, genau wie der RAM,
nach dem Einschalten zufällige Werte.
MfG Spess
> Was die Include-Datei und die Benahmung der Ports betrifft,> die habe ich absichtlich weggelassen.> Ich will den Chip verstehen und deswegen so Hardwarenah wie> möglich bleiben.
Was für ein Unsinn.
Dann führ dir wenigstens ein paar Namen für die Bezeichner ein.
Und wenn du das getan hast, kommst du drauf, dass das include File genau
das gleiche macht.
Mit genau demselben Argument könntest du auch die Memnonics weglassen
und alles per .db machen.
-> es gibt Dinge, die sind in einem realen Projekt nicht sinnvoll!
Und es gibt Dinge, die bringen dir keinen Erkentnisgewinn. In der
Programmierung geht es nicht darum, ob der CPU Befehl Add jetzt das
Bitmuster 010010001 hat oder nicht. Das ist Detailswissen das man sich
einmal ansieht wenn man sich dafür interessiert, aber dann gleich wieder
vergisst und dem Assembler überlässt solche Dinge zu wissen.
Ob du
1
// Unsere bits (DB7+DB6+DB5+DB4) auf 0 setzen durch ein AND mit 00001111 (0x0F)
schenkt sich nichts. Die eine Schreibweise hilft dir beim Verstehen was
da passiert nicht mehr oder weniger als die andere.
Aber: Die 2.te ist weniger fehleranfällig! Von leichter zu handhaben bei
Hardwaränderungen reden wir erst mal gar nicht.
Du musst dir eines merken: Wenn du dich genötigt siehst, solche Dinge in
einem Kommentar zu verewigen, dann machst du etwas falsch und musst dich
fragen: Wie kann ich die Möglichkeiten meines Programmiersystems nutzen,
so dass ich genau diesen Kommentar gar nicht brauche, sondern den Inhalt
des Kommentars im Code selber ausdrücken kann. Denn: Kommentare auf
dieser Ebene sind Schall und Rauch. Die sind öfter falsch als einem lieb
ist.
Deine Analyse ist falsch
> Warum ist mir das nicht aufgefallen ?
Weil deine Schreibweisen beschissen sind
> Wie ich drauf gekommen bin ?
Weil du ein paar 'Dumme' gefunden haben, die die Arbeit übernommen
haben, deinen Code auf Dinge zu kontrollieren, die bei vernünftiger
SChreibweise gar nicht passiert wären
> Und warum bin ich nicht früher drauf gekommen ?
Weil du unsinnigerweise auf bescheuerter SChreibweise bestehst
Und der wichtigste Punkt in deiner Analyse fehlt:
**** Was hab ich für die Zukunft daraus gelernt? ****
--> Das Schreibweise und die Möglichkeiten des Assemblers nicht einfach
nur optische Gimmicks sind, sondern ihren Sinn haben, gewisse dumme
Fehler gar nicht erst zu machen!
Dein Fehler in diesem Programm fängt nicht bei irgendwelchen technischen
Details an, sondern ist viel banaler: Du hast ihn dir selbst
eingebrockt, weil du nicht verinnerlicht hast, dass man sich seine
Arbeit so organisieren muss, das man sich selbst vor Fehlern schützt.
Deine Annahme 'Ich mache keine Fehler, also muss ich mir auch keine
Hilfskonstrukte machen' ist falsch!
PS: Deine 'Technik', jede Zeile am linken Rand anfangen zu lassen, fällt
in genau die gleiche Kategorie.