Forum: Mikrocontroller und Digitale Elektronik [PIC]Probleme bei SPI Übertragung


von Yves E. (Gast)


Lesenswert?

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?)
5
  goto     SendT1            ; if not, check again
6
  BANKSEL  SSPBUF            ; BANK0
7
  movf     SSPBUF,W          ; Get Data from SSPBUF
8
  ;                          ; Throw it away
9
  movlw    HIGH  Logo1T1 
10
  movwf    PCLATH
11
  movf     bytecount,w
12
  call     Logo1T1
13
  movwf    SSPBUF
14
  incf     bytecount,f
15
  bcf      STATUS,Z
16
  movlw    D'252'
17
  subwf    bytecount,w
18
  btfss    STATUS,Z
19
20
  goto     SendT1
21
  clrf     bytecount

von TK (Gast)


Lesenswert?

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

von Yves E. (Gast)


Lesenswert?

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.

von TK (Gast)


Lesenswert?

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

von Yves E. (Gast)


Angehängte Dateien:

Lesenswert?

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

von TK (Gast)


Lesenswert?

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

von Yves E. (Gast)


Lesenswert?

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.

von TK (Gast)


Lesenswert?

So sollte es eigentlich funktionieren.
Das mit dem D/C-Pin habe ich deshalb erwähnt, da ich nicht weiss, wie 
Dein Code aussieht.

Gruß
TK

von Yves E. (Gast)



Lesenswert?

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.

von TK (Gast)


Lesenswert?

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

von Yves E. (Gast)



Lesenswert?

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.

von Yves E. (Gast)



Lesenswert?

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.

von TK (Gast)


Lesenswert?

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

von Yves E. (Gast)


Lesenswert?

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 -.-

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.