www.mikrocontroller.net

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


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
Autor: Markus Wi*** (kornbanane)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht 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.

void InitDisplay(void)
{
    int time;
    PDR08_P2=0;          // Port 08_2 (RS fürs Display) auf Low Schalten  


// **Routine nach 8 Bit Beispiel Datenblatt** //
  
  time=40;
  Delay_us(50000);      // Auf das Display warten

  SPI0SendData(0x39);      // Fuktion set: 8 Bit, 2 Zeilen
  
  Delay_us(time);        // ca 40µs warten
  
  SPI0SendData(0x1C);      // Bias set: BS:1/4, 2 Zeilen LCD

  Delay_us(time);        // ca 40µs warten
  
  SPI0SendData(0x52);      // Power Control : Booster aus

  Delay_us(time);        // ca 40µs warten
  

  SPI0SendData(0x69);      // Follower Controll
  
  Delay_us(time);        // ca 40µs warten
  
  SPI0SendData(0x74);      // Contrast set
  
  Delay_us(time);        // ca 40µs warten

  SPI0SendData(0x0F);      // Display on
  
  Delay_us(time);        // ca 40µs warten
  
  SPI0SendData(0x01);      // Clear Display
  
  Delay_us(1300);        // ca 1,3ms warten
  
  SPI0SendData(0x06);      // Entry Mode set
  
  Delay_us(time);        // ca 40µs warten
  
}




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 :(

Autor: dummy (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Ich hoffe der
>Gedanke ist bisschen rübergekommen.

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

Autor: Markus Wi*** (kornbanane)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht 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

Autor: Dennis H. (t1w2i3s4t5e6r)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Markus Wi*** schrieb:
> Die ist doch
> bei Controllerreset auch low

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


MfG Dennis

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Markus Wi*** (kornbanane)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Super endlich funktionierts !! Es hing also wirklich nur an diesem 
CSB...

VIELEN DANK für den Tipp ;)

Autor: Markus Wi*** (kornbanane)
Datum:

Bewertung
0 lesenswert
nicht 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.

/***************** LcdSendData ***********************

Sended ein Byte an das Display. Mode=0 -> Steuerdaten; Mode=1 -> Daten
WICHTIG: Bei jedem zu sendenden Byte muss der CSB Eingang des Displays auf Low und High geschaltet werden, damit sich
     die SPI Schnittstelle des Displays mit der des Controllers Synchronisiert

Parameter: Zu sendendes Byte; Mode 

Rückgabeparameter: Keine

****************************************************/ 
void LcdSendData(unsigned char *data, unsigned char mode)
{
  Delay_us(40);        // ca 40µs warten, um dem Display Zeit zu lassen
  PDR08_P0=0;          // CSB = Low -> Display empfängt ab jetzt Daten
  
  if(mode==0)          // Steuerdaten senden ? 
  {
    PDR08_P1=0;        // Port 08_1 auf Low Schalten (RS fürs Display)  
  }  
  else            // Daten senden
  {
    PDR08_P1=1;        // Port 08_1 auf High Schalten (RS fürs Display)  
  }
  
  SPI0SendData(data);      // Das Byte ans Display senden
  Delay_us(40);        // ca 40µs warten, um dem Display Zeit zu lassen
  PDR08_P0=1;          // CSB = High -> Display empfängt ab jetzt keine Daten mehr     
}



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:


/***************** LcdSendText ***********************

Sendet einen Text an das LCD Display 


Parameter: Zu sendender Text

Rückgabeparameter: Keine

****************************************************/ 
void LcdSendText(unsigned char *text[])
{
  unsigned char pos=0;
  
  while(text[pos]!='\0')      // Das Stringende ist noch nicht erreicht ??
  
  {
    LcdSendData(text[pos],1);  // Das jeweilige byte senden
    pos++;
  }
}



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

Autor: Nachtaktiver (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.
void LCD_SchreibeString( const char *ZeichenkettenPointer)
{
// Schreibe ein Zeichen auf dem Display solange der String
// nicht terminiert ist.
  while(*ZeichenkettenPointer)
                // Schreibe das neue Zeichen und Inkrementiere den Zeiger
    LCD_SendeDaten(*ZeichenkettenPointer++);
}

Autor: Markus Wi*** (kornbanane)
Datum:

Bewertung
0 lesenswert
nicht 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):

unsigned char wort[]="1";

LcdSendText(wort);




/***************** LcdSendText ***********************

Sendet einen Text an das LCD Display 

Parameter: Zu sendender Text

Rückgabeparameter: Keine

****************************************************/ 
void LcdSendText(const unsigned char *text)
{
  
  while(*text)      // Das Stringende ist noch nicht erreicht ??
  {
    LcdSendData(*text++,1);  // Das jeweilige byte senden
  }

}




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
LcdSendText('1');

kommt garkeine Ausgabe.

Bei

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

Autor: Axel (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hier ein Beispiel:

Beitrag "EA DOGM162 an SPI"

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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
>
> LcdSendText('1');
> 
>
> 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.

Autor: Markus Wi*** (kornbanane)
Datum:

Bewertung
0 lesenswert
nicht 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 ?

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel




Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.