Hi,
ich habe zwei Displays mit PCD8544 Controller erworben und habe mich
prompt dran gemacht, ein kleines Testprogramm für den PIC16F877A zu
schreiben.
Ansteuern wollte ich das Display gleich per SPI. Das Programm ist in
Assembler geschrieben.
Nun, die Kommunikation funktioniert zwar, allerdings mehr schlecht als
Recht...
Der PIC sendet zwar die Daten und das Display scheint sie auch zu
verarbeiten, z.B. die Konfiguration für den Kontrast, aber die
Darstellung des Testbildes klappt absolut nicht...Teile des Bildes
werden dargestellt aber nicht an richtiger Stelle...
Hier mal das Unterprogramm, welches eine der beiden Tabellen sendet:
1
SendT1
2
3
btfss PIR1,3
4
goto SendT1
5
bcf PIR1,3
6
movlw HIGH Logo1T1
7
movwf PCLATH
8
movf bytecount,w
9
call Logo1T1
10
movwf SSPBUF
11
incf bytecount,f
12
bcf STATUS,Z
13
movlw D'252'
14
subwf bytecount,w
15
btfss STATUS,Z
16
17
goto SendT1
18
clrf bytecount
Ich habe übrigens für die Fehlersuche eine Überprüfung des
Kollisionsbits "WCOL" mit programmiert, also wenn WCOL gesetzt dann
erleuchtet eine LED...und die LED leuchtet...
Geprüft wird nur bei den Konfigurationsbytes, also nicht wundern, beim
senden der Tabellen wird WCOL nicht geprüft.
Getestet habe ich auch die Prüfmethode die Microchip in diesem PDF hier
beschrieben hat.
http://ww1.microchip.com/downloads/en/DeviceDoc/spi.pdf
Aber wenn ich diese verwende, zeigt mir das Display gleich garnichts
mehr an, allerdings leuchtet die "CollisionsLED" nicht mehr...
1
SendT1
2
3
BANKSEL SSPSTAT
4
btfss SSPSTAT,BF ; Data transfer complete? (Buffer Full?)
Aus dem Code wird man nicht ganz schlau.
Ich habe früher schon einmal ein ähnliches Problem gehabt.
Hat sich nachher rausgestellt, dass ich die SPI zu schnell betrieben
hatte - oder anders gesagt, war das Layout nicht ganz für die SPI
Geschw. optimiert.
Zudem kann es noch Probleme mit dem richtigen SPI-Mode geben (Mode
0,0..1,1).
Aber alles das muss im DB des Displays drinstehen!
Fragst Du auch das Busy-Flag vom Display ab, bevor Du neue Daten
sendest?
Oder gibt es das nicht bei diesem LCD?
Übrigens ist der Befehl bcf STATUS,Z nach dem incf nicht notwendig, da
das
Z-Bit generell vom nachfolgenden subwf neu gesetzt wird.
Gruß
TK
TK schrieb:> Aus dem Code wird man nicht ganz schlau.> Ich habe früher schon einmal ein ähnliches Problem gehabt.> Hat sich nachher rausgestellt, dass ich die SPI zu schnell betrieben> hatte - oder anders gesagt, war das Layout nicht ganz für die SPI> Geschw. optimiert.> Zudem kann es noch Probleme mit dem richtigen SPI-Mode geben (Mode> 0,0..1,1).> Aber alles das muss im DB des Displays drinstehen!> Fragst Du auch das Busy-Flag vom Display ab, bevor Du neue Daten> sendest?> Oder gibt es das nicht bei diesem LCD?>> Übrigens ist der Befehl bcf STATUS,Z nach dem incf nicht notwendig, da> das> Z-Bit generell vom nachfolgenden subwf neu gesetzt wird.>>> Gruß> TK
Ich erklär kurz mal meinen Code.
Ich prüfe zuerst ob das SSPIF gesetzt wurde, ist dies der fall, wird das
SSPIF gelöscht und das HIGH Byte von Logo1T1 (erste lookup Tabelle) wird
nach PCLATH geladen. Dann wird der Wert in bytecount (Register welches
die Anzahl der gesendeten Bytes enthält) nach W geladen, dann wird die
Tabelle aufgerufen und der Wert in W zu PCL addiert um den
entsprechenden Wert aus der Tabelle zu erhalten. Mit retlw geht es von
der Tabelle zurück in das Unterprogramm wo W in SSPBUF kopiert wird und
bytecount inkrementiert wird.
Laut Datenblatt muss das Z-Flag in der Software gelöscht werden, das
wird ja auch in meinem Code gemacht, ich schiebe den Wert 252 nach W und
subtrahiere das von bytecount, ist das Ergebnis 0, wird ja das Z-Flag
gesetzt, ist das der Fall wurden alle 252Byte der ersten Tabelle
übermittelt und es geht weiter zur nächsten Tabelle, aber vorher wird
das Register bytecount noch gelöscht. Die Routine der zweiten Tabelle
sieht genauso aus.
Das Display sendet selbst leider keinerlei Daten an den Controller. Die
Taktversorgung des Displays(Takt für die Datenübertragung) beträgt
1/16Fosc, ich verwende einen 10Mhz Quartz, demnach hat SCLK eine
Frequenz von 625kHz, das Display schafft laut DB bis zu 4Mhz.
Was ich aber nicht verstehe ist, wieso jedesmal eine Datenkollision
stattfindet, obwohl ich ordnungsgemäß das SSPIF prüfe, fällt dir dazu
was ein?
Ich denke ich werde nochmal einen anderen SPI Mode wählen, aber
prinzipiell müsste der den ich mir ausgesucht habe so funktionieren.
Der Wert für CKE ist 1 und der für CKP ist 0.
Hallo Yves,
den Code habe ich prinzipiell schon verstanden. Es ging mir eher um die
Konfiguration der "Special Function Register"!
Bei der SPI gibt es noch ein SME oder SMP-Bit (hab jetzt die Bezeichnung
nicht mehr ganz im Kopf - aber liegt im SSPSTAT-Register - ich glaube
Bit 7). Damit entscheidet man, wie die Daten zurückgelesen werden - auf
die steigende oder die fallende Flanke. Da kann auch noch ein Problem
liegen. Aber Du sagtest ja, dass das LCD keine Daten zurücksendet, was
ich etwas komisch finde, denn woher weisst Du, wann die gesendeten Daten
vom LCD verarbeitet wurden. Müssen evtl. Wartezeiten zwischen dem Senden
von mehreren Schreibzyklen eingehalten werden? Wie sieht das denn mit
dem CS-Pin aus?
Der PIC ist ja als SPI-MASTER konfiguriert. Da wird der CS-Pin (/SS) nur
manuell gesetzt. Wie sieht das denn in Deinem Code aus?
Gut was kann sonst noch sein - eine Datenkollision entsteht, wenn Du
versuchst in den SSPBUF zu schreiben, obwohl der noch nicht seine alten
Daten gesendet hat. Wenn das WCOL-Bit gesetzt wird, musst Du es IMMER
von Hand zurücksetzen, sonst geht KEINE weitere Übertragung mehr. Ist
das evtl. ein Problem in Deinem Code?
Gruß
TK
Das Kollisionsbit wird im Code nicht zurückgesetzt, da keine Kollision
auftreten sollte.
Mich beschäftigt ja die Tatsache, dass eine Kollision auftritt, obwohl
SSPIF geprüft wird, bevor neue Daten gesendet werden. Laut Datenblatt
wird SSPIF nur gesetzt, wenn die Datenübertragung vollständig ist.
Demnach dürfte keine Datenkollision zustande kommen, allerdings steht in
dem Microchip Datenblatt zur SPI Übertragung
(http://ww1.microchip.com/downloads/en/DeviceDoc/spi.pdf) dass nach dem
senden auch aus dem SSPBUF wieder gelesen werden muss, damit er geleert
wird und WCOL nicht gesetzt wird.
Im Datenblatt des LCD steht nicht geschrieben, das SCE(Chip Enable) nach
jedem Byte gesetzt werden muss, im Diagramm sieht man das auch nicht so,
unschlüssig bin ich beim D/C Bit, Data/Command, vielleicht könntest du
dir ja das Datenblatt mal ansehen und mir sagen, was du davon hälst,
wäre super, das Diagramm dass ich meine ist auf Seite 12 (Fig.11 Serial
bus protocol - transmission of several bytes.)
Im Anhang gleich mal das Datenblatt des Display Controllers, ist recht
kurz, aber es sind weitestgehend alle Informationen enthalten...die
Kontrasteinstellungen hätten meiner Meinung nach besser beschrieben sein
können, aber naja, der Kontrastwert hängt ja vom verwendeten Display ab,
da hätte der Hersteller des Displays Auskunft geben müssen, stattdessen
muss man sich mühselig herantasten...
Falls sich jemand dafür interessiert, hier habe ich das Display gekauft:
http://www.ebay.com/itm/ws/eBayISAPI.dll?ViewItem&item=220966025536&ssPageName=ADME:X:RTQ:US:1123
Hallo Yves,
OK, hab mal ein wenig im DB gelesen. Ich denke, der SPI-Mode 0,1 (CKP=0
und CKE=1) sollte hier der Richtige sein.
Um sicherzustellen, dass das LCD zwischen Daten und Kommandos
unterscheiden kann, würde ich dringend vorschlagen den CS-Pin nach jeder
Übertragung wieder auf H zu legen.
Nur so kannst Du sicherstellen, dass der D/C-Pin auch VOR bzw. WÄHREND
einer Übertragung den richtigen Pegel aufweist.
Ist der RES-Zyklus auch eingehalten? Also spätestens 30ms nach Anlegen
der
Versorgungsspannung am LCD auch den RES-Pin auf L gezogen (S21 im DB)?
Trotzdem - die Übertragung müsste dann so aussehen:
0) BF-Bit prüfen und evtl. warten, dann SSPBUF auslesen
1) D/C-Pin setzen
2) CS auf L
3) Wert in SSPBUF schreiben
4) WCOL-Bit abfragen und evtl. zurücksetzen und wieder zu 3)
5) CS auf H
LOOP zu 0)
Gruß
TK
Ok, aber wieso sollte D/C während/vor der Übertragung einen falschen
Pegel aufweisen? Der PIC ändert doch eigentlich nichts daran, wenn ich
das nicht so programmiert habe, oder täusche ich mich?
An die RST Vorgaben habe ich mich gehalten, das Display wird vom PIC
gespeist, da es nur 1-2mA benötigt(schrieb einer in einem Forum)
SCE wird nach jeder Übertragung (alle Bytes gesendet) auf High gesetzt.
Also nach der Übertragung aller Config Bytes und dann wieder nach der
Übertragung des darzustellenden Bildes.
Ich hab den kompletten Code mal hochgeladen. Er ist sicher...ziemlich
wirr, aber das sollte auch nur ein erster Test sein, ich wollte das
später nochmal ordentlich machen.
Die Routine bei LCDoff ist ein Test für ein Software PWM, ich wollte bei
gelegenheit mal ein Programm schreiben, mit dem man viele PWM Signale
mit einem PIC erzeugen kann, und wollte das gleich mal mit der
Hintergrundbeleuchtung des Displays testen. Das hat aber keine Relevanz,
das musst du dir nicht weiter ansehen.
Hallo Yves,
ja, der Code ist ziemlich lang. Und wenn ich das richtig sehe, dürfte
der
eigentlich gar nicht funktionieren. Das liegt aber an einer Routine, die
Du überhaupt nicht im Auge hattest. Und zwar in 'wait4rst' und
'wait4set'. Dort benutzt Du einen incf-Befehl und fragst das C-Flag ab.
Das wird aber durch den incf überhaupt nicht geändert. Der incf-Befehl
ändert nämlich nur das Z-Flag. Also es ist dann Zufall, dass die
Schleife wieder verlassen wird.
Wie erkennst Du die COLLED? Per Oszi, oder durch draufsehen?
Wenn Du nämlich ohne Oszi arbeitest, kannst Du die COLLED auch gar nicht
sehen - zumindestens in Teilen vom Code. Du solltest hier den Code
anpassen, indem Du einfügst:
btfsc SSPCON,7
bsf COLLED
btfss SSPCON,7
bcf COLLED
Damit bleibt die LED solange AN oder AUS, bis das nächste Übertragung
stattfindet.
Noch was: Wieso hast Du den 'org 0x04 / retfie' nicht mehr drin - klar
Du benutzt keine Interrupts mehr - ABER das ist eine Fehlerquelle, an
der man Tage lang sucht wenn es dumm läuft, wenn doch mal ein Interrupt
aktiviert wird. Dann springt das Programm wieder in die INIT (Also es
ist jetzt kein Fehler - aber ich programmiere immer ein Grundgerüst, bei
dem sowohl ORG 0, als auch ORG 4 IMMER vorhanden ist)
Wie ist das beim PIC16F877 mit einem CMCON-Register (Comparator Modul).
Ich glaube das steht beim Initialisieren auch auf Analog-In. (Das
bezieht sich zwar nur auf diverse PORT_A Pins - trotzdem mal auf digital
setzen).
Na, ja - soviel erst mal für jetzt.
Gruß
TK
Laut Datenblatt genügt es, im ADCON Register die Analogen Eingänge zu
deaktivieren, das soll auch die Komparatormodule deaktieren.
Ja die Collisions-LED, zunächst sollte sie einfach leuchten wenn eine
Kollision stattgefunden hat, ich hatte diese Änderung erst vorgenommen,
auf deinen Rat hin, ich hatte wohl nicht ganz verstanden wie du das
meintest.
Die Warteroutinen habe ich erst nach der neuen Abfrageart (per BF Bit)
eingebaut, seit ich aber das BF Bit Abfrage statt das SSPIF,
funktioniert das Programm garnicht mehr, das Display zeigt nichts an.
Hier nochmal der Code, ich hab die Abfragen verändert, müsste jetzt
hinhauen.
Ich hab grade gemerkt, dass ich, als ich den SPI Eingang im TRISC
Register als Eingang definieren wollte, ich versehentlich SCLK als
Eingang definiert habe, hab ich nun noch geändert, hat aber auch keinen
Unterschied gebracht.
Hallo Yves,
ich habe jetzt erst mal "nur noch" einen Fehler in 'config6' und
'config7' gesehen. Da sind die 'goto' falsch!
Was ich Dir noch zur Fehleranalyse empfehlen kann ist:
- da Du noch einige Pins frei hast, gibst Du einfach in jeder
Senderoutine ein bestimmtes Bitmuster auf diese freien Pins aus. Dort wo
der Controller dann hängenbleibt, kannst Du das Bitmuster (entweder über
angeschlossene LEDs oder per Multimeter) einmessen und so die
problembehaftete Programmstelle analysieren.
Gruß
TK
Ich hab's nun aufgeben und werde mich erstmal mit C beschäftigen, ich
schätze wenn man mit Tabellen arbeiten möchte, ist es das beste in C zu
programmieren -.-