Forum: Mikrocontroller und Digitale Elektronik TFT_ILI9163C mit Arduino richtig verbinden


von Max M. (maxmicr)


Angehängte Dateien:

Lesenswert?

Hallo,

ich hab auf Github eine Anleitung gefunden, wie man das ILI9163C LCD 
Display mit einem µC verbinden kann:

https://github.com/sumotoy/TFT_ILI9163C (unter "Wiring").

Im Datenblatt des ATMega328P ist diese Pinbelegung gezeigt.

Damit ich jetzt nichts falsch mache:

VCC und GND sind klar, aber was ist ein CS-Pin und wo finde ich den bei 
diesem µC?

Bei dem RST-Pin steht:
1
connect to a MCU pin or tie to +3V3 or 10K to 3V3 (do NOT leave float!)

also kann ich den theoretisch an irgend einen Pin anschließen?

Bei A0 steht:
1
DC or RS pin (3v3 level!)

Also wäre da z.B. der Pin PC0 möglich?

SCK müsste dann demnach an Pin PB5 angeschlossen werden?


Könnt ihr da etwas Licht ins Dunkel bringen?

: Bearbeitet durch User
von Dennis X. (Gast)


Lesenswert?

CS ist ein ChipSelect Pin und dieser kann an jeden beliebigen Pin vom 
Microcontroller. Wenn du eine SPI Schnittstelle des µC benutzt, kannst 
du CS auch auf den SS Pin dieser Schnittstelle legen. Der wird dann 
direkt von der Hardware aus gesteuert und du brauchst den nicht mehr aus 
deiner Software anzusteuern.

Max M. schrieb:
> Bei dem RST-Pin steht:
> connect to a MCU pin or tie to +3V3 or 10K to 3V3 (do NOT leave float!)
>
> also kann ich den theoretisch an irgend einen Pin anschließen?
JA

> Bei A0 steht:
> DC or RS pin (3v3 level!)
>
> Also wäre da z.B. der Pin PC0 möglich?

und JA

Grüße

von Max M. (maxmicr)


Angehängte Dateien:

Lesenswert?

Danke für deine Antwort, das hilft mir schon einmal sehr weiter.

Bleibt nur die Frage, wie ich aus der Pinbeschriftung die richtigen aus 
dem Datenblatt rausbekomme?

von Max M. (maxmicr)


Lesenswert?

Hallo,

ich melde mich mal wieder da ich gerade wieder versucht habe, das 
Display zum laufen zu kriegen.
Die Verbindungen sehen wie folgt aus:

LCD / Board
SCK / PB5 [SCK]
SDA / PB3 [MOSI]
A0 / PC0
RST / 3.3V (PD2)
CS / PB2 [SS]
Vcc / 3.3V

RST hab ich an PD2 da mein Arduino nur einen 3.3V Ausgang hat. Programm 
sieht wie folgt aus:
1
void SPI_init(){
2
  SPCR = (1<<SPE); //init SPI
3
  SPCR = (1<<CPOL) | (1<<CPHA) | (1<<SPR0); //Clock Polarity, Clock Phase, SCK = F_CPU/16, 
4
  SPCR = (1<<MSTR); //enable Master
5
6
  DDRB = (1<<DDB3) | (1<<DDB5) | (1<<DDB2); //MOSI, SCK, SS as Output
7
  //DDRC = (1<<DDB0);
8
9
  DDRD = (1<<DDB2); //turn Vcc as Output
10
}
11
12
char SPI_transmit(char s){
13
  SPDR = s; //start transmit
14
  while((!SPSR & (1<<SPIF))) //transmit is done if SPIF is not one
15
  ;
16
  return SPDR;
17
}

In dem Datenblatt zum Display:

http://www.orientdisplay.com/pdf/ILI9163C.pdf

finde ich zwar die ganzen Konfigurationsmöglichkeiten (S.83), aber 
welche ich tatsächlich brauche, um das Display zu starten, steht da 
nicht :(

Es gibt eine bereits fertige Bibliothek auf Github:

https://github.com/sumotoy/TFT_ILI9163C

Dort werden auch verschiedene Sachen konfiguriert, jedoch denke ich, 
dass es mehr sind als zum Starten nötig sind (über 50: 
https://github.com/sumotoy/TFT_ILI9163C/blob/master/TFT_ILI9163C.cpp).

In meiner init_LCD Funktion schalte ich dann noch den entsprechenden Pin 
für A0 an (neben einigen Konfigurationen):
1
void init_LCD(){
2
  SPI_init();
3
  _delay_ms(10);
4
  PORTD = (1<<DDB2); //turn Vcc on
5
6
  SPI_transmit(0x01); // Software reset
7
  _delay_ms(500);
8
9
  SPI_transmit(0x11); //Sleep Off
10
  _delay_ms(50);
11
12
  SPI_transmit(0x29); //Display On
13
  _delay_ms(50);
14
}

Kann mir da jemand weiterhelfen? Stimmen meine SPI-Funktionen soweit?

: Bearbeitet durch User
von grundschüler (Gast)


Angehängte Dateien:

Lesenswert?

rst/tft verbindest du am besten mit rst/board.

  DDRD = (1<<DDB2); //turn Vcc as Output passt nicht zu deinem CS (DDRB)


zum testen von spi bietet sich bitbanging an. Ich habe die drei 
Möglichkeiten, spi mit dem avr zu generieren - bitbang/usart/hw_spi - in 
eine low_level-Datei herausgezogen. Kannst du dir ja mal anschauen.

von grundschüler (Gast)


Lesenswert?

Max M. schrieb:
> DDRD = (1<<DDB2);

DDRB |= (1<<DDB2);

von Max M. (maxmicr)


Lesenswert?

Danke für eure Antworten,

grundschüler schrieb:
> passt nicht zu deinem CS (DDRB)

Ich schalte damit auch den Pin PD2 an, der an Reset hängt. Laut der 
Beschreibung auf Github muss der auf 3.3V, da der Arduino aber nur einen 
3.3V Pin hat (der bereits für Vcc benutzt wird) hab ich einfach 
irgendeinen Pin genommen und den als Ausgang geschaltet.

CS wird zusammen mit MOSI und SCK als Ausgang geschaltet.

grundschüler schrieb:
> DDRB |= (1<<DDB2);

Danke, sollte aber nicht zu einem Problem führen, wenn das der einzige 
Pin aus den PORTDs ist, den ich benutze?

Euren Antworten zufolge scheint jetzt erstmal nichts grundlegend 
falsches an meinem Code zu sein?

: Bearbeitet durch User
von grundschüler (Gast)


Lesenswert?

Max M. schrieb:
> Danke, sollte aber nicht zu einem Problem führen,

noch nicht. Programmieren ist Genauigkeit. Wenn du DDRD schalten willst, 
solltest du die dafür allgemeingültige Funktion und die Pin-Definition 
für das jewilige Register verwenden.
 DDRD |= (1<<DDD2);
auch wenn DDB2 und DDD2 identisch ist.

 Es fehlt dann noch

 PORTD |= (1<<DDD2);

damit der PIN auf high geht.

von Michael U. (amiga)


Lesenswert?

Hallo,

warum testet Du Deine Anschlußgeschichte nicht erstmal aus der 
Arduinoumgebung mit der fertigen Lib?.

Und ja, Du wirst von den 50 Sachen die meisten brauhcen, der Controller 
will schließlich richtig initialisiert werden.
Hast Du Dir das Datenblatt des ILI9163C schonmal in Ruhe angeschaut?
Hast Du Dir den Schaltplan des Breakout-Board des Displays angeschaut?

Ich bin mit Sicherheit für "alles selber machen". Einen LCD-Controller 
mal initialisieren und ansprechen dauert auch mit Übung einige Zeit.

Gruß aus Berlin
Michael

von Max M. (maxmicr)


Lesenswert?

Michael U. schrieb:
> Hast Du Dir das Datenblatt des ILI9163C schonmal in Ruhe angeschaut?

Ja, aber ehrlich gesagt finde ich mich da nicht zurecht. Noch dazu 
werden ja verschiedene Displays, teilweise mit mehreren 100 Pins 
beschrieben, da kenn ich mich nicht mehr aus. Noch dazu heißen die Pins 
komplett anders als bei meinem Display (siehe Pin Description).

Michael U. schrieb:
> Hast Du Dir den Schaltplan des Breakout-Board des Displays angeschaut?

Wo finde ich den?

Michael U. schrieb:
> Einen LCD-Controller
> mal initialisieren und ansprechen dauert auch mit Übung einige Zeit.

Okay!?

Michael U. schrieb:
> warum testet Du Deine Anschlußgeschichte nicht erstmal aus der
> Arduinoumgebung mit der fertigen Lib?.

Michael U. schrieb:
> Ich bin mit Sicherheit für "alles selber machen".

von Max M. (maxmicr)


Lesenswert?

Anscheinend gibt es irgendwie ein Problem mit meiner while-schleife:
1
void SPI_transmit(char s){
2
  SPDR = s; //start transmit
3
  while(!(SPSR & (1<<SPIF))) //transmit is done if SPIF is not one
4
  ;
5
}

In meiner Main schalte ich einen Pin an und aus, an der eine LED hängt. 
Sie geht jedoch nur einmal an und nicht wieder aus, was darauf 
hindeutet, dass das Programm in der while-Schleife hängen bleibt. 
Anscheinend ist die Übertragung nie abgeschlossen?
1
int main (void)
2
{
3
  DDRB |= (1<<DDB4);
4
  while(1){
5
    PORTB |= (1<<DDB4);
6
    _delay_ms(250);
7
    SPI_transmit("c");
8
    PORTB &= ~(1<<DDB4);
9
    _delay_ms(250);
10
  }
11
  return 0;
12
}

Hat jemand eine Idee, was ich falsch mache?

von grundschüler (Gast)


Lesenswert?

Max M. schrieb:
> SPI_transmit("c");

Das ist ein String. Probier mal 'c'.

von Max M. (maxmicr)


Lesenswert?

Leider immer noch nicht :(

Was genau überprüft Flag? Kann der µC wirklich sagen, wann der Transfer 
abgeschlossen ist? Ich kann jetzt z.B. nicht sagen ob der LCD-Controller 
wirklich was zurück gibt, weil ich ihn noch nicht korrekt initialisiert 
habe.

von Michael U. (amiga)


Lesenswert?

Hallo,

Max M. schrieb:
> Michael U. schrieb:
>> Hast Du Dir das Datenblatt des ILI9163C schonmal in Ruhe angeschaut?
>
> Ja, aber ehrlich gesagt finde ich mich da nicht zurecht. Noch dazu
> werden ja verschiedene Displays, teilweise mit mehreren 100 Pins
> beschrieben, da kenn ich mich nicht mehr aus. Noch dazu heißen die Pins
> komplett anders als bei meinem Display (siehe Pin Description).

Dein Breakout-Board besteht aus einem LC-Display, dem daran befindlichen 
Controller und der Leiterplatte mit der Anpassung als "Arduiono"-Modul.
Der Controlelr kann verschieden LC-Display ansteuern, die meisten seiner 
Pins hängen am LC-Display. Der Controller will gesagt bekommen, was für 
ein Display mit welcher Ausflösung dranhängt, wie das angesteuert werden 
will, wie die Backplanes bedient werden wollen usw. usw. usw.
Das ist das, wann in den vielen Init-Bytes übertragen wird. Wenn da was 
nicht stimmt, passiert optisch oft garnichts oder irgendwelcher Unfug.

Du mußt also die Init-Sequenz ohnehin übernehmen, weil Du die nötigen 
Einstellungen sonst garnicht zusammenbekommt. Dir fehlen z.B. die 
Angaben zum eigentlichen Display.
Dazu kommt, daß die Controller zum µC meist mehrere Schnittstellen 
anbieten (Parallel 8Bit, 16Bit, I2, SPI) und über Pins von Cotroller 
festgelegt wird, welche Schnittstelle benutzt werden soll.
Auch datauf hast Du keinen Einfliß, das haben die Hersteller der 
Anpaßleiterplatte festgelegt.

Die Frage, warum Du nicht zuerst mit der ArduinoIDE und dem Demo-Code 
testet, ob prinzipiell ailes past, hast Du ja nicht beantwortet.

Ist das ein 1,8" von Adafruit oder ein China-Nachbau?
Mein 1,8" China-Modul hat z.B. einen ST7735 Controller drauf.

Gruß aus Berlin
Michael

von Max M. (maxmicr)


Lesenswert?

Danke für deine ausführliche Antwort!

Michael U. schrieb:
> Ist das ein 1,8" von Adafruit oder ein China-Nachbau?

Ich denke mal ein China Nachbau wobei da kein Unterschied mit den 
Adafruit Displays besteht (die auch aus China kommen und zum 3-fachen 
Preis verkauft werden).

Michael U. schrieb:
> Du mußt also die Init-Sequenz ohnehin übernehmen, weil Du die nötigen
> Einstellungen sonst garnicht zusammenbekommt. Dir fehlen z.B. die
> Angaben zum eigentlichen Display.

Ja aber das Datenblatt muss mir als Entwickler doch sagen, wie ich das 
Display mit dem Controller zum laufen bekomme? Der Entwickler der Lib 
auf Github hat das anscheinend auch irgendwie rausbekommen:

["I got one of those displays from a chinese ebay seller but 
unfortunatly I cannot get any working library so I decided to work on 
it. ILI9163C looks pretty similar to other display driver but it uses 
it's own commands so it's tricky to work with it unlsess you carefully 
fight with his gigantic and confused datasheet."]

Michael U. schrieb:
> Dein Breakout-Board besteht aus einem LC-Display, dem daran befindlichen
> Controller und der Leiterplatte mit der Anpassung als "Arduiono"-Modul.

Inwiefern ist das Modul als Arduino-Modul angepasst? Auf dem 
Breakout-Board erkenne ich nicht viel mehr als ein Widerstand vor der 
Display-LED, ein Spannungsregulator und einen Kondensator.

Michael U. schrieb:
> Die Frage, warum Du nicht zuerst mit der ArduinoIDE und dem Demo-Code
> testet, ob prinzipiell ailes past, hast Du ja nicht beantwortet.

Okay. Das Problem ist, dass ich dann wieder tausend Sachen installieren 
muss (z.B. Adafruit GFX und Teensy(?). Klar, ich stocher solange im 
Dunkeln. Aber anscheinend hängt schon bei meiner SPI-Funktion irgendwas, 
nachdem die LED nicht blinkt und das Programm in der While-Schleife 
stoppt.

: Bearbeitet durch User
von Michael U. (amiga)


Lesenswert?

Hallo,

die Arduino-IDE kannst Du portable installieren, dann macht sie nichts 
an Deinem Rechner. Als ZIP-Archiv runterladen, irgendwohin entpacken.
Im Arduino-Ordner einen Ordner portable anlegen und dann erst die IDE 
starten.

Dann landet alles (Sketchbook, Erweiterungen usw. in diesem Ordner.
Kannst Du auch einfach auf einem USB-Stick irgendwo mitnehmen und 
starten.

Du kannst z.B. auch Dein  C-Programm einfach in die die IDE kopieren, 
leeren Sketch aufmachen, setup() und loop() löschen und Deins 
reinkopieren.

Wenn es dort eine main() gibt, wird es normal compiliert (ist ja auch 
nur ein GCC dahinter) und läßt sich direkt aus der IDE flashen, wenn der 
ATMega den Arduino-Bootloader noch hat.

Ich nutze das inzwischen kreuz und quer, wie gerade passt. Zur Zeit 
meist für den ESP8266...

PS: die version 1.6.7 scheint stabil zu sein. ansonsten die 1.6.5 
nehmen, nicht die 1.6.6.

Gruß aus Berlin
Michael

: Bearbeitet durch User
von Max M. (maxmicr)


Lesenswert?

Okay, ich hab mal das "Basic Setup" Beispielprojekt hochgeladen und es 
tut sich leider absolut nichts auf dem Display :(

von grundschüler (Gast)


Lesenswert?

Max M. schrieb:
> Hat jemand eine Idee, was ich falsch mache?

ich habe deinen spi code


 DDRD |= (1<<DDB0);
  while(1){
    PORTD |= (1<<DDB0);
    _delay_ms(250);
    SPI_transmit('c');
    PORTD &= ~(1<<DDB0);
    _delay_ms(250);
  }

mal auf mein m328-bord geladen. Die spi-pins sind nicht angeschlossen. 
Es blinkt.

von Max M. (maxmicr)


Lesenswert?

Heist das, dass mein Board kaputt ist? Ich mein, es blinkt ja auch wenn 
ich das "SPI_transmit('c')" rausmache.

von grundschüler (Gast)


Lesenswert?

keine Ahnung. toggle mal PortB, ob die pins ohne spi gehen. Wenn ja, 
kannst du es mit bitbanging-spi probieren.

von Max M. (maxmicr)


Lesenswert?

PB5 und PB4 lassen sich toggeln.

grundschüler schrieb:
> Wenn ja,
> kannst du es mit bitbanging-spi probieren.

Okay

von grundschüler (Gast)


Lesenswert?

Max M. schrieb:
> In meiner Main schalte ich einen Pin an und aus, an der eine LED hängt.
> DDRB |= (1<<DDB4);

Das ist schlecht. Das ist doch der Miso-Pin. Ich meine, der muss Eingang 
sein.

von Michael U. (amiga)


Lesenswert?

Hallo,

Max M. schrieb:
> Okay, ich hab mal das "Basic Setup" Beispielprojekt hochgeladen und es
> tut sich leider absolut nichts auf dem Display :(

hast Du auch wirklich das Display aus dem GitHub-Link?
Hast Du mal ei Foto der Rückseite?
Wie ist die Leiste denn beschriftet?
Ich frage nur deshalb, weil mein China-Display auf den ersten Blick auch 
identisch aussah und trotzdem einen anderen Controller hatte.

Du kannst Dir ja mal die Pixelmaster-Lib runterladen:
http://pd4ml.com/pixelmeister/pixels.htm
Link ist unten auf der Seite. Die kann auch den IL9163.
Die läuft auch mit meinem China-Teil mit dem ST7735.
Nur den include dann eben anpassen.

Vielelicht bekommst Du dann erstmal überhaupt was zu sehen.
Anschlußbelegung steht im Sketch.
Ich habe meins gerade nochmal an einen Nano gesteckt, meldet sich noch. 
;-)

Gruß aus Berlin
Michael

: Bearbeitet durch User
von Max M. (maxmicr)


Lesenswert?

Guten Morgen,

grundschüler schrieb:
> Das ist schlecht. Das ist doch der Miso-Pin. Ich meine, der muss Eingang
> sein.

In der Verschaltung aus der GitHub Lib wird der MISO-Pin gar nicht 
benutzt. Wahrscheinlich, weil man nicht unbedingt (zumindest erstmal 
nicht) etwas vom Controller des LCDs abfragen will.

Oder muss man den trotzdem im Programm als Eingang definieren?

Michael U. schrieb:
> Du kannst Dir ja mal die Pixelmaster-Lib runterladen:

Werde ich mal probieren, danke!

Michael U. schrieb:
> Ich frage nur deshalb, weil mein China-Display auf den ersten Blick auch
> identisch aussah und trotzdem einen anderen Controller hatte.

Zumindest stand dieser Controller-Name damals als Produktbeschreibung 
mit dabei. Von außen sehe ich den Controller nicht, Bild werde ich 
nachreichen.

Grüe

von Michael U. (amiga)


Lesenswert?

Hallo,

Max M. schrieb:
> In der Verschaltung aus der GitHub Lib wird der MISO-Pin gar nicht
> benutzt. Wahrscheinlich, weil man nicht unbedingt (zumindest erstmal
> nicht) etwas vom Controller des LCDs abfragen will.

ist bei meinem Display garnicht rausgeführt.
Nur C/D (mit A0 beschriftet...), MOSI (mit SDA beschriftet...), SCK, CS 
und Reset.
Die Beschriftung ist also ohnehin von einer I2C-Version und damit 
eigentlich falsch...

PS: gerade Deinen Text ganz oben zu "A0" gelesen: das ist die 
Command/Daten-Umschaltung und möchte auch richtig angesteuert werden.
Wenn Reset fest auf H liegt auch unbedingt vor dem Initalisieren lange 
genug warten, bis der Dispalycontroller mit seinem PowerOn-Reset durch 
ist, die können (im Verhältnis zum AVR) dafür auch "ewig" brauchen, 
etliche ms.

Besser ist es, Reset anzusteuern und nach dem H setzen sicherheitshalber 
erstmal 100ms zu warten wenn man nicht erst im Dateblatt des Controllres 
kramen will.

Gruß aus Berlin
Michael

: Bearbeitet durch User
von grundschüler (Gast)


Lesenswert?

Max M. schrieb:
> Oder muss man den trotzdem im Programm als Eingang definieren?

ich meine ja

von Michael U. (amiga)


Lesenswert?

Hallo,

das Datenblatt des Mega328 sagt, daß SPI Enable im Mastermode MISO auf 
Input setzt und die anderen Leitungen (MOSI/SCK/SS) vom User gesetzt 
werden müssen.
Eigenlich dürfte MISO garkein Ausgang werden solange SPI-Master aktiv 
ist weil die SPI-Settings gewinnen.

Gruß aus Berlin
Michael

: Bearbeitet durch User
von Max M. (maxmicr)


Lesenswert?

Michael U. schrieb:
> Besser ist es, Reset anzusteuern und nach dem H setzen sicherheitshalber
> erstmal 100ms zu warten wenn man nicht erst im Dateblatt des Controllres

Der Reset Pins des LCDs ist mit dem Reset Pins des Boards verbunden (wie 
von
grundschüler weiter oben vorgeschlagen). Kann ich den einfach so 
anschalten?

grundschüler schrieb:
> ich meine ja

Okay, meine Init Funktion sieht nun so aus:
1
void SPI_init(){
2
  SPCR = (1<<SPE); //init SPI
3
  SPCR = (1<<SPR0);//SCK = F_CPU/16, 
4
  SPCR = (1<<MSTR);//enable Master
5
6
  DDRB = (1<<DDB3) | (1<<DDB5) | (1<<DDB2); //MOSI, SCK, SS as Output
7
  DDRB &= ~(1<<DDB4); //MISO as Input
8
9
  DDRD = (1<<DDD2); //turn Vcc as Output to supply display
10
}

Ich hab dann mal PD7 mit der LED dran blinken lassen um zu testen, ob 
das Programm nun nicht mehr im while hängen bleibt:
1
int main (void)
2
{
3
  DDRD |= (1<<DDD7); //turn D7 as output
4
  while(1){
5
    PORTD |= (1<<DDD7); //on
6
    _delay_ms(1000);
7
    SPI_transmit('c');
8
    PORTD &= ~(1<<DDD7); //off
9
    _delay_ms(250);
10
  }
11
  return 0;
12
}

Aber die LED geht nur an aber nicht mehr aus -> bleibt immer noch hängen

Für das Initialisieren bzw. einfach mal Daten rausschieben dürfte es 
doch egal sein, wie der A0 (Reset Pin) geschaltet ist, oder? Irgendwas 
stimmt also immer noch nicht mit meiner Init Funktion, sehe ich das 
richtig? Sonst würde die while Schleife ja nach einer gewissen Zeit 
durchlaufen werden.

von grundschüler (Gast)


Lesenswert?

in der main fehlt der Aufruf von

SPI_init()

von Michael U. (amiga)


Lesenswert?

Hallo,

ich habe irgendwie garnicht wahrgenommen, daß bereits Dein SPI nicht 
macht, was soll...

>  while((!SPSR & (1<<SPIF))) //transmit is done if SPIF is not one

Sieht für mich falsch aus, Du machst ein Not von SPSR und dann die 
And-Verknüpfung,
das dürfte wohl eher so richtig sein:

>  while(!(SPSR & (1<<SPIF))) //transmit is done if SPIF is not one


Gruß aus Berlin
Michael

von Max M. (maxmicr)


Lesenswert?

grundschüler schrieb:
> in der main fehlt der Aufruf von
>
> SPI_init()

Lol, ist nun drinnen:
1
int main (void)
2
{
3
  SPI_init();
4
  DDRD |= (1<<DDD7); //turn D7 as output
5
  while(1){
6
    PORTD |= (1<<DDD7); //on
7
    _delay_ms(1000);
8
    SPI_transmit('c');
9
    PORTD &= ~(1<<DDD7); //off
10
    _delay_ms(250);
11
  }
12
  return 0;
13
}

funktioniert trotzdem nicht (also LED geht an, aber nicht wieder aus) 
_

Michael U. schrieb:
> Sieht für mich falsch aus, Du machst ein Not von SPSR und dann die
> And-Verknüpfung,

Der Fehler ist mir kurz nach dem Beitrag selber aufgefallen, hatte ich 
bereits gefixt (siehe: 
Beitrag "Re: TFT_ILI9163C mit Arduino richtig verbinden")

von grundschüler (Gast)


Lesenswert?

ich habe deinen code nochmal probiert und es blinkte nicht!

Nach Änderung
1
void SPI_init(){
2
//  SPCR = (1<<SPE); //init SPI
3
//  SPCR = (1<<SPR0);//SCK = F_CPU/16, 
4
//  SPCR = (1<<MSTR);//enable Master
5
6
  DDRB = (1<<DDB3) | (1<<DDB5) | (1<<DDB2); //MOSI, SCK, SS as Output
7
  DDRB &= ~(1<<DDB4); //MISO as Input
8
9
//  DDRD = (1<<DDD2); //turn Vcc as Output to supply display
10
SPCR=(1<<SPE)|(1<<MSTR);
11
SPCR|=(1<<CPOL);// 
12
SPCR|=(1<<CPHA);//
13
SPSR = (1 << SPI2X);  // maximale Geschwindigkeit: F_CPU / 2 
14
_delay_ms(50);
15
}

geht es.

von grundschüler (Gast)


Lesenswert?

Jetzt wird es auch klar warum:
//  SPCR = (1<<MSTR);//enable Master

damit schaltest du

//  SPCR = (1<<SPE); //init SPI
aus.

von Max M. (maxmicr)


Lesenswert?

grundschüler schrieb:
> geht es.

Jep, super danke!!!
1
void SPI_init(){
2
  DDRB = (1<<DDB3) | (1<<DDB5) | (1<<DDB2); //MOSI, SCK, SS as Output
3
  DDRB &= ~(1<<DDB4); //MISO as Input
4
5
  DDRD |= (1<<DDD2); //turn Vcc as Output to supply display
6
7
  SPCR = (1<<SPE) | (1<<MSTR); //init SPI & enable Master mode
8
  SPCR |= (1<<CPOL);
9
  SPCR |= (1<<CPHA);
10
  SPSR = (1<<SPI2X);//SCK = F_CPU/2, 
11
  _delay_ms(50);
12
}

Mir ist aber vom Datenblatt her nicht klar, warum ich CPOL und CPHA 
anschalten muss?

: Bearbeitet durch User
von Michael U. (amiga)


Lesenswert?

Hallo,

  SPCR = (1<<SPE); //init SPI
  SPCR = (1<<SPR0);//SCK = F_CPU/16,
  SPCR = (1<<MSTR);//enable Master

toll.. Du schaltest den SPI ein und dann wieder aus...

  SPCR = (1<<SPE) | (1<<SPR0) | (1<<MSTR); //init SPI

Gibt allerdings noch ein nettes anderes Problem: SPIF wird nach dem 
ersten Senden nicht zurückgesetzt. Ich habe wohl auch zulange nichts 
mehr mit SPI zu Fuß gemacht, ein Einlesen von SPDR nach Lesen von SPSR 
mit gesetztem SPIF soll es löschen, macht es bei mir aber gerade auch 
nicht???

Gruß aus Berlin
Michael

von Max M. (maxmicr)


Lesenswert?

Michael U. schrieb:
> PIF wird nach dem
> ersten Senden nicht zurückgesetzt.

Warum das denn? Davon steht in der documentation aber nichts :(

von Michael U. (amiga)


Lesenswert?

Hallo,

Max M. schrieb:
> Mir ist aber vom Datenblatt her nicht klar, warum ich CPOL und CPHA
> anschalten muss?

Mußt Du auch nicht, das legt den SPI-Mode fest und welcher nötig ist 
bestimmt das Timing des Slave.

>> SPIF wird nach dem
>> ersten Senden nicht zurückgesetzt.

>Warum das denn? Davon steht in der documentation aber nichts :(

Nö, das ist hier bei mir beim "Schnelltest" passiert, habe es aber nicht 
weiter verfolgt.
Bei Dir geht es jetzt?

Gruß aus Berlin
Michael

von Max M. (maxmicr)


Angehängte Dateien:

Lesenswert?

Michael U. schrieb:
> Bei Dir geht es jetzt?

Also zumindest die LED blinkt nun durchgängig, also bleibt das Programm 
nicht mehr in der while-Schleife hängen.

Display initialisieren ist aber weiterhin nicht :(

Edit: Achso, ja hier noch die Fotos.

: Bearbeitet durch User
von Michael U. (amiga)


Lesenswert?

Hallo,

sehen sich sehr ähnlich (Beschriftungstext identisch, bei mir kein 
Aufdruck auf dem Plasterahmen), Layout weicht etwas ab. Bleibt also 
interessant. ;-)

Was schickst Du denn dem Display zur Zeit und was soll passieren?

Gruß aus Berlin
Michael

von Max M. (maxmicr)


Lesenswert?

Michael U. schrieb:
> Bleibt also
> interessant. ;-)

Wäre zwischenzeitlich mal ganz schön, wenn es nicht so interessant bzw. 
langwierig wäre.

Michael U. schrieb:
> Was schickst Du denn dem Display zur Zeit und was soll passieren?

Ich bin immer noch am Suchen, welche Sachen ich nun alle über SPI an das 
LCD übertragen muss, damit es reagiert.

von Michael U. (amiga)


Lesenswert?

Hallo,

naja, es ist schon etliche Jahre her, aber bis meine eigenen T6963C 
Routinen liefen hat es auch etwas gedauert.
Gerade mal geschaut:
Beitrag "LCD mit T6963C in ASM"

Die Pixelmaster-Lib ist da recht brauchbar dokumentiert und kann Deinen 
Controller auch. Nachschauen und vergleichen ist nicht verboten und 
außerdem kann man eben erstmal sicherstellen, ob die Hardware geht.

Habe gerade mal ins Datenblatt des ILI9163C geschaut: viel Vergnügen. 
:-)
Ich werde mir die 200 Seiten nicht antun, dagegen ist ein alter T6963C 
nur Spielzeug. Ist ja auch logisch, 16Bit RGB wollen dazu doch etwas 
mehr Init.

Ein paar Ablaufdiagramme sind ja drin und die Beschreibung der wohl rund 
100 Register ist ja auch lesbar.

Ich will Dich nicht von Deinem Vorhaben abbringen, ich versuche nur Dein 
Vorhaben zu verstehen und Deine Vorkenntnisse einzuschätzen, das ist nur 
Neugier oder Interesse von mir...

Gruß aus Berlin
Michael

von Max M. (maxmicr)


Angehängte Dateien:

Lesenswert?

Hi,

Ich hab eine Frage zu der Parameterbeschreibung. Nehmen wir mal an, ich 
möchte den ersten Parameter setzen.

Dann muss D/CX auf "1", RDX auf "High"(?), WRX auf 1 und D17-8 auf was? 
Und danach folgen komische Buchstabenkombinationen die mir überhaupt 
nichts sagen. Und was sollen D7 - D0 sein?

D/CX ist vllt. Chip Select (?), RDX vllt. MOSI und WRX MISO, aber der 
Rest?

Michael U. schrieb:
> Ein paar Ablaufdiagramme sind ja drin und die Beschreibung der wohl rund
> 100 Register ist ja auch lesbar.

Ja, "lesbar". Aber nirgends steht, was ich für das initialisieren setzen 
muss.

Michael U. schrieb:
> ich versuche nur Dein
> Vorhaben zu verstehen und Deine Vorkenntnisse einzuschätzen

Keine Vorkenntnisse. Mache das ganze zum ersten Mal.

Michael U. schrieb:
> Nachschauen und vergleichen ist nicht verboten

Okay, schau ich mir mal an.

: Bearbeitet durch User
von Michael U. (amiga)


Lesenswert?

Hallo,

Du bist beim 8 Bit Parallel-Mode gelandet.
Die Displays sind im 4-Wire seriell Mode und das kannst Du auch nicht 
ändern, weil Du an die zugehörigen Pins des Controllers nicht rankommst.

Ich war diesmal schon zufrieden, daß sich der Adafruit-Kram für meinen 
Controller halbwegs problemlos für das ESP8266 WLAN-Modul compilieren 
ließ und auch spielte.

Gruß aus Berlin
Michael

: Bearbeitet durch User
von Max M. (maxmicr)


Lesenswert?

Michael U. schrieb:
> Du bist beim 8 Bit Parallel-Mode gelandet.

Wie komme ich zum richtigen Mode ^^?

Die Pixelmeister-Lib wirft in der Arduino IDE nur Fehler mit 
"[Funktionsname] was not declared in this scope". Wahrscheinlich muss 
ich noch eine lib einfügen, die ich gerade übersehe.

Edit: Okay, das Program lies sich nun kompilieren und hochladen. Aber 
passieren tut nix, außer das nun sämtliche LEDs auf dem Nano Board 
leuchten (RX, TX & LED).

: Bearbeitet durch User
von Michael U. (amiga)


Lesenswert?

Hallo,

bei ging es vorhin. Angeschlssen wie im setup?
    pxs.setSpiPins(13, 11, 10, 7 ,9); // (SCK, MOSI, CS, RES, D/C)

Du kannst ja spaßeshalber Deinen Controller durch meinen erstezen

#include <Pixels_ST7735.h>

ansonsten höre ich für heute erstmal auf.

Gruß aus Berlin
Michael

von Max M. (maxmicr)


Lesenswert?

Michael U. schrieb:
> Angeschlssen wie im setup?

Sind damit die Pinnummern von Atmel oder die Pinnummern von Arduino 
gemeint?

Michael U. schrieb:
> ansonsten höre ich für heute erstmal auf

Ja, sollte ich wahrscheinlich auch. Gute Nacht

von grundschüler (Gast)


Lesenswert?

Du brauchst funktionierenden code mit der Initialisierungssequenz 
serial-ili9163. Wundert mich, dass den niemand hier bereitstellt. es ist 
doch ein weit verbreitetes display.

Bei googeln nach serial-ili9163.c findet man z.B.
http://www.pocketmagic.net/ili9163-lcd-library/
1
// Reset the LCD hardware
2
void ILI9163::reset(void) {
3
    // Reset pin is active low (0 = reset, 1 = ready)
4
  m_reset->write(0);
5
    _delay_ms(50);
6
7
    m_reset->write(1);
8
    _delay_ms(120);
9
}
10
11
void ILI9163::writeCommand(uint8_t address) {
12
    uint8_t i;
13
    m_cs->write(0);
14
    m_a0->write(0);
15
    for(i=0;i<8;i++) {
16
        if(address & 128) m_sda->write(1); else m_sda->write(0);
17
        m_sck->write(1);
18
        address <<= 1;
19
        m_sck->write(0);
20
    }
21
    _delay_us(1);
22
    m_cs->write(1);
23
}
24
25
void ILI9163::writeParameter(uint8_t parameter) {
26
    uint8_t i;
27
28
    m_cs->write(0);
29
    m_a0->write(1);
30
    for(i=0;i<8;i++) {
31
        if(parameter & 128) m_sda->write(1); else m_sda->write(0);
32
        m_sck->write(1);
33
        parameter <<= 1;
34
        m_sck->write(0);
35
    }
36
    //_delay_us(1);
37
    m_cs->write(1);
38
}
39
40
void ILI9163::writeData(uint16_t word) {
41
  m_cs->write(0);
42
  m_a0->write(1);
43
  for (int i=0;i<16;i++) {
44
    if (word & 0x8000) m_sda->write(1); else m_sda->write(0);
45
    m_sck->write(1);
46
    m_sck->write(0);
47
    word <<=1;
48
  }
49
  m_cs->write(1);
50
}
51
52
// Initialise the display with the require screen orientation
53
void ILI9163::init(uint8_t orientation) {
54
    m_cs->write(1);
55
    m_sck->write(0);
56
    m_reset->write(1);
57
   
58
    // Hardware reset the LCD
59
    reset();
60
    
61
    writeCommand(EXIT_SLEEP_MODE);
62
    _delay_ms(5); // Wait for the screen to wake up
63
    
64
    writeCommand(SET_PIXEL_FORMAT);
65
    writeParameter(0x05); // 16 bits per pixel
66
   
67
    writeCommand(SET_GAMMA_CURVE);
68
    writeParameter(0x04); // Select gamma curve 3
69
    
70
    writeCommand(GAM_R_SEL);
71
    writeParameter(0x01); // Gamma adjustment enabled
72
    
73
    writeCommand(POSITIVE_GAMMA_CORRECT);
74
    writeParameter(0x3f); // 1st Parameter
75
    writeParameter(0x25); // 2nd Parameter
76
    writeParameter(0x1c); // 3rd Parameter
77
    writeParameter(0x1e); // 4th Parameter
78
    writeParameter(0x20); // 5th Parameter
79
    writeParameter(0x12); // 6th Parameter
80
    writeParameter(0x2a); // 7th Parameter
81
    writeParameter(0x90); // 8th Parameter
82
    writeParameter(0x24); // 9th Parameter
83
    writeParameter(0x11); // 10th Parameter
84
    writeParameter(0x00); // 11th Parameter
85
    writeParameter(0x00); // 12th Parameter
86
    writeParameter(0x00); // 13th Parameter
87
    writeParameter(0x00); // 14th Parameter
88
    writeParameter(0x00); // 15th Parameter
89
     
90
    writeCommand(NEGATIVE_GAMMA_CORRECT);
91
    writeParameter(0x20); // 1st Parameter
92
    writeParameter(0x20); // 2nd Parameter
93
    writeParameter(0x20); // 3rd Parameter
94
    writeParameter(0x20); // 4th Parameter
95
    writeParameter(0x05); // 5th Parameter
96
    writeParameter(0x00); // 6th Parameter
97
    writeParameter(0x15); // 7th Parameter
98
    writeParameter(0xa7); // 8th Parameter
99
    writeParameter(0x3d); // 9th Parameter
100
    writeParameter(0x18); // 10th Parameter
101
    writeParameter(0x25); // 11th Parameter
102
    writeParameter(0x2a); // 12th Parameter
103
    writeParameter(0x2b); // 13th Parameter
104
    writeParameter(0x2b); // 14th Parameter
105
    writeParameter(0x3a); // 15th Parameter
106
    
107
    writeCommand(FRAME_RATE_CONTROL1);
108
    writeParameter(0x08); // DIVA = 8
109
    writeParameter(0x08); // VPA = 8
110
    
111
    writeCommand(DISPLAY_INVERSION);
112
    writeParameter(0x07); // NLA = 1, NLB = 1, NLC = 1 (all on Frame Inversion)
113
   
114
    writeCommand(POWER_CONTROL1);
115
    writeParameter(0x0a); // VRH = 10:  GVDD = 4.30
116
    writeParameter(0x02); // VC = 2: VCI1 = 2.65
117
      
118
    writeCommand(POWER_CONTROL2);
119
    writeParameter(0x02); // BT = 2: AVDD = 2xVCI1, VCL = -1xVCI1, VGH = 5xVCI1, VGL = -2xVCI1
120
121
    writeCommand(VCOM_CONTROL1);
122
    writeParameter(0x50); // VMH = 80: VCOMH voltage = 4.5
123
    writeParameter(0x5b); // VML = 91: VCOML voltage = -0.225
124
    
125
    writeCommand(VCOM_OFFSET_CONTROL);
126
    writeParameter(0x40); // nVM = 0, VMF = 64: VCOMH output = VMH, VCOML output = VML
127
    
128
    writeCommand(SET_COLUMN_ADDRESS);
129
    writeParameter(0x00); // XSH
130
    writeParameter(0x00); // XSL
131
    writeParameter(0x00); // XEH
132
    writeParameter(0x7f); // XEL (128 pixels x)
133
   
134
    writeCommand(SET_PAGE_ADDRESS);
135
    writeParameter(0x00);
136
    writeParameter(0x00);
137
    writeParameter(0x00);
138
    writeParameter(0x7f); // 128 pixels y
139
    
140
    // Select display orientation
141
    writeCommand(SET_ADDRESS_MODE);
142
    writeParameter(orientation);
143
144
    // Set the display to on
145
    writeCommand(SET_DISPLAY_ON);
146
    writeCommand(WRITE_MEMORY_START);
147
}


Das scheint Bitbanging-code in c++ zu sein.


In C für dein spi ergibt das z.B.:

#define m_cs_write_low PORTx|=(1<<pinx)
...
//void ILI9163::writeCommand(uint8_t address) {
writeCommand(uint8_t address) {
    uint8_t i;
    m_cs_write_low;
    m_a0_write_low;

    SPI_transmit(address);

    _delay_us(1);
    m_cs_write_high;
}



usw.

von grundschüler (Gast)


Lesenswert?

grundschüler schrieb:
> #define m_cs_write_low PORTx|=(1<<pinx)

das ist natürlich high und nicht low

von Michael U. (amiga)


Lesenswert?

Max M. schrieb:
> Michael U. schrieb:
>> Angeschlssen wie im setup?
>
> Sind damit die Pinnummern von Atmel oder die Pinnummern von Arduino
> gemeint?

die vom Arduino.

grundschüler schrieb:
> Du brauchst funktionierenden code mit der Initialisierungssequenz
> serial-ili9163. Wundert mich, dass den niemand hier bereitstellt. es ist
> doch ein weit verbreitetes display.

Das ist in den Arduino-Libs doch letztlich auch so enthalten.
Bisher war ja auch erstmal SPI sein Problem verbunden mit der Absicht, 
das alles selbst rausfinden zu wollen.

Gruß aus Berlin
Michael

von Max M. (maxmicr)


Lesenswert?

Danke, das sieht doch gut aus!

Max M. schrieb:
> Der Reset Pins des LCDs ist mit dem Reset Pins des Boards verbunden (wie
> von
> grundschüler weiter oben vorgeschlagen). Kann ich den einfach so
> anschalten?

Kann ich den Reset Pin vom Arduino einfach so High und Low schalten oder 
resettet er sich dann selber? Noch dazu ist ja eine Invertierung davor?

: Bearbeitet durch User
von Michael U. (amiga)


Lesenswert?

Hallo,

Max M. schrieb:
> Kann ich den Reset Pin vom Arduino einfach so High und Low schalten oder
> resettet er sich dann selber? Noch dazu ist ja eine Invertierung davor?

den Reset-Pin des Mega328 kannst Du garnicht schalten, der ist ein 
Reset-Eingang und kein I/O-Port. Für Display-Reset mußt Du dann schon 
einen I/O opfern.

Das ist aber z.B. auch in der Arduino-Lib so. Nach dem Anschluß hatte 
ich ja oben schon gefragt.

Von welcher Invertierung redest Du? Sowohl beim AVR als auch beim 
Display ist Reset Low-aktiv.
Auch in seiner Source wird es so bedient.
1
// Reset the LCD hardware
2
void ILI9163::reset(void) {
3
    // Reset pin is active low (0 = reset, 1 = ready)
4
  m_reset->write(0);
5
    _delay_ms(50);
6
7
    m_reset->write(1);
8
    _delay_ms(120);
9
}

Gruß aus Berlin
Michael

von Max M. (maxmicr)


Angehängte Dateien:

Lesenswert?

Okay, ich hab jetzt mal versucht, das ganze nach zu programmieren. Noch 
eine Verständnisfrage. Wie kommt man von diesen Parameterangaben vom 
Datenblatt (siehe Bild) auf den Parameterwert "0x3f"?

von grundschüler (Gast)


Lesenswert?

bei meinem ili9325 reicht rst an rst. Ich würde mir da aber keinen Kopf 
darüber machen. Du hast genug pins. Mach es genau so wie in deiner 
Vorlage.

von Michael U. (amiga)


Lesenswert?

Hallo,

vermutlich, indem man sich die Gamma-Kurven anschaut, irgendwo im 
Datenblatt die Erklärung der Parameter in der Formel zur Positive Gamma 
Correction zusammensucht und den Wert übernimmt.
Wird sich wohl irgendwo aus Tabelle 1 ergeben, letztlich ist es ja die 
Spannungskorrektur der LCD-Treiber um den gewünschten Gamma-Verlauf zu 
erhalten.

LCD-Treiber-IC-Parameter an das verwendete LCD anzupassen ist wirklich 
nicht meine Baustelle, dazu braucht man ja auch noch die Unterlagen des 
zugehörigen Displays (Aufbau, Backplanes, nötige Spannungsverläufe 
usw.).

Gruß aus Berlin
Michael

von Max M. (maxmicr)


Lesenswert?

grundschüler schrieb:
> Mach es genau so wie in deiner
> Vorlage.

Okay ich hab jetzt Reset an PB0 (D8) gehängt.
Nur damit ich das richtig verstehe:

"m_a0->write(1);" bedeutet das A0 "high" geschalten wird?

von Michael U. (amiga)


Lesenswert?

Hallo,

write() muß irgendwo in der Lib existieren, sonst könnte es ja nicht 
benutzt werden...
Also suchen aunfd anschauen, was es genau macht.
Würde mich allerdings wundern, wenn da noch jemand was umdreht und eine 
1 in ein als Ausgang definiertes Portregister schreiben setzt einen AVR 
Ausgang eben auf High.

Gruß aus Berlin
Michael

von Max M. (maxmicr)


Lesenswert?

Also write macht das hier:

1
// Set the output, specified as 0 or 1 (int)
2
void DigitalPin::write(bool state) {
3
  state? *m_pport |= mask1 : *m_pport &= mask0;
4
}

also einfach nur an und aus. Ich frag mich dann, warum mein 
abgeschriebener Code immer noch nicht geht...

von Michael U. (amiga)


Lesenswert?

Hallo,

das kann ich Dir allerdings auch nicht sagen...

Du kannst ja mal Dein komplettes Projekt in ein zip packen und hier 
anhängen.
Ein passendes Display habe ich nicht zur Hand, aber ich kann es ja mal 
auf den Nano packen und den Logik-Analyzer ranhängen, ob da überhaupt 
rauskommt was reingeht.
Ich mußte erstmal von meinen beiden Uhren den ESP8266 neu flashen, war 
zu faul gewesen, die Zeitumschaltung in die NPT-Funktion reinzubauen und 
nun gingen die falsch...
Dabei stellte sich erstmal raus, daß in der einen der FTDi232 gestorben 
war (wohl meine Schuld, ist nur nicht aufgefallen seit einem halben 
Jahr).

Das und mein Schnupfen haben mir für heute erstmal etwas die Lust an 
eigenen Basteleien verdorben.

Gruß aus Berlin
Michael

von Max M. (maxmicr)


Lesenswert?

Michael U. schrieb:
> Ich mußte erstmal von meinen beiden Uhren den ESP8266 neu flashen

Hey cool! Wenn ich das Display endlich zum laufen bringe plane ich auch 
ein Projekt mit dem ESP8266. Programmierst du die mit C oder hast du 
eine NodeMCU-Firmware laufen?

Michael U. schrieb:
> Das und mein Schnupfen haben mir für heute erstmal etwas die Lust an
> eigenen Basteleien verdorben.

Sorry, gute Besserung.

von Michael U. (amiga)


Lesenswert?

Max M. schrieb:
> Michael U. schrieb:
>> Ich mußte erstmal von meinen beiden Uhren den ESP8266 neu flashen
>
> Hey cool! Wenn ich das Display endlich zum laufen bringe plane ich auch
> ein Projekt mit dem ESP8266. Programmierst du die mit C oder hast du
> eine NodeMCU-Firmware laufen?

lustige C/C++-Mischung aus der Arduino-IDE.
Mein Display war auch schonmal am ESP  als WLAN-Scanner, war der Grund 
eine anpaßbare Arduino-Lib zu suchen.

Falls Du mal Langeweile hast:
http://www.avr.roehres-home.de/

habe im Moment nur keine Lust, richtig weiterzumachen...

> Sorry, gute Besserung.
Naja, halb so schlimm, weiß nicht, ob es vielleicht eher eine Allergie 
(Birkenpollen?) ist.

Gruß aus Berlin
Michael

von Max M. (maxmicr)


Angehängte Dateien:

Lesenswert?

Michael U. schrieb:
> Du kannst ja mal Dein komplettes Projekt in ein zip packen und hier
> anhängen.

Ich hab mal PB3 (MOSI/SDA) an ein Oszilloskop gehängt. Das war dann ein 
Sägezahn-Muster auf dem Display. Sollte das so sein?

: Bearbeitet durch User
von Michael U. (amiga)


Lesenswert?

Hallo,

ok, versuche ich erstmal "konstruktives Gemecker"... ;-)

Was schaltest Du eigentlich mit DDD2?
Falls die Beleuchtung: hast den Strom mal gemessen?
Falls die Betriebsspannung des Displays: wozu???
Hast Du nachgeschaut, ob Deine  50ms im Init reichen, damit das Display 
seinen Reset beendet hat und überhaupt ansprechbar ist?

Weiter: ich sehe auf Anhieb nicht, daß Du A0 (DDC0) jemals auf Ausgang 
setzt.

Warum gibst Du Kindern nicht die Namen, die sie haben?
MOSI, MISO, SCK, SS sollten in der avr/io.h deklariert sein und Reset 
und CS kann man sich selber defnieren mit
 #define RESET DDB0
 #define CS    DDB2
 #define A0    DDC0

Bei mir um Duplikate zu vermeiden meist:
 #define DISP_SDA   MOSI
 #define DISP_SCK   SCK
 #define DISP_RESET DDB0
 #define DISP_CS    DDB2
 #define DISP_A0    DDC0

Warum also nicht gleich:
  DDRB = (1<<MOSI) | (1<<SCK) | (1<<CS) | (1<<RESET); //MOSI, SCK, SS, 
D8 as Output

Dann kann man sich z.B. fast jeden Kommentar sparen:
1
void write_command(uint8_t address){
2
  uint8_t i;
3
  PORTB &= ~(1<<DDB2); //turn CS low
4
  PORTC &= ~(1<<DDC0); //turn A0 low
5
  for(i = 0; i < 8; i++){
6
    if(address & 128){
7
      PORTB |= (1<<DDB3); //turn SDA high
8
    } else {
9
      PORTB &= ~(1<<DDB3); //turn SDA low
10
    }
11
    PORTB |= (1<<DDB5); //turn SCK high
12
    address <<=1;
13
    PORTB &= ~(1<<DDB5); //turn SCK low
14
  }
15
  _delay_ms(1);
16
  PORTB |= (1<<DDB2); //turn CS high
17
}
wird zu
1
void write_command(uint8_t address){
2
  uint8_t i;
3
  PORTB &= ~(1<<DISP_CS); //turn CS low
4
  PORTC &= ~(1<<DISP_A0); //turn A0 low
5
  for(i = 0; i < 8; i++){
6
    if(address & 128){
7
      PORTB |= (1<<DISP_SDA); //turn SDA high
8
    } else {
9
      PORTB &= ~(1<<DISP_SDA); //turn SDA low
10
    }
11
    PORTB |= (1<<DISP_SCK); //turn SCK high
12
    address <<=1;
13
    PORTB &= ~(1<<DISP_SCK); //turn SCK low
14
  }
15
  _delay_ms(1);
16
  PORTB |= (1<<DISP_CS); //turn CS high
17
}

Wenn man jetzt was auf einen anderen Pin legt kostet es genau das Ändern 
eines #define und nicht die Suche nach der Pinbezeichnung im ganzen 
Code.

Außerdem ist es auch für andere lesbar und !wichtig" aucg für Dich 
spätestens wenn Du in einem Jahr weider reinschaust...

So, mal weitersehen. ;-)

Gruß aus Berlin
Michael

von Michael U. (amiga)


Angehängte Dateien:

Lesenswert?

Hallo,

so. Es macht wenig Sinn, bei Software-SPI mit Bit-Banging den 
Hardware-SPI zu initialisieren. Mußt Du mal selber rüberschauen, 
zumindest sendet er die Daten über SPI jetzt raus.

#include <asf.h> ist auskommentiert, sagte mir nichts, wohl von Deiner 
IDE, außerdem ist in der main nochwas auskommentiert, ich wollte ihn da 
nur anhalten für den LA.

Ich habe leider nie eine Save-Routine in meinen Logic-Analyzer 
eingebaut, deshalb gibt es einen Screnshot vom ersten write_command...

Gruß aus Berlin
Michael

: Bearbeitet durch User
von Max M. (maxmicr)


Lesenswert?

Dein...Code...geht...

Edit: Okay, der Fehler war wohl, dass ich A0 nicht als Ausgang gesetzt 
habe. Vielen Dank für die umfangreiche Hilfe!

: Bearbeitet durch User
von Michael U. (amiga)


Lesenswert?

Hallo,

Max M. schrieb:
> Dein...Code...geht...
>
> Edit: Okay, der Fehler war wohl, dass ich A0 nicht als Ausgang gesetzt
> habe. Vielen Dank für die umfangreiche Hilfe!

na also. Kein Problem, hat letztlich ja zum Erfolg geführt.
Kam mein LA wenigstens mal wieder zum Einsatz. ;-)
Der ist damals auch mehr wegen "das geht so nicht" entstanden...

Gruß aus Berlin
Michael

von Max M. (maxmicr)


Lesenswert?

Ich hab nun doch noch eine Frage. In der lib von hier 
https://github.com/radhoo/ILI9163_LCD wird SPI initialisiert:
1
void spi_init(void) {
2
  PORTB = 0b10110101;      /* Enable drivers */
3
  DDRB  = 0b11000111;
4
  SPCR = (1<<SPE) | (1<<MSTR);
5
  SPSR |= (1<<SPI2X);
6
}

Mit den binären Portzuweisungen werden wahrscheinlich MISO, SCK etc. als 
Output gesetzt.

Unter anderem schreibt die Funktion "writeData16":
1
void ILI9163::writeData16(uint16_t word) {
2
  m_cs->write(0);
3
  // set D/C pin for data
4
  m_a0->write(1);
5
  // send data by SPI
6
  spi_send((word >> 8) & 0x00FF);
7
  spi_send(word & 0x00FF);
8
  m_cs->write(1);
9
}

damit etwas ins SPI-Register. Wenn ich den MSTR, SPE usw. bei mir setze, 
funktioniert der Display-Code nicht mehr. So funktioniert es noch:
1
void SPI_init(){
2
  DDRB = (1<<MOSI) | (1<<SCK) | (1<<SS) | (1<<RESET); //MOSI, SCK, SS, Reset as Output
3
  DDRB &= ~(1<<DDB4); //MISO as Input
4
  DDRC |= (1<<DDC0);
5
  //SPCR = (1<<SPE) | (1<<MSTR); //init SPI & enable Master mode
6
  //SPSR = (1<<SPI2X);//SCK = F_CPU/2, 
7
  _delay_ms(50);
8
}

mit dem Auskommentierten wieder eingekommentiert gehts dann nicht mehr. 
Somit kann ich natürlich auch nichts über SPI schreiben. Was hab ich 
übersehen?

Edit:

Hm, mit dieser Funktion als "Ersatz" funktionierts dann:
1
void writeData(uint16_t word){
2
  PORTB &= ~(1<<DDB2); //turn CS low
3
  PORTC |= (1<<DDC0); //turn A0 high
4
  for(int i = 0; i < 16; i++){
5
    if(word & 0x8000){
6
      PORTB |= (1<<DDB3); //turn SDA high
7
      } else {
8
      PORTB &= ~(1<<DDB3); //turn SDA low
9
    }
10
    PORTB |= (1<<DDB5); //write SCK high
11
    PORTB &= ~(1<<DDB5); //write SCK low
12
    word <<=1;
13
  }
14
  PORTB |= (1<<DDB2); //turn CS high
15
}

: Bearbeitet durch User
von Michael U. (amiga)


Lesenswert?

Hallo,

der Ersatz ist ein Software-SPI, Daten und Clock werden "von Hand" 
gesetzt, ist langsamer, aber manchmal will man den Hardware-SPI 
unbedingt für was anderes oder das Timing paßt in keinem Mode zum 
SPI-Slave.
Die Herstelelr von ICs mit "SPI"-Schnittstelle sind da manchmal sehr 
creativ...

Entwerde erstmal mit Soft-SPI leben oder alles auf Hardware umstellen 
(Init und die Schreibfunktionen) und hoffen oder mit den Datenblättern 
vergleichen, welcher SPI-Mode paßt, wie schnell der Slave kann usw.

Gruß aus Berlin
Michael

von Max M. (maxmicr)


Lesenswert?

Michael U. schrieb:
> Entwerde erstmal mit Soft-SPI leben oder alles auf Hardware umstellen
> (Init und die Schreibfunktionen) und hoffen oder mit den Datenblättern
> vergleichen, welcher SPI-Mode paßt, wie schnell der Slave kann usw.

Okay, werde ich mal versuchen. Ich denke aber, fürs erste passt das 
schon so. Auch wenns sichtlich langsam ist ^^

Ich hätte noch eine Verständnisfrage zum Code:

In der Funktion "drawChar()":
1
void ILI9163::drawChar( uint8_t x, uint8_t y, char c, uint8_t size, uint16_t colour, uint16_t bg) {
2
  // draw. optimisation:6th font line is set as 0, to lower font array size
3
  for (int8_t i=0; i < FONT_WIDTH; i++ ) {
4
    uint8_t line = (i == FONT_WIDTH-1)? 0 : pgm_read_byte(font5x8 + (c * (FONT_WIDTH - 1)) + i);
5
    for (int8_t j = 0; j < FONT_HEIGHT; j++) {
6
      if (line & 0x1) {
7
        if (colour != TRANSPARENT) drawPixel(x + i*size, y + j*size, size, colour);
8
      }
9
      else {
10
        if (bg != TRANSPARENT) drawPixel(x + i*size, y + j*size, size, bg);
11
      }
12
      line >>= 1;
13
    }
14
  }
15
}

wird das Makro "pgm_read_byte" aufgerufen. An dieses Makro wird das 
Array "font5x8" übergeben, dass viele Bytes für ASCII Codes enthält. 
Allerdings verstehe ich nicht, wie man zu einem Array etwas hinzuzählen 
kann?
Also insbesondere das hier:
1
font5x8 + (c * (FONT_WIDTH - 1)) + i

verstehe ich nicht. Nach Atmel tut das Makro das: "Read a byte from the 
program space with a 16-bit (near) address."

Wäre nett, wenn mir das jemand beantworten könnte :)

: Bearbeitet durch User
von Michael U. (amiga)


Lesenswert?

Hallo,

es wird der Zeiger auf den Beginn des font5x8 Arrays übergeben.
Dann wir der Offset zum gewünschten Zeichenmuster berechnet und das Byte 
geholt. Das mit dem Zeiger ist eine C-Geschichte, das mit der Art der 
Ablage des Zeichensatzes eine Frage des Prigrammierers, man wird das 
Bitmuster eines Zeichensatzes möglichst so ablegen, wie es das Display 
gern haben möchte. und wie man die Pixelwerte in einer Schleife mit 
möglichste wenig weiterem Aufwand holen kann.

Das Macro ist in C und auf dem AVR nötig, weil der Zugriff auf den Flash 
mit anderen Befehlen passiert als der Zugriff auf den Ram 
(Harvard-Architektur).

Gruß aus Berlin
Michael

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.