Hallo zusammen, ich habe hier ein TFT-Display mit ILI9341-Controller liegen, den ich ueber SPI ansteuern moechte (die Variante mit 4 Leitungen; MISO, MOSI, SCL und DC). Zum Test der Kommunikation wuerde ich erstmal gerne einfach die Hersteller-ID auslesen. Das Datenblatt (http://www.newhavendisplay.com/app_notes/ILI9341.pdf) beschreibt das Vorgehen auf Seite 91. Ich bin allerdings noch relativ unerfahren im Umgang mit SPI und bin mir nicht ganz sicher, wie ich das hinbekomme. Der erste Schritt ist wohl, DC auf 0 zu ziehen, um zu signalisieren, dass ein Befehl folgt. Dann sende ich 0x04. Danach tun sich allerdings grosse Fragezeichen fuer mich auf. Anscheinend muss man DC dann wieder auf 1 setzen und dann...? Prinzipiell muessten dann irgendwie 3 Bytes mit den IDs zu bekommen sein. Aber wie genau muss ich dazu vorgehen? Ich werde aus dem Datenblatt einfach nicht schlau. Es waere nett, wenn mir da jemand einen Denkanstoss geben koennte. Viele Gruesse und danke, Martin
Wichtig zu wissen ist, dass die Übertragung mit CS gestartet und beendet wird. Pegeländerung High > Low startet die Übertragung, Low > High beendet sie. Der Pegel von DC legt nur fest, ob der Controller das Byte als Kommando oder Daten versteht.
@ Martin S. (tungl) >Der erste Schritt ist wohl, DC auf 0 zu ziehen, um zu signalisieren, >dass ein Befehl folgt. Dann sende ich 0x04. Ja. > Danach tun sich allerdings >grosse Fragezeichen fuer mich auf. Anscheinend muss man DC dann wieder >auf 1 setzen und dann...? Schau dir Seite 35 an. > Prinzipiell muessten dann irgendwie 3 Bytes >mit den IDs zu bekommen sein. Aber wie genau muss ich dazu vorgehen? Ich >werde aus dem Datenblatt einfach nicht schlau. Ganz einfach, nach 0x04 sendest du vier mal 0x00 (oder beliebige andere Daten), damit bekommst du vier mal Daten vom LCD zurück. Achtung, dieses SPI-Interface hat eien Make! Siehe Seite 38. Diesen Dummy-Clock können die meisten SPI-Module der Mikrocontroller nicht generieren. Da muss man tricksen! Entweder Soft-SPI oder zwischendurch Umschalten zwischen normalen GPIO-Funktion und SPI. Irgendwie doof.
>Achtung, dieses SPI-Interface hat eien Make! Siehe Seite 38. Diesen >Dummy-Clock können die meisten SPI-Module der Mikrocontroller nicht >generieren. Da muss man tricksen! Wieso nicht? Das sind 8 Clocks. Das ist nur blöd dargestellt mit den 5 sichtbaren. Man beachte die gestrichelten Linien;)
>Wieso nicht? Das sind 8 Clocks. Das ist nur blöd dargestellt >mit den 5 sichtbaren. Man beachte die gestrichelten Linien;) Verdammt, falsche Seite. Post vergessen oder löschen.
Vielen Dank fuer die Tipps! Diverese Libraries fuer den Controller habe ich mir schon angeschaut, aber mir ging es jetzt erstmal explizit um den Lesevorgang und dazu habe ich kein Beispiel gefunden. Wer will auch schon im "normalen Betrieb" unbedingt die Manufacturer-ID auslesen... @Falk: Auch Dir danke fuer die Erklaerung. Das mit dem Clock habe ich auch schon vorhin irgendwann mal bemerkt (also zumindest, dass da was seltsam ist), werde mir das jetzt im Datenblatt nochmal etwas genauer anschauen, in der Hoffnung, es genauer zu verstehen.
:
Bearbeitet durch User
Muss leider nochmal nachhaken, ich stehe extremst auf dem Schlauch, nachdem ich besagte Seite 38 nochmal angeschaut habe. Dort sieht es so aus, dass ich, nachdem ich das Command-Byte abgesetzt habe und der Dummy Cycle abgelaufen ist, die 3 Byte Antwortdaten (D0 bis D23) hintereinander weg rausgespuckt werden. Wo genau sehe ich jetzt, dass ich fuer jedes der Bytes tatsaechlich noch ein beliebiges Byte (die oben genannten 0x00) rausschicken muss?
>Muss leider nochmal nachhaken, ich stehe extremst auf dem Schlauch, >nachdem ich besagte Seite 38 nochmal angeschaut habe. Mal ein Vorschlag: Nimm das 8 Bit Read oben auf der Seite und vergiss das 24 Bit Read. >D23) hintereinander weg rausgespuckt werden. Wo genau sehe ich jetzt, >dass ich fuer jedes der Bytes tatsaechlich noch ein beliebiges Byte (die >oben genannten 0x00) rausschicken muss? Das ist bei SPI so. Wenn der Master kein Clocksignal generiert sendet der Slave nix. Clocksignale werden nur generiert wenn der Master etwas sendet, und seien es auch nur Dummy Bytes.
> Mal ein Vorschlag: Nimm das 8 Bit Read oben auf der Seite > und vergiss das 24 Bit Read. Ups. Ganz uebersehen, dass man die 24 Bit-Geschichte gar nicht zwingend dafuer braucht. Vielen Dank, dann lass' ich den Kaese wirklich. Zumal das Lesen zum Betrieb des Displays ja eher nebensaechlich ist. > Das ist bei SPI so. Wenn der Master kein Clocksignal generiert > sendet der Slave nix. Clocksignale werden nur generiert wenn > der Master etwas sendet, und seien es auch nur Dummy Bytes. Dass man bei SPI fuer jedes empfangene Byte ein gesendetes braucht, war mir soweit klar, aber in dem Diagramm auf Seite 38 sah das so kontinuierlich aus, das hat mich sehr irritiert. Aber jetzt ists's mir klar, nochmals danke. Werde jetzt mal sehen, ob ich das Teil gespraechig bekomme.
Ich krieg die Kiste einfach nicht dazu, mir was zu erzaehlen. In der 8-Bit-Variante (wie auf Seite 151) muesste ich eigentlich nur DC auf 0, 0xDA rausschicken, DC auf 1, zweimal 0x00 rausschicken und jeweils die Ohren aufsperren. Ergebnis: nichts. Kommt konsequent 0x00 zurueck.
1 | io.digitalWrite(self.dcPin, io.LOW) |
2 | time.sleep(0.001) |
3 | |
4 | r = spi.xfer2([0xDA]) |
5 | print hex(r[0]) |
6 | |
7 | io.digitalWrite(self.dcPin, io.HIGH) |
8 | time.sleep(0.001) |
9 | |
10 | r = spi.xfer2([0x00]) |
11 | print hex(r[0]) |
12 | |
13 | time.sleep(0.001) |
14 | r = spi.xfer2([0x00]) |
15 | print hex(r[0]) |
Irgendwas offensichtliches, was ich falsch gemacht habe?
:
Bearbeitet durch User
>In der 8-Bit-Variante (wie auf Seite 151) muesste ich eigentlich >nur DC auf 0, 0xDA rausschicken, DC auf 1, zweimal 0x00 rausschicken >und jeweils die Ohren aufsperren. Laut Seite 38 schickst du 0xDA mit DC auf 0. Dann ein Dummybyte mit DC auf egal. Danach sollte im SPI Empfangsregister dein Wert stehen. Benutzt du eine Chip Select Leitung CSX? Ohne wird das nix. Das muss schon so aussehen wie im Datenblatt: CS = 0 DC = 0 write 0xDA write 0xwas immer du willst lese SPI Register CS = 1
Und ich hab immer noch das Gefühl, da fehlt CS ;)
:
Bearbeitet durch User
Jep, um die Chip Select-Leitung kuemmert sich die SPI-Library, die ich verwende. Das wird korrekt auf 0 gezogen, wenn geschrieben wird. Leider bleibt die Antwort aus.
Nachtrag: CS = 1 <------------------------ CS = 0 DC = 0 write 0xDA write 0xwas immer du willst lese SPI Register CS = 1 Die Flanke CS = 1 zu CS = 0 ist wichtig. Wenn du CS dauerhaft auf 0 gelegt hast funktioniert das unter Umständen nicht.
>Jep, um die Chip Select-Leitung kuemmert sich die SPI-Library, die ich >verwende. Das wird korrekt auf 0 gezogen, Wie schön das man das in deinem Beispiel nicht sieht. Dann hätte ich mir meinen letzten Post sparen können.
Sorry, haette ich vielleicht dazu schreiben sollen. Hatte das im Kopf halt schon abgehakt, weil ich ja wusste, dass das korrekt gesetzt wird und deshalb gar nicht mehr dran gedacht.
>Sorry, haette ich vielleicht dazu schreiben sollen. Hatte das im Kopf >halt schon abgehakt, weil ich ja wusste, dass das korrekt gesetzt wird >und deshalb gar nicht mehr dran gedacht. Schon ok. Hast du das SPI auf die richtige Bitreihenfolge MSB First und SPI Mode 0 eingestellt? Auch das kann niemand sehen.
Ja, auch das ist beides der Fall. Bin langsam schon leicht genervt von dem Teil. Werde vielleicht morgen nochmal die Verkabelung durchtesten, aber das habe ich auch schon mehrfach getan und ich bin sehr sicher, dass da alles in Ordnung ist.
>dass da alles in Ordnung ist
Kannst du denn da wenigstens ein paar Pixel mit ner Farbe
beschreiben? Auslesen wär da das letzte was ich zuerst
versuchen würde.
Martin S. schrieb: > (die Variante mit 4 Leitungen; MISO, MOSI, > SCL und DC) Prüf mal, ob die Reset-Leitung verbunden werden muss/ist.
Also zumindest mein Code für den Controller beinhaltet einen Reset, der war imho auch vom Datenblatt vorgeschrieben.
Martin S. schrieb: > Zum Test der Kommunikation wuerde ich erstmal gerne einfach > die Hersteller-ID auslesen. Kann man machen, ich hab mit der Initialisierung angefangen. Dabei war es wichtig die Wartezeiten einzuhalten und den Controller aus dem Sleep-Mode zu holen:
1 | // funktionierende Initialisierung für einen ATmega168
|
2 | |
3 | void ili9341_init( void) |
4 | {
|
5 | uint32_t index; |
6 | |
7 | // reset als output
|
8 | ILI9341_RESET_DDR |= (1 << ILI9341_RESET_N); |
9 | // reset aktivieren
|
10 | ILI9341_RESET_PORT &= ~(1 << ILI9341_RESET_N); |
11 | // ports aktivieren ( 1 = output)
|
12 | ILI9341_DDR = (1 << ILI9341_CS_N) | (1 << ILI9341_D_C_N) | |
13 | (1 << ILI9341_SDI) | (1 << ILI9341_SCK) | |
14 | (1 << ILI9341_BACKLIGHT); |
15 | ILI9341_PORT = (1 << ILI9341_CS_N) | (1 << ILI9341_D_C_N); |
16 | ili9341_backlight( 1); |
17 | // spi aktivieren
|
18 | // master mode, fck/2
|
19 | // cpol = 0, cpha = 0, msb first
|
20 | SPCR = (1 << SPE) | (0 << DORD) | (1 << MSTR) | (0 << CPOL) | (0 << CPHA) | (0 << SPR1) | (0 << SPR0); |
21 | SPSR |= (1 << SPI2X); |
22 | |
23 | _delay_us( 10); |
24 | // release reset
|
25 | ILI9341_RESET_PORT |= (1 << ILI9341_RESET_N); |
26 | |
27 | |
28 | _delay_ms( 10); |
29 | ili9341_command( SLEEP_OUT); |
30 | // wait for 120 ms
|
31 | for( index = 120; index > 0; index--) |
32 | _delay_ms( 1); |
33 | |
34 | ili9341_command( DISPLAY_ON); |
35 | _delay_ms( 10); |
36 | // change orientation
|
37 | // and set color order
|
38 | ili9341_command( MEMORY_ACCESS_CONTROL); |
39 | #if ILI9341_ROTATE == 0
|
40 | ili9341_data( MEMORY_ACCESS_CONTROL_BGR | MEMORY_ACCESS_CONTROL_MX); |
41 | #endif
|
42 | #if ILI9341_ROTATE == 90
|
43 | ili9341_data( MEMORY_ACCESS_CONTROL_BGR | MEMORY_ACCESS_CONTROL_MV); |
44 | #endif
|
45 | #if ILI9341_ROTATE == 180
|
46 | ili9341_data( MEMORY_ACCESS_CONTROL_BGR | MEMORY_ACCESS_CONTROL_MY); |
47 | #endif
|
48 | #if ILI9341_ROTATE == 270
|
49 | ili9341_data( MEMORY_ACCESS_CONTROL_BGR | MEMORY_ACCESS_CONTROL_MY | MEMORY_ACCESS_CONTROL_MX | MEMORY_ACCESS_CONTROL_MV); |
50 | #endif
|
51 | |
52 | // set pixel format
|
53 | ili9341_command( PIXEL_FORMAT_SET); |
54 | ili9341_data( PIXEL_FORMAT_16BPP << 4 | PIXEL_FORMAT_16BPP); |
55 | |
56 | ili9341_clear_screen(); |
57 | }
|
58 | |
59 | |
60 | // switch backlight on or off
|
61 | void ili9341_backlight( uint8_t value) |
62 | {
|
63 | if ( value == 1) |
64 | ILI9341_PORT |= (1 << ILI9341_BACKLIGHT); |
65 | else
|
66 | ILI9341_PORT &= ~(1 << ILI9341_BACKLIGHT); |
67 | }
|
68 | |
69 | |
70 | // send a byte to the display controller
|
71 | void ili9341_out( uint8_t value) |
72 | {
|
73 | ILI9341_PORT &= ~(1 << ILI9341_CS_N); |
74 | SPDR = value; |
75 | while( !( SPSR & (1 << SPIF))); |
76 | ILI9341_PORT |= (1 << ILI9341_CS_N); |
77 | }
|
78 | |
79 | |
80 | // send a command to the display
|
81 | void ili9341_command( uint8_t command) |
82 | {
|
83 | ILI9341_PORT &= ~(1 << ILI9341_D_C_N); |
84 | ili9341_out( command); |
85 | }
|
86 | |
87 | |
88 | // send data to the display
|
89 | uint8_t ili9341_data( uint8_t data) |
90 | {
|
91 | ILI9341_PORT |= (1 << ILI9341_D_C_N); |
92 | ili9341_out( data); |
93 | return SPDR; |
94 | }
|
Martin S. schrieb: > Hallo zusammen, > > ich habe hier ein TFT-Display mit ILI9341-Controller liegen, den ich > ueber SPI ansteuern moechte (die Variante mit 4 Leitungen; MISO, MOSI, > SCL und DC). Hi Martin, ich hab jetzt nicht alles durchgelesen aber es gibt zwei Modes beim ILI9341 mit 4Wire-SPI (siehe Seite 10 vom Datasheet) dieser wird mit den 4 IM-Pins per Hardware festgelegt Mode "0110" ist der Betrieb im Half-Duplex-SPI (da ist Data-IN und Data-Out der gleiche PIN -> SDI !!) und Mode "1110" ist der Betrieb im Full-Duplex-SPI (da gibt es SDI für IN und SDO für OUT) eventuell ist dein Display im Mode "0110" und du bekommst aus dem Grund keine Daten zurück den gleichen "Fehler" hatte ich auch mit einem externen ILI9341-Display Uwe
Danke fuer die weiteren Tipps. Reset hatte ich tatsaechlich fest auf High gelegt. Habe das mal geaendert und die Reset-Sequenz durchgefuehrt, allerdings ohne, dass das was geaendert haette. Habe dann mal Deine, Klaus, Init-Sequenz uebernommen. Immerhin scheint was anzukommen, das Display wechselt von weiss auf grau und bekommt einen kleinen Streifen. Das mit dem Auslesen funktioniert allerdings nach wie vor nicht... warum auch immer. @Uwe: Ich war davon ausgegangen, dass es den 1110-Mode benutzt, da auf der Platine, auf der das Display sitzt, der SDO-Pin rausgefuehrt ist. War das bei Deinem Display auch der Fall?
:
Bearbeitet durch User
Nochmal als Rueckmeldung: Habe es geschafft, das Ding anzusteuern, die Leserei lasse ich jetzt halt. Ist nur leider brutal langsam, um das Display komplett zu beschreiben, braucht es bestimmt 20 Sekunden. Hat jemand konkrete Erfahrungen mit der SPI-Geschwindigkeit am Raspberry Pi? Kann man da noch was drehen?
@ Martin S. (tungl) >Hat jemand konkrete Erfahrungen mit der SPI-Geschwindigkeit am Raspberry >Pi? Kann man da noch was drehen? Vergiss diese SPI-Workaround und klemm ein LCD per HDMI oder LVDS mit Adapter an das Ding! Das geht wunderbar!
Den HDMI brauche ich noch fuer was anderes und auf dem kleinen SPI-Display sollen nur Informationen angezeigt werden, die vielleicht hoechstens einmal pro Minute aktualisiert werden. Die kann ich direkt als Bitmap abgreifen und ins Display schreiben, das funktioniert auch schon (bis auf die falschen Farben, aber das wird auch noch irgendwie zu beheben sein). Nur der Aufbauprozess nervt halt.
Martin S. schrieb: > Ist nur leider brutal langsam, Man kann die Dinger bereichsweise ansteuern. Das geht dann relativ schnell. Bei meinem 8 MHz Atmega /2,8"TFT dauert der komplette Bildaufbau ca. 1 bis 2 Sekunden. Für die Darstellung von Text ist die Geschwindigkeit des Displays völlig ausreichend.
Meinst du mit "bereichsweise", nur den Bereich neu zu beschreiben, der sich geaendert hat? Ist bei mir eher unpraktisch, da meistens eine Zeile dazukommt und dafuer die oberste wegfliegt und alle anderen nachruecken muessen. Ich glaube, dass es so langsam ist liegt weniger daran, dass es SPI ist, sondern dass der RPi da verdammt lahm ist. Ich habe auch ein Monochromes-Grafikdisplay (DogL128) dran haengen und selbst da geht der Aufbau relativ langsam, obwohl da ja nur ein Bruchteil der Daten geschaufelt werden muss).
:
Bearbeitet durch User
1 | |
2 | void lcd_clear(u16 Color) |
3 | {
|
4 | unsigned int i,m; |
5 | Lcd_SetRegion(0,0,MAX_X-1,MAX_Y-1); |
6 | for(i=0;i<MAX_Y;i++) |
7 | for(m=0;m<MAX_X;m++) |
8 | {
|
9 | Lcd_WriteData(Color>>8); |
10 | Lcd_WriteData(Color); |
11 | }
|
12 | curposx=0; |
13 | curposy=MAX_Y; |
14 | }
|
Bereichsweise heißt, du sagst ihm wo er anfangen soll und gibst dann nur noch die Farben ein. Es wird also nicht ein einzelnes Pixel gezeichnet sondern eine Reihe von Pixeln hintereinander. Dass ein Atmega-spi wesentlich schneller ist als ein Pi-spi, kann ich mir nicht vorstellen.
Ok, danke fuer das Beispiel. > Dass ein Atmega-spi wesentlich schneller ist als ein Pi-spi, kann ich > mir nicht vorstellen. Genau das denke ich mir auch. Ich weiss aber auch nicht, wie man da noch was einstellen koennte. Die Dokumentation ist irgendwie grausig.
@ Martin S. (tungl)
>Nur der Aufbauprozess nervt halt.
Nun ja, wie steuerst du das Ding denn an? Wahrscheinlich über eine
Scriptsprache ala Phyton und SPI. Dass das langsam wie Sau ist, ist kein
Wunder. Wenn man das SPI vom Prozessor mit Volldampf fahren könnte (z.B.
über einen gescheiten Kerneltreiber), wäre ein Update in 1s kein Thema.
Denn ein Bild hat ja bekanntlich 240x320 Punkte bei 16 Bit Farbtiefe,
macht
172800 Bytes. Bei 8 Mbit/s SPI Geschwindigkeit ist somit ein Bild in
~180ms geladen. WENN die Software was taugt. Und 8 MHz ist nicht das
Ende der Fahnenstange, das LCD macht bis zu 10 MHz mit, also nachmal 20%
schneller.
Der Himbeerkuchen kann das auch, rein von der Hardware her.
@ leluno (Gast) >Dass ein Atmega-spi wesentlich schneller ist als ein Pi-spi, kann ich >mir nicht vorstellen. Die reine Hardware nicht, die Software schon! Klingt komisch, ist aber so! Das sind die Grenzen der seeligen Arduino-Philosophie!
Soweit klar, deswegen meine Frage nach konkreten Erfahrungen. Denn es gibt anscheinend einen Kernel-Patch bzgl. der SPI-Latenzen auf dem RPi. Bevor ich jetzt aber den Kernel selber kompiliere, wuerde ich doch gerne wissen, ob es nicht eher an Python liegt. Andersrum genauso, bevor ich das jetzt in C umschreibe bzw. keins von beidem helfen wuerde.
leluno schrieb: > Dass ein Atmega-spi wesentlich schneller ist als ein Pi-spi, kann ich > mir nicht vorstellen. Beim Raspi ist noch ein riesiger Overhead dabei. Leider. Ein Kernelmodul für das Display wäre da wahrscheinlich die eleganteste Variante. Martin S. schrieb: > Bevor ich jetzt aber den Kernel selber kompiliere, wuerde ich doch gerne > wissen, ob es nicht eher an Python liegt. Ich würde den Kernelpatch probieren. Klingt nach weniger Aufwand. Bei Gordon findet sich was zu den erreichbaren SPI-Geschwindigkeiten: http://projects.drogon.net/understanding-spi-on-the-raspberry-pi/ Und eine Art Datenblatt gibt es auch: http://www.raspberrypi.org/wp-content/uploads/2012/02/BCM2835-ARM-Peripherals.pdf Klaus
Wen es interessiert bzw. wer irgendwann mal vor dem gleichen Problem steht: Bis jetzt habe ich die py-spidev Library verwendet. Damit war die Kommunikation, wie bereits angemerkt, extrem langsam. Zudem enthaelt diese Bibliothek anscheinend ein Memory Leak. Nach ca. einem Tag ist der Speicher komplett vollgelaufen und das Programm verabschiedet sich. Genervt davon verzichte ich jetzt auf py-spidev und oeffne '/dev/spidev0.0' jetzt direkt als File Handle. Der Bildaufbau dauert jetzt nur noch 1-2 Sekunden und der Speicher laeuft auch nicht mehr voll. Hinterher ist man immer schlauer. ;-)
> Das mit dem Auslesen funktioniert allerdings nach wie vor nicht... warum > auch immer. Ich verdiene mir mal den Goldenen Spaten. Ich habe ebenfalls versucht ein Display mit dem ILI9341V auszulesen. Auch das Display Identification Register 0x04. In dem steht bei mir nichts drin! Keine LCD Modus Manufacturer ID, keine Driver Version ID, keine Driver ID. Nur Nullen. Insofern kommt auf SDO eine Flatline raus, die halt nicht "geht nicht" sondern "steht nichts drin" heisst. Ein Versuch mit einem anderem Register, dem 0x09 oder dem 0x0A hat funktioniert. Es kamen ein paar vereinzelte Bits an, die zum Status passten und mir sagten, dass das Display im "Normal Mode" ist. Ich habe den "4-wire 8-bit data serial interface II"-Modus genommen (S. 26) IM[3:0] sind 1110.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.