Forum: Mikrocontroller und Digitale Elektronik Dog-M 162 SPI Initialisierung (wieder einmal)


von Markus W. (kornbanane)


Angehängte Dateien:

Lesenswert?

Hallo Leute,

die hälfte denkt jetzt bestimmt oh man schon wieder ein Topic mit dem 
Display ... ja ich weiß, hab auch lange rumgesucht bevor ich schreibe.

Mein Problem besteht zur Abwechslung mal nicht daraus, dass sich das 
Display mit meiner Routine nicht initialisieren lässt, sondern darin das 
es eben nur manchmal funktioniert (Timingproblem ?)

Also ich will ein DOG-M Display per SPI Schnittstelle ansteuern, die 
Schaltung ist wie im Datenblatt bzw. Bild 1. Das Display wird mit 5 V 
versorgt. Der /CSB Eingang ist dauerhaft auf Masse gelegt.

Meine Initialisierungsroutine folgt auch dem Datenblatt, siehe Bild 2, 
und sieht folgendermaßen aus.
1
void InitDisplay(void)
2
{
3
    int time;
4
    PDR08_P2=0;          // Port 08_2 (RS fürs Display) auf Low Schalten  
5
6
7
// **Routine nach 8 Bit Beispiel Datenblatt** //
8
  
9
  time=40;
10
  Delay_us(50000);      // Auf das Display warten
11
12
  SPI0SendData(0x39);      // Fuktion set: 8 Bit, 2 Zeilen
13
  
14
  Delay_us(time);        // ca 40µs warten
15
  
16
  SPI0SendData(0x1C);      // Bias set: BS:1/4, 2 Zeilen LCD
17
18
  Delay_us(time);        // ca 40µs warten
19
  
20
  SPI0SendData(0x52);      // Power Control : Booster aus
21
22
  Delay_us(time);        // ca 40µs warten
23
  
24
25
  SPI0SendData(0x69);      // Follower Controll
26
  
27
  Delay_us(time);        // ca 40µs warten
28
  
29
  SPI0SendData(0x74);      // Contrast set
30
  
31
  Delay_us(time);        // ca 40µs warten
32
33
  SPI0SendData(0x0F);      // Display on
34
  
35
  Delay_us(time);        // ca 40µs warten
36
  
37
  SPI0SendData(0x01);      // Clear Display
38
  
39
  Delay_us(1300);        // ca 1,3ms warten
40
  
41
  SPI0SendData(0x06);      // Entry Mode set
42
  
43
  Delay_us(time);        // ca 40µs warten
44
  
45
}


Die Spi Schnittstelle arbeitet sehr langsam - 488 Bit/s, von daher 
sollte es ja absolut unkritisch sein. Das MSB wird zuerst gesendet und 
die Daten werden so gesendet, das sie auf der positiven Taktflanke 
übernommen werden.

Ich hab mir den "Datenstrom" am Oszi angeschaut, sieht alles super aus.

Jetzt ist es so das die ganze Sache halbwegs funktioniert. Soll heißen, 
wenn ich das Display 10 mal initialisiere...

Habe ich: 3x Erfolg -> alles ok, Cursor oben links blinkt
          2x Mist -> Display initialisiert, aber Cursor blinkt irgendwo 
anders
2x wieder Mist -> kein Cursor, aber die "Kästchen" sind zumindest schon 
mal leicht grau
3x garkeine Veränderung im Vergleich zum uninitialisiertem Zustand.

Deshalb denke ich das es ein Timingproblem ist... Wie gesagt die Daten 
und der Clock kommen sauber am Display an. CSB Leitung liegt auf Low, RS 
liegt auch auf low. Ich ahbe schon mit den Zeiten herumgespielt (Die 
Variable time bei mir und die 1,3 ms vor dem Entry Mode set). Habe auch 
die SPI Schnittstelle mal schneller gemacht. All das hatte überhaupt 
keine Auswirkung.

Mir ist jetzt eine Idee gekommen, aber ich glaube ich bin da voll auf 
dem Holzweg ? Und zwar, wenn ich den Controller (Jujitzu MB96338) 
resette dauert es ja ne Zeit lang, bis das SPI Modul initialisiert ist. 
Der SPI CLK Pin hat also kurz ein Low Pegel und dann ein High Pegel 
(Ruhezustand des SPI Busses). Kann es sein, das aufgrund diesen 
Pegelwechsels das Display jetzt denkt, das zu dem Zeitpunkt ein Bit über 
den SPI Bus anliegt ?? Dann Speichert es das Bit als MSB des aktuellen 
Bytes ab. Ich schicke jetzt meine 8 Bit echten Daten rüber und nach 7 
Bits dieser 8 Bits sagt das Display: ok ich hab ein Byte empfangen, 
weiter gehts mit dem nächsten. Und somit ist das LSB meiner Nutzdaten 
das MSB des nächsten Bytes, was das Display einließt. Ich hoffe der 
Gedanke ist bisschen rübergekommen.
Allerdings kann ich mir nicht vorstellen das dies so eine Problematik 
ist, da es sich ja bei jedem Controller so verhält und immer wenn ein 
System eingeschaltet wird habe ich ja diesen Effekt.

Ich warte auch Übrigens einen Moment nachdem der Controller (und des 
Display) an Versorgungsspannung hängen, befor ich die Daten übertrage. 
Wenn ich in der Initialisierungsroutine bin werden immer noch 50ms 
gewartet befor's losgeht.

Also ich hab jedenfalls keine Ahnung was es sein kann wie gesagt:

- Signale ok
- Es werden die richtigen Daten übertragen
- Es wird zwischen den Bytes gewartet
- Längere Wartezeiten bringen keine Besserungen

Bin mit meinen Ideen am Ende :(

von dummy (Gast)


Lesenswert?

>Ich hoffe der
>Gedanke ist bisschen rübergekommen.

Und der ist richtig. Benutze die CS Leitung.
Damit kannst du dich wieder synchronisieren.

von Markus W. (kornbanane)


Angehängte Dateien:

Lesenswert?

hmm das würde einiges erklähren. Heißt also die CSB Leitung auf High 
Schalten und erst wenn die Kommunikation anfängt auf low Schalten ? Dann 
hab ich doch aber das selbe Problem mit dieser Leitung ? Die ist doch 
bei Controllerreset auch low und dann setzt der µC sie erst auf High. 
Somit empfängt das Display doch auch schon ein Bit was es nicht soll ?

Hab nochmal paar Bilder vom Display drangehängt, also von den 
verschiedenen Zuständen.

IMAG0521: Display im nicht initialisierten Zustand bzw. wenn sich garnix 
getan hat.

IMAG0522: RICHTIG INITIALISIERT :)

IMAG0523: Cursor an der falschen Position bzw. blinkt oben und unten

IMAG0524 und IMAG0525: falsch initialisiert, aber es hat sich zumindest 
was getan

von Dennis H. (t1w2i3s4t5e6r)


Lesenswert?

Markus Wi*** schrieb:
> Die ist doch
> bei Controllerreset auch low

Für so etwas gibt es einen Pull Up Widerstand.


MfG Dennis

von Peter D. (peda)


Lesenswert?

Markus Wi*** schrieb:
> Somit empfängt das Display doch auch schon ein Bit was es nicht soll ?

Natürlich muß CSB nach jedem Byte wieder auf high gesetzt werden. Damit 
synchronisiert sich das SPI des LCD bei jedem Byte neu.

von Markus W. (kornbanane)


Lesenswert?

Super endlich funktionierts !! Es hing also wirklich nur an diesem 
CSB...

VIELEN DANK für den Tipp ;)

von Markus W. (kornbanane)


Lesenswert?

Ich brauche doch nochmal eure Hilfe.

Hab mir eine Routine geschrieben, die mir ein beliebiges Byte auf das 
Display schicken kann und dabei unterscheidet, ob es sich um ein 
Steuerbyte oder Datenbyte handelt.
1
/***************** LcdSendData ***********************
2
3
Sended ein Byte an das Display. Mode=0 -> Steuerdaten; Mode=1 -> Daten
4
WICHTIG: Bei jedem zu sendenden Byte muss der CSB Eingang des Displays auf Low und High geschaltet werden, damit sich
5
     die SPI Schnittstelle des Displays mit der des Controllers Synchronisiert
6
7
Parameter: Zu sendendes Byte; Mode 
8
9
Rückgabeparameter: Keine
10
11
****************************************************/ 
12
void LcdSendData(unsigned char *data, unsigned char mode)
13
{
14
  Delay_us(40);        // ca 40µs warten, um dem Display Zeit zu lassen
15
  PDR08_P0=0;          // CSB = Low -> Display empfängt ab jetzt Daten
16
  
17
  if(mode==0)          // Steuerdaten senden ? 
18
  {
19
    PDR08_P1=0;        // Port 08_1 auf Low Schalten (RS fürs Display)  
20
  }  
21
  else            // Daten senden
22
  {
23
    PDR08_P1=1;        // Port 08_1 auf High Schalten (RS fürs Display)  
24
  }
25
  
26
  SPI0SendData(data);      // Das Byte ans Display senden
27
  Delay_us(40);        // ca 40µs warten, um dem Display Zeit zu lassen
28
  PDR08_P0=1;          // CSB = High -> Display empfängt ab jetzt keine Daten mehr     
29
}


Funktioniert auch soweit alles. Jetzt wollte ich eine zweite Routine 
schreiben, die auf vorherigen aufbaut und mir ermöglicht Zeichenketten 
zu schicken. Ich will also diese Möglichkeit haben:

LcdSendText("Hallo");

Hier die Routine:
1
/***************** LcdSendText ***********************
2
3
Sendet einen Text an das LCD Display 
4
5
6
Parameter: Zu sendender Text
7
8
Rückgabeparameter: Keine
9
10
****************************************************/ 
11
void LcdSendText(unsigned char *text[])
12
{
13
  unsigned char pos=0;
14
  
15
  while(text[pos]!='\0')      // Das Stringende ist noch nicht erreicht ??
16
  
17
  {
18
    LcdSendData(text[pos],1);  // Das jeweilige byte senden
19
    pos++;
20
  }
21
}


Irgendwas stimmt jetzt mit der Übergabe der Zeichenkette nicht, wenn die 
Funktion über

LcdSendText("Hallo");

aufgerufen wird. Ich komme erst garnicht in die While Schleife rein. 
Wenn ich die While schleife durch while(pos<5) ersetze, sehe ich auch 
das was mit dem Array Text nicht stimmt, denn dann springt der Cursor 
des Displays zwar 5 Spalten weiter nach rechts, aber die vorherigen 
Spalten zeigen keinen Inhalt.....

Da ich kein Debugger habe, kann ich leider nicht nachsehen, was sich in 
dem Array text befindet.

Andere Leute hier im Forum haben solche Sachen auch mit einem 
dynamischen Pointerarray (nennt man es so?) gelöst. Ich dachte auch das 
man es so machen kann ??

Vieleicht liegt es am Compiler ? nach dem Motto C ist nich gleich C...

Ich benutze den Softune Workbench Compiler für Fujitzu µC

Danke schon mal

von Nachtaktiver (Gast)


Lesenswert?

Mir gefallen deine Bitoperationen für die Steuerung der Ausgangspins 
nicht.
Warum benutzt du nicht die klassischen Bit Operationen?

Zum Pin setzen:
PORTX |= (1<<PIN_X)

Zum Pin löschen:
PORTX &= ~(1<<PIN_X)

Das was du da tust (Makros?) sieht sehr kryptisch aus bringt nur 
schwierigkeiten beim Verstehen des Quellcodes und sorgt für zusätzliche 
Fehlerquellen.

Wenn du einen String an einer Routine übergeben möchtest dann reicht es 
aus, das du dieser Routine einen Pointer übergibst welcher auf das erste 
Zeichen dieser Kette zeigt.

In der Routine welche die Zeichen an das Display schickt, reicht es dann 
wenn du den Pointer pro Ausgabe inkrementell erhöhst und überprüfst ob 
der Speicherinhalt an diesen Ort ungleich Null ist.

Wenn die Routine dann auf diese Null trifft wurde das 
Terminierungszeichen der Zeichenkette gefunden und die Routine wird 
wieder verlassen.
1
void LCD_SchreibeString( const char *ZeichenkettenPointer)
2
{
3
// Schreibe ein Zeichen auf dem Display solange der String
4
// nicht terminiert ist.
5
  while(*ZeichenkettenPointer)
6
                // Schreibe das neue Zeichen und Inkrementiere den Zeiger
7
    LCD_SendeDaten(*ZeichenkettenPointer++);
8
}

von Markus W. (kornbanane)


Lesenswert?

So war das We nich da, hab jetzt nochma rumprobiert.

Also das die Ansteuerungen der Ports so aussehen liegt halt am 
Controller. Ist halt kein AVR, deshalb auch kein PORTX |= (1<<PIN_X) 
usw...

Die Lösung die du Vorgeschlagen hast hatte ich auch schon, allerdings 
ohne Erfolg. Meine Lösung macht im Grunde doch nix anderes oder ? Mit 
dem Unterschied das deine eleganter ist.

Hier jetzt die "neue" Version (LcdSendData ist gleich geblieben):
1
unsigned char wort[]="1";
2
3
LcdSendText(wort);
4
5
6
7
8
/***************** LcdSendText ***********************
9
10
Sendet einen Text an das LCD Display 
11
12
Parameter: Zu sendender Text
13
14
Rückgabeparameter: Keine
15
16
****************************************************/ 
17
void LcdSendText(const unsigned char *text)
18
{
19
  
20
  while(*text)      // Das Stringende ist noch nicht erreicht ??
21
  {
22
    LcdSendData(*text++,1);  // Das jeweilige byte senden
23
  }
24
25
}


Ich sollte jetzt also am Display sehen: 1

Was ich sehe: xxxxx, wobei x für irgendein sinnloses Zeichen steht.
Diese Reihe sinnloser Zeichen ist aber bei jedem Aufruf durch 
LcdSendText(wort); dieselbe  !!
Sieht also so aus als würde er bei irgendeiner anderen Adresse als die 
von dem char wort anfangen ?

Bei einem aufruf mit
1
LcdSendText('1');

kommt garkeine Ausgabe.

Bei
1
LcdSendText("1");

Kommen viele sinnlose Zeichen (auch immer dieselbe Zeichenreihe bei 
jedem Aufruf). Das Display läuft ein paar mal komplett durch und bleibt 
dann stehen (also eine Menge Zeichen).

Wenn ich jetzt nicht nur den Text "1" sondern "Hallo" oder so ausgebe, 
habe ich natürlich dieselben Effekte.

Sieht also doch so aus, als würde der Pointer *text meiner Routine 
LcdSendText nicht auf den Anfang der Zeichenkette zeigen, sondern 
irgendwo anders hin ??

Die Frage ist, ob ich da ohne Debugger überhaupt noch klar kommen kann ?


Gruß Markus

von Axel (Gast)


Lesenswert?

Hier ein Beispiel:

Beitrag "EA DOGM162 an SPI"

von Karl H. (kbuchegg)


Lesenswert?

Markus Wi*** schrieb:

> Was ich sehe: xxxxx, wobei x für irgendein sinnloses Zeichen steht.
> Diese Reihe sinnloser Zeichen ist aber bei jedem Aufruf durch
> LcdSendText(wort); dieselbe  !!

Welcher Prozessor, welcher COmpiler?

Es gibt Compiler, die auf manchem Prozessoren (PIC und IAR fällt mir da 
als erstes ein) aus dem "const" einen impliziten Flash-Zugriff machen, 
der µC-intern anders abgehandelt wird, als ein Zugriff aufs SRAM. Da 
muss man also peinlich genau unterscheiden, was man eigentlich zur 
Verfügung hat.
D.h. dein Problem hat möglicherweise jetzt überhaupt nichts mit dem LCD 
an sich zu tun, sondern damit, wie dein Compiler Strings bzw. konstante 
Strings in der Schreibweise unterscheidet bzw. behandelt.

> Sieht also so aus als würde er bei irgendeiner anderen Adresse als die
> von dem char wort anfangen ?


> Bei einem aufruf mit
>
1
> LcdSendText('1');
2
>
>
> kommt garkeine Ausgabe.

logisch. Das ist schon mal grundfalsch, weil '1' überhaupt kein String 
ist und somit schon mal grundsätzlich komplett anders behandelt wird 
bzw. behandelt werden muss.

von Markus W. (kornbanane)


Lesenswert?

Ja das mit '1' war mit auch klar irgendwie ;)


Also es ist ein Fujitzu MB96F338 Controller.
Als Compiler wird die Softune Workbench V30 verwendet.
Ja ich denke auch das es am Controller liegt. Am Display sicher nicht, 
denn dieses funktioniert ja schließlich.

Die Frage ist jetzt wie ich dahinterkomme ?

von Karl H. (kbuchegg)


Lesenswert?

Markus Wi*** schrieb:

> Die Frage ist jetzt wie ich dahinterkomme ?

Tja.
Compilerdoku.
mitgelieferte Beispiele studieren, ob was auffälliges zu sehen ist.
Anderen COde für diesen COmpiler/µC studieren.

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.