Guten Abend,
Ich habe an einem Raspberry Pi Zero W ein 2.8 Zoll TFT Display verbaut
mit ILI9341 als Controller. Ich weiß man könnte auch ein HDMI Display
dran anschließen etc.. und eigentlich ist der RasPi auch absolut
Overkill aber egal.
Das Display anzusteuern ist absolut kein Problem zumindest wenn es um
das beschreiben des Displays geht das funktioniert nämlich super. Ein
teil der GUI läuft ja auch schon auf dem Display. Verwendet wird der AUX
SPI1 des Raspberry Pis. Angeschlossen habe ich alle Leitungen wie
CS,D/C,SCK,MOSI,MISO,RESET. Es ist ein Display mit XPT2046
Touchcontroller welcher ebenfalls angeschlossen ist und ohne Probleme
funktioniert. Gelesen wird auch nur mit 8MHz! SPI Frequenz darf ja
eigentlich auch nicht mehr als 10MHz betragen ...
Kommen wir zum Problem: Ich möchte gerne aus dem internen Grafikspeicher
des ILI9341 Pixel auslesen um ein bestimmten Bereich wieder herzustellen
nachdem eine Eingabe vom Nutzer erfolgt ist. Das Problem ist das ich
zwar den Pixel lesen kann jedoch nur einmal danach kann ich ruhig
irgendein anderen Pixel versuchen zu lesen es wird jedoch immer der Wert
des zuerst gelesen Pixel zurückgeben. Also das pixel lesen vom Display
funktioniert teilweise.
Ich habe auch versucht zB. die ID4 auszulesen(Gibt dann ja 0x9341
wieder) jedoch bekomm ich da nur 00 00. Nie etwas anderes.
Mit einem STM32 Nucleo Board und der eTFT Library hab ich es auch nicht
geschafft die ID4 auszulesen andere Befehle(Auch aus der Level1
Befehlsgruppe) funktionieren ebenfalls nicht.
Ich muss sagen ich verstehe das Datenblatt auch da nicht so ganz. Es
gibt Serial Interface I und II welche durch die IM Pins fix kodiert
sind, wie die bei diesem Display beschaltet sind? Keine Ahnung. Da aber
der SDO(MISO) Pin rausgeführt ist gehe ich von 4-wire Serial Interface
II aus mit D/C als Pin und nicht als Bit.
Geschrieben ist das Programm in C mit der BCM2835 library um die
Prozessorfunktionen anzusteuern. Ich hab auch mal aufm Logic analyzer
geschaut was dort so ankommt jedoch passt das von der Übertragung nur
der ILI9341 gibt einfach keine Daten zurück.
Hier mal die readPixel funktion:
1
void ili9341_readPixel(uint16_t x, uint16_t y) {
2
bcm2835_gpio_fsel(RPI_BPLUS_GPIO_J8_36, BCM2835_GPIO_FSEL_OUTP); //Manual CS control - To keep CS continues low during the operation
ili9341_writeCommand(0xD3); //Command 0xD3 read ID4 - writeCommand sets DC to low for command.
7
8
ili9341_readByte(); //Dummy read - readBytes set D/C to high for data
9
ili9341_readByte(); //First data byte all zeros
10
uint8_t id1 = ili9341_readByte(); //ID part 0 (should be 0x93)
11
uint8_t id2 = ili9341_readByte(); //ID part 1 (should be 0x41)
12
13
bcm2835_gpio_write(RPI_BPLUS_GPIO_J8_36, HIGH); //CS High
14
bcm2835_gpio_fsel(RPI_BPLUS_GPIO_J8_36, BCM2835_GPIO_FSEL_ALT4); //Back to auto CS
15
16
printf("ID is: %X %X\r\n", id1, id2);
17
}
Hab mich bereits auch schon schlau gelesen das es scheinbar Probleme mit
dem auslesen im SPI Modus gibt hab jedoch nichts gefunden war für mich
hilfreich gewesen ist. Die IM pins scheinen ja wohl richtig zu sein wenn
man mit readPixel einmalig arbeitet kommen ja auch die richtigen Daten
von dem Pixel an X,Y zurück so wie es soll nur funktioniert readPixel
kein zweites mal obwohl die Daten richtig zum Display gesendet werden
das Display antwortet einfach neuert mit den gleichen Daten.
Ich komm da nicht mehr hinter was da los ist. Hat einer vielleicht von
euch ne Idee woran es liegen könnte?
Mfg und schönen Abend noch
Warum benutzt du keinen Framebuffer-Treiber?
Den hab ich schon mehrfach für ili9341 genutzt, und der funktioniert
ganz hervorragend, und das mit jeder Software, die Framebuffer
unterstützt.
https://github.com/notro/fbtft/wiki
Harry L. schrieb:> Warum benutzt du keinen Framebuffer-Treiber?
Hallo,
Framebuffer-Treiber? Das heißt das Display wird zum Hauptdisplay/Monitor
für das Linux Betriebssystem auf dem Raspberry? Falls ja ist das nicht
gewollt. Zumal ich eh nur eine Raspbian Version ohne Grafische
Oberfläche verwende und alles andere via SSH mache.
Das Projekt sollte ursprünglich auf einem STM32F446RE umgesetzt werden
da ich aber auch noch ein RF Signal erzeugen muss im Bereich von 170MHz
war dieses auf einem Raspberry mit Hilfe des rpitx Programm leichter
umzusetzten als mit externer Hardware zum STM32 dazu und da der Preis
unterschied zwischen einem Nucleo 64 Board(16€) und dem Raspberry Pi
Zero(22€) nicht so groß war hab ich mich dieses mal für den Raspberry
entschieden.
An sich könnte ich auch auf die lese Funktionen des ILI9341 verzichten
in dem ich einfach ein 16 Bit Array anlege mit einer Größe von 320x240.
Dann hätte ich den Grafikspeicher selbst im Arbeitsspeicher des
Raspberrys(Der Pi hat ja mehr als genug RAM für sowas) und die
Grafikfunktionen wie drawPixel, drawRect fillRect ... schreiben dann
halt nicht nur auf das Display via SPI sondern halt auch noch in dieses
Array mit rein. In Bezug auf Geschwindigkeit beim auslesen der Pixels
geht dann nicht mehr schneller :) Als alle Daten wieder via SPI
abzufragen.
Nur es hatte mich halt verwundert das ich halt so gut wie keine Daten
vom Display via SPI beziehen kann obwohl dieses eigentlich möglich
seinen müsste. Mit einem ILI9486 den ich mal im 8-Bit Parallel Modus
angesteuert hatte war das kein Problem alle Register auszulesen. Mit dem
ILI9341 im SPI Interface hab ich es noch nicht wirklich geschafft es
auszulesen.
Aber das scheint ja wohl ein Problem zu sein das andere auch haben mit
dem Auslesen im SPI Modus des Displays. Beiträge gibts dazu ja genug
teilweise auch mit Codebeispielen mit diesem Ominösen 0xD9 Befehl der ja
offiziell nicht mal dokumentiert(Bei der Adafruit lib für den ILI9341
ist er als "Woo sekret command?" kommentiert) ist im Datenblatt(Er
funktioniert bei mir auch nicht) aber anderen scheint der wohl geholfen
zu haben Register auszulesen.
Mfg
Felix N. schrieb:> Kommen wir zum Problem: Ich möchte gerne aus dem internen Grafikspeicher> des ILI9341 Pixel auslesen um ein bestimmten Bereich wieder herzustellen> nachdem eine Eingabe vom Nutzer erfolgt ist.
Wenn das Limitierende die SPI-Geschwindigkeit ist, ist's vermutlich
schneller einfach den Bereich neu zu Zeichnen, ohne vorher nachzuschauen
welche Pixel sich geändert haben.
Felix N. schrieb:> An sich könnte ich auch auf die lese Funktionen des ILI9341 verzichten> in dem ich einfach ein 16 Bit Array anlege mit einer Größe von 320x240.> Dann hätte ich den Grafikspeicher selbst im Arbeitsspeicher
Du kannst dir auch anschauen, wie das z.B. lvgl gelöst hat. Das braucht
keinen kompletten Framebuffer im RAM, aktualisiert nur geänderte
Bereiche, und organisiert die Updates so, das man sie einfach per DMA
zum Display schieben kann. Optional mit zwei Buffern, damit der eine
berechnet werden kann, während der andere gerade rausgeschrieben wird.
Felix N. schrieb:> Framebuffer-Treiber? Das heißt das Display wird zum Hauptdisplay/Monitor> für das Linux Betriebssystem auf dem Raspberry?
Nein, das bedeutet nur, daß Deine Software ein Abbild des
Bildschirmspeichers des Displays vorhält, und jeden Schreibvorgang
sowohl auf das Display als auch auf dieses Abbild durchführt. Bei
Lesezugriffen aber wird nicht auf das Display, sondern dieses Abbild
zugegriffen.
Es ist auch oft schneller, den kompletten Puffer an das Display zu
senden als einzelne Pixel zu adressieren, so kann auch das Beschreiben
nur über das Abbild erfolgen, während eine wo auch immer laufende
Funktion zum Aktualisieren des Displays angestoßen wird, die (z.B. via
DMA) den Puffer an das Display rausschaufelt.
ID4 auslesen geht nicht: Ja, das ist bei manchen Displaymodulen
"normal". Es hängt vom Leiterplatten-Layout ab (Siehe Datenblatt,
Stichwort "extended command list").
meistens machen aber da die Displays mit parallelem Interface Probleme,
für die Arduino Kompatibilität haben die Levelshifter für 5V drauf und
die sind meist nicht bidirektional. Bei dem SPI gibt es noch die
Variante SDA oder SDI/SDO, aber wenn diese Signale am Stecke so heißen
dann sollte das eigentlich auch so konfiguriert sein (IM3=1).
Beim eTFT ist ein Beispiel ScreenCapture dabei, das soll mit ILI9341 und
STM32 laufen. Die Vielfalt an ILI9341 Displayboards ist aber recht groß.
Aber da es das Display nur langsam macht und die Ausgaben flackern wenn
man pixelweise Bereiche überschreibt, mache ich das auch nur noch mit
Framebuffer. Und auch mit lvgl, für Raspberry gibt es da auch Beispiele:
https://github.com/lvgl/lv_port_linux_frame_buffer
Felix N. schrieb:> Das Problem ist das ich> zwar den Pixel lesen kann jedoch nur einmal danach kann ich ruhig> irgendein anderen Pixel versuchen zu lesen es wird jedoch immer der Wert> des zuerst gelesen Pixel zurückgeben.
Nachtrag: Ich habe mir Dein Timing noch nicht genau angeschaut, aber was
mir mal aufgefallen ist: Beim Schreiben vertragen die ILI9341, die nativ
über SPI angesteuert werden (es gibt auch welche, die Parallel mit zwei
Schieberegistern am SPI angeschlossen sind :( ), eine deutlich höhere
Datenrate als beim Lesen.
Felix N. schrieb:> void ili9341_readPixel(uint16_t x, uint16_t y) {> //Set read address> ili9341_writeCommand(0x2A);> ili9341_writeDataDWord((x << 16) + x); //32-Bit> ili9341_writeCommand(0x2B);> ili9341_writeDataDWord((y << 16) + y); //32-Bit> ili9341_writeCommand(0x2E); //Read from GRAM
Du setzt hier ein 1x1 Pixel großes Fenster und liest dann dieses eine
Pixel aus.
Ich habe dich so verstanden dass du ganze Bereiche des Displays lesen
willst. Dann setze doch mal ein größeres Lesefenster und lese alle
Pixel(Bytes) in einem Rutsch aus. Vielleicht funktioniert das besser?
Εrnst B. schrieb:> Wenn das Limitierende die SPI-Geschwindigkeit ist, ist's vermutlich> schneller einfach den Bereich neu zu Zeichnen, ohne vorher nachzuschauen> welche Pixel sich geändert haben.
Geschwindigkeit ist tatsächlich nicht das Problem naja das SPI Interface
ist im Verhältnis zum Parallel betrieb natürlich deutlich langsamer.
Offiziell sind es laut Datenblatt nur max 10MHz an SPI Takt erlaubt.
Wobei die Frequenz selbst garnicht angegeben ist sondern nur die
maximale Periodendauer von 100ns? Das wären ja dann 10MHz.
Da der AUX SPI1 Bus am Raspberry vom APB Bus angetrieben wird welcher
auf 250MHz laufen sollte und kann man mit dem Prescaler von 2 bis 65536
fast alles einstellen. Wobei der Entwickler der BCM2835 C Bibliothek zu
nicht mehr als über 60MHz rät da wohl dann die MISO/MOSI Leitungen
anfangen zu schwingen. 62.5MHz funktionieren bei mir aber ganz gut
Ich habe die maximale Geschwindigkeit des Displays mal ausgetestet. Bis
62,5MHz läuft das Display problemlos und ohne Pixelfehler bei 80MHz
werden teilweise rote Pixel falsch dargestellt. Bei 125MHz(Prescaler 2)
nun ja es kommt alles an aber alles im bunten Farbenmischmasch :)
Lesen tute ich aber nur mit 8MHz tatsächlich macht es aber kein
Unterschied ob ich mit 62.5MHz die Lesebefehle ausführe oder mit 8MHz es
kommt wenn was zurückkommt immer das gleiche zurück.
Harald K. schrieb:> Bei> Lesezugriffen aber wird nicht auf das Display, sondern dieses Abbild> zugegriffen.
Diese Idee hatte ich ja auch schon mal oben erwähnt gehabt hat natürlich
auch ein gewaltigen Geschwindigkeitsvorteil:
Felix N. schrieb:> An sich könnte ich auch auf die lese Funktionen des ILI9341 verzichten> in dem ich einfach ein 16 Bit Array anlege mit einer Größe von 320x240.> Dann hätte ich den Grafikspeicher selbst im Arbeitsspeicher des> RaspberrysHarald K. schrieb:> Es ist auch oft schneller, den kompletten Puffer an das Display zu> senden als einzelne Pixel zu adressieren
Ein komplettes löschen bei 62.5MHz dauert ca. 47ms bei diesem Display.
Es ist schnell man sieht es auch noch auf dem Display es ist aber
vertretbar und ich habe kein Problem damit das man es kurz sieht das
sich das Display ändert.
Wenn ich dann bestimmte Bereiche ändern will zB. oben linkes wird die
Uhrzeit dargestellt dann schreibe ich nur den Text an der entsprechenden
Stelle neu das geht dann so brutal schnell weil der adressierte Bereich
relativ klein ist das man das nicht sieht das sich da was geändert hat.
Also kein flackern zu erkennen.
Walter T. schrieb:> Es hängt vom Leiterplatten-Layout ab
Ja das hab ich auch schon mehrmals gelesen im Netz. Hat ja zum Teil auch
was mit diesen IM pin zutun. Da das Display aber ein SDI sowie SDO pin
hat und aus dem SDO pin die richtigen Daten teilweise rauskommen denke
ich das IM=1110 sind wird sprich "4-wire 8-bit data serial interface Ⅱ"
Weil dann hätte ich folgende Pins zur Ansteuerung des Displays:
SCL,SDI,D/CX,SDO, CSX
Und das sind auch die Pins die am Display rausgeführt sind.
Walter T. schrieb:> Siehe Datenblatt,> Stichwort "extended command list"
Tatsächlich kann ich den Punkt "Extended command list" nicht im
Datenblatt finden
https://cdn-shop.adafruit.com/datasheets/ILI9341.pdf
Ich verstehe aber auch nicht was die Unterschied zwischen den
sogenannten "Level1" und "Level2" Befehlen ist. Also das die genau von
einander unterscheidet, bzw kann ich im Datenblatt nichts finden oder
habs überlesen :P. Read ID4 gehört zu den Level2 Befehlen. Aber auch die
Level1 befehle wie Read ID1(0xDA) oder Read Display Identification
Information(0x04) bekomm ich keine Antwort vom Display mit sinnvollen
Daten in der regel ist alles 0x00.
Ich bin aktuell noch nicht Zuhause kann später nochmal ein Bild vom
Logic analyzer hochladen bei den Level1 befehlen.
J. S. schrieb:> Beim eTFT ist ein Beispiel ScreenCapture dabei, das soll mit ILI9341 und> STM32 laufen. Die Vielfalt an ILI9341 Displayboards ist aber recht groß.
Ah ok das ist interessant werde ich heute Nachmittag mal ausprobieren,
dazu berichte ich noch später!
Thomas F. schrieb:> Du setzt hier ein 1x1 Pixel großes Fenster und liest dann dieses eine> Pixel aus.
Genau weil die Funktion readPixel() von einen Pixel auslesen soll.
Später wollte ich noch eine readPixels() Funktion machen.
Das komische ist ja wenn zB. readPixel(0, 0) mache und dort der Pixel
rot ist dann bekomme ich 0xF800 zurück -> PASST!
Wenn ich dann nochmal später im Programm readPixel(10, 10) mache zB. und
der Pixel weiß ist bekomme ich trotzdem 0xF800 zurück immer das was
zuvor mit dem ersten readPixel gelesen wurde. Lasse ich das erste
readPixel(0, 0) weg und hab somit nur readPixel(10, 10) drin stehen dann
bekomme ich als Resultat 0xFFFF was korrekt ist wenn ich aber danach
nochmal readPixel(0, 0) der ja rot ist bekomme ich wieder 0xFFFF.
Absolut komisch. Ich lad nachher nochmal ein Bild vom Logic analyzer
hoch
Thomas F. schrieb:> Ich habe dich so verstanden dass du ganze Bereiche des Displays lesen> willst. Dann setze doch mal ein größeres Lesefenster und lese alle> Pixel(Bytes) in einem Rutsch aus. Vielleicht funktioniert das besser?
Ja will ich später auch das ist korrekt. Ich werde das nachher mal
ausprobieren mal schauen was da rauskommt.
Für den Tipp mit lvgl das schaue ich mir mal die Tage an.
Mfg
Felix N. schrieb:> Tatsächlich kann ich den Punkt "Extended command list" nicht im> Datenblatt finden
Seiten 11 und 85. Hier heißt es wohl "Extended Command Set", bei einigen
ILI9xxxx-Schwester-Bausteinen heißt die Tabelle "Extended Command List".
24 MHz SPI-Takt bei bei mir (STM32F446RE) immer deutlich zu schnell beim
auslesen. Schreiben ging, fürs lesen musste ich heruntertakten, ich
glaube auf 12 MHz. (Bei den Zahlen bin ich mir nicht 100% sicher - ich
habe nur noch im Kopf, dass Schreiben doppelt so schnell wie lesen ging.
Nachgucken kann ich erst heute abend.)
So Hallo nochmal,
Walter T. schrieb:> Extended Command List
Ah okay ja dann hab ich es wohl einfach übersehen. Achso das wird also
durch den EXTC pin per Hardware bestimmt ob man die Register auslesen
kann. Nun ja gut das ich jetzt sagen kann das ich es tatsächlich
geschafft habe die ID4 auszulesen und zwar mit diesem unbekannten 0xD9
Command.
Er ist zwar nicht dokumentiert und auch in einem älteren
Datenblatt(V1.01) ist dieser Befehl nicht aufgelistet. Meine Vermutung
ist das dieser Befehl aus einen Register Daten extrahiert. Weil man muss
nachdem 0xD9 Befehl noch ein index mitschicken. Die eTFT Library hat
diesen Befehl als readCommand8() implementiert. Wenn ich den Befehl
jetzt auf 0xD3(Read ID4) anwende mit Index 2 und 3(Für Byte 2 und 3)
dann bekomme ich für Index 2 = 0x93 und für Index 3 = 0x41.
Also die ID4. Bei Level1 Befehlen wie zB. Read Display ID Infos(0x04)
funktioniert er nicht dort kommt einfach nur 0x00 wieder zurück.
J. S. schrieb:> Beim eTFT ist ein Beispiel ScreenCapture dabei, das soll mit ILI9341 und> STM32 laufen.
Das das läuft tatsächlich! Ich habs auf einem STM32F446RET6 gespielt und
siehe im Anhang die Pixel konnten ausgelesen werden und mittels
Processing 4.3 dargestellt werden. Also das Display kann schon Daten
ausgeben!
Thomas F. schrieb:> Vielleicht funktioniert das besser?
Jein, also ich habe jetzt eine readPixels() Funktion hinzugefügt welche
ein Block an pixels ließt. Das gute zu erst es funktioniert und die
Pixeldaten stimmten auch, jetzt das schlechte wird die Funktion über den
genau gleichen Pixelblock nochmal ausgeführt kommen andere teilweise
korrekte Daten zurück siehe Bild "Output" von der SSH Konsole.
Das verstehe ich halt nicht. Ich habe per Logic analyzer überprüft ob da
was falsch gesendet aber wird es nicht die Adresse etc... wird alles
korrekt wie beim ersten readPixels korrekt übertragen. Nur das Display
antwortet komplett anderes.
Auch mit der readPixel Funktion wird es nicht besser. Der erste
readPixel Funktion Aufruf liefert korrekt die richtigen Pixeldaten der
zweite liefert die gleichen vom ersten readPixel obwohl der Pixel an der
angegeben X,Y komplett andere Werte hat. Und der dritte Aufruf liefert
was komplett falsches.
Ich habe das Gefühl das der interne address pointer im ILI9341 selbst
nicht zurückgesetzt wird wenn man die Adresse neu schreibt mit 0x2A und
0x2B. Hab aber auch nichts darüber gefunden das man das nach einem Read
zurücksetzten muss oder so.
Auch die readPixel und rectRectRGB Funktionen aus der TFT_eSPI Library
sind gleich aufgebaut wie meine machen aber auch nichts anderes.
Was mir noch aufgefallen ist im Logic analyzer, was ich mir auch nicht
erklären kann, sobald das Display einmal Daten geschickt hat egal welche
werden diese IMMER bei einem Transfer wieder auf der MISO gesendet siehe
dazu den Anhang "setAddr MISO Daten" dort wird der Befehl 0x2A also die
Adresse gesetzt sobald der D/C pin auf Daten schaltet und die
eigentliche Adresse kommt(0x0A und 0x13) wird auf MISO wieder 0xFC
ausgegeben und beim nächsten Befehl von 0x2B wieder.
Das kann doch nicht richtig sein, da dürfte der Controller eigentlich
gar nicht antworten, auch im Datenblatt ist vermerkt das dort keine
Daten zurückgeben werden.
Ich hatte eben nochmal kurz in den Code für den ILI9486 welcher auf
einem STM32 läuft reingeschaut. Das Display war im 8-Bit 8080 parallel
Modus angesteuert. Da hatte ich den Code so geschrieben das bevor das
Display überhaupt initialisiert wird erstmal die ID4 ausgelesen wird um
zu bestätigen das es das richtige Display ist. Dort habe ich das aber
ganz normal gemacht wie es das Datenblatt vorsieht 0xD3 als Befehl
senden. Einen Dummyread danach 3x reads und dann hatte ich meine ID, hat
immer funktioniert nie Probleme gemacht das Ding ist beim Kollegen seit
knapp 1 Jahre als Hardware Monitor im Einsatz.
Hier nochmal der Code der ausgeführt wird in der main und die Ausgabe in
der Konsole erzeugt:
1
//Read Level2 command "Read ID4" returns 0x9341
2
ili9341_readRegister(0xD3, 2); //Returns 0x93 Byte 2 of 0xD3
3
ili9341_readRegister(0xD3, 3); //Returns 0x41 Byte 3 of 0xD3
Felix N. schrieb:> So Hallo nochmal,
Ausdrücklichen Dank an dich für die Hinweise zum Auslesen
der Display-Identifikation. Funktioniert, wäre ich nicht
draufgekommen. Endlich kann ich das auch mal ....
Guten Abend nochmal an alle,
Ich habe heute nochmal ein bisschen weiter experimentiert mit dem
Display und vergesst mal fast alles was ich im letzten Beitrag bzgl.
readPixel und readPixels geschrieben habe.
Ich habe hier 2 gleiche Display(Zumindest dachte ich dieses) vom Typ
ILI9341 liegen sehen exakt gleich aus wie auf dem Bild was ich
hochgeladen habe. Beide habe ich 2018 auf Amazon bestellt kamen auch
beide vom gleichen Verkäufer in einem Paket das weiß ich noch.
Nur hatte ich eins am Raspberry angeschlossen und das andere(War sogar
noch eingeschweißt in der ESD Verpackung) am STM32 angeschlossen. Weil
dachte es seien beide gleich. Nun ja das Display welches eingeschweißt
war funktioniert am STM32 perfekt und auch am Raspberry funktioniert es
so wie es soll heißt die oben beschreibenden Probleme mit readPixel und
readPixels treten nicht mehr auf! Das andere Display funktioniert am
STM32 nicht richtig! Das screenshot capture Skript läuft nicht sauber
durch teilweise werden gar keine Pixel geladen manchmal nur halb ... Es
scheint wohl so als wäre das Display defekt zumindest was das lesen
angeht. Beim darstellen von Pixeln und beschreiben von Registern scheint
es keine Probleme zu geben die wären sonst in den letzten 2 Wochen
aufgefallen beim Testen
Toll hat jetzt nur fast 3 Tage gedauert um das herrauszufinden.
Ich habe noch eine Anmerkung zu dem Memory Read(0x2E) Befehl. Es steht
nicht direkt beim Memory Read Command drin sondern beim NOP
Command(0x00) wenn man fertig ist mit lesen beendet JEDER Befehl laut
Memory Read Beschreibung den Lesevorgang man kann ein NOP senden(Vllt.
soll man das auch?) um das lesen zu stoppen. Das gleich gibt auch für
den Memory Write(0x2C) Befehl..
Ich habe nachdem ich die Pixeldaten in readPixel und readPixels fertig
gelesen habe nochmal ein NOP Befehl gesendet, danach bliebt das ominöse
Verhalten der MISO Leitung(Siehe Anhang letzter Beitrag setAddr MISO
...) weg. Sie gibt also nicht mehr die selben Daten bei jeden
Befehl/Daten aus -> TOLL!
Das ID lesen bleibt mir noch immer ein Rätsel vllt. kann ja einer von
euch das mal für mich ausprobieren mit seinem ILI9341 Display und
schauen ob er was anderes bekommt. Es geht dabei um den Befehl 0x04.
0x04 ist "Read display identification information" und sendet in der
Theorie laut Datenblatt ein Dummy und 3x IDs. Die drei ID's bekommt man
aber auch mit Read ID1(0xDA), Read ID2(0xDB) und Read ID3(0xDC). Und es
handelt sich dabei um USER IDs. Der 0x04 Befehl scheint die IDs somit
nur als ein Befehl auszugeben in der Theorie.
Heißt man muss die selber Programmieren mit dem NV Memory Befehlen!
Standardmäßig sind ID1 = 0x00 und ID3 = 0x00. Bei ID2 bin ich mir nicht
sicher es soll sich da um eine Revision ID handeln im Bereich von 0x80
bis 0xFF. Ob jetzt jedoch der Default Value von ID2 = 0x80 ist bin ich
mir nicht sicher ich würde sagen laut Datenblatt ja.
Aber ich lese da immer nur 0x00 zurück. Egal ob direkt oder mit diesem
geheim 0xD9 Befehl ...
Vielleicht kann ja jemand das von euch mal testen was er bei dem
Read-ID2 Befehl bekommen würde.
Ich habe auch alle anderen Lesebefehle die so direkt mit "Read ..." im
Datenblatt gestanden ausprobiert. Zb. liefert mit der 0x0C Befehl (Read
Display Pixel Format) 0x05 zurück. Was 16bit/pixel entspricht und auch
passt.
Jedoch ist mir da eins aufgefallen laut Datenblatt ist das erste Byte
ein Dummy-Read und enthält keine Daten erst das zweite Byte enthält die
Daten. Komischerweise ist es bei mir genau anderes rum. Das "Dummy-Byte"
laut Datenblatt enthält bei mir die 0x05 und das zweite Byte nix. Ich
kann auch nur ein Byte lesen(Sprich laut DB das "Dummy Byte") und
bekomme die richten Daten.
Das gleiche trifft auch auf die Read Display Status/Power/Image Befehle.
Ich bin mir auch nicht sicher ob man jedes Register lesen darf. Zum
Beispiel bei dem "Positive Gamma Correction(0xE0)" Register dort
schreibt man ja beim Init die Gamma Werte rein. Wenn ich das jetzt lesen
würde via SPI muss ich ja ein Byte senden um eins zu empfangen das würde
ja bedeuten das ich die vorherigen Daten überschreibe also kann ich das
eigentlich nicht auslesen. Mit dem 0xD9 Befehl geht das dann aber wieder
doch. Wenn ich den Sende und auf das Gamma Register anwende und den
Index entsprechend setzte werden mir die Werte wiedergeben welche ich
zuvor beim Init festgelegt habe ins Register.
Also erstmal danke an euch die mir geholfen haben, das Thread ist
hiermit eigentlich erledigt. Pixel auslesen geht und die ID4 lesen geht
auch. Vielleicht hilft dem einen oder anderen dieser Beitrag ja auch
weiter. Ganz zu 100 % Zufrieden bin ich zwar nicht da ich noch nicht
alles so ganz zu 100 % nachvollziehen kann. Ist aber so.
Vielleicht kann ja der ein oder andere wenn er Lust dazu mal die Punkte
die ich angesprochen habe bei sich ausprobieren würde mich echt mal
interessieren wie gut das Sachen bei euch funktionieren gerne auch mit
einem 8-Bit 8080 parallel interface :) Aber ist kein muss!
Mfg und schönen Abend noch.
Felix N. schrieb:> Ich bin mir auch nicht sicher ob man jedes Register lesen darf.
Darfst du auch nicht. Jedes Kommando ist auf Lesen oder
Schreiben ausgelegt, nicht für beides.
Felix N. schrieb:> Beispiel bei dem "Positive Gamma Correction(0xE0)" Register dort> schreibt man ja beim Init die Gamma Werte rein.
Genau das. Schreiben, nicht lesen. Dass es hintenrum anders doch
zu lesen geht ist dann ein anderes Thema.
Felix N. schrieb:> Wenn ich das jetzt lesen> würde via SPI muss ich ja ein Byte senden um eins zu empfangen das würde> ja bedeuten das ich die vorherigen Daten überschreibe also kann ich das> eigentlich nicht auslesen.
An diesem Punkt hast du SPI nicht verstanden. Ein SPI Schreiben
ist auch immer ein Lesen. Es ist ein Transfer in beide Richtungen.
Erst der Kontext bestimmt ob im Lese- oder im Schreib-Register
etwas sinnvolles drinsteht.
Beispiel: wenn du 0xE0 kommandierst bekommst du im Lese-Register
auch etwas zurück was aber nicht von Bedeutung ist. In C würde
man "undefined behaviour" sagen. Wenn du in die Parameter-Liste
des Kommandos schaust wirst du dort kein einziges Byte finden
das du lesen kannst, nur schreiben. Das virtuelle Read-Signal
(RDX) ist immer inaktiv (statisch 1).
Umgekehrt musst du - um ein Byte zu lesen - immer auch ein Byte
schreiben. In diesem Fall (im richtigen Kontext) ist der Wert
des geschriebenen Bytes ohne Bedeutung.
Dass man die geschriebenen Daten des Kommandos trotzdem
("hintenrum") lesen kann hast du ja offenbar herausgefunden,
nur geht das eben nicht mit dem Kommando 0xE0 da das ein
Schreib-Kommando ist.
Wastl schrieb:> Jedes Kommando ist auf Lesen oder> Schreiben ausgelegt
Guten Morgen,
Macht ja auch irgendwie nur sinn. Ich bin es tatsächlich ein wenig
gewohnt in Datenblätter eine Angabe direkt unter dem Bit haben ob es
Read Only(R) oder Read-Write(RW) ist :O. Aber klar hier wird es mit dem
RDX und WRX angegeben, die sind zwar nur im parallel betrieb
interessant. Bei SPI braucht man diese zwei Datenleitungen ja nicht bzw.
stehen ja auch gar nicht zur Verfügung vllt. habe ich deswegen diese
Angaben(RDX, WRX) im Datenblatt unterbewusst ignoriert.
Wastl schrieb:> An diesem Punkt hast du SPI nicht verstanden
Ich glaube ich hab mich da etwas falsch ausgedrückt. Ich weiß wie SPI
funktioniert ich weiß auch das ich ein Byte schreiben muss um ein Byte
lesen zu können.
Was ich meinte war wenn ich in das Positive Gamma Correction(0xE0) ein
Byte mittels SPI schreibe ich den ersten Wert in diesem Register
überschreibe obwohl ich ein Byte lesen wollte. Sprich als erstes steht
dort zB. 0xFE drin ich will dieses lesen schicke ein 0x00 um die 8 clock
pulse auf der SCK Leitungen zu generieren und lese dann MISO aus. MISO
bleibt bei 0x00 weil das Display hier nicht antwortet wegen Write Only
Register. Nun aber an erster Stelle, im Register, nicht mehr 0xFE steht
sondern mein 0x00 welches aber ein Dummy-Byte ist um eigentlich nur die
Clock-Pulse zu generieren damit das Display was ausgeben könnte wenn es
sich um ein Leseregister handeln würde.
Das war damit gemeint.
Wastl schrieb:> Dass man die geschriebenen Daten des Kommandos trotzdem> ("hintenrum") lesen kann hast du ja offenbar herausgefunden,> nur geht das eben nicht mit dem Kommando 0xE0 da
Doch es geht auch bei dem 0xE0 Befehl. Es gibt ja keine Offizielle
Dokumentation zu dem 0xD9 Befehl mit dem man auch solche Register
auslesen kann welche eigentlich nicht zum Auslesen gedacht sind. Ich
habe gestern Abend in einem anderen Forum ein Beitrag von 2006 gefunden.
Es soll wohl ein Inoffizielles Datenblatt des ILI9341 geben mit der V0.X
da sei der noch dokumentiert. Allerdings fängt mein Datenblatt erst bei
V1.0 im Jahre 2010 an.
Dort wird aber das zu auslesende Register als Parameter übergeben zB:
Befehl 0xD9 senden
Parameter index senden (Also welches Byte man vom Register lesen möchte)
Parameter cmd senden (Hier wird das zu auslesende Register genannt)
-> Das Byte kommt zurück
Sprich für 0xE0 wäre das so:
send Command 0xD9
send Index 0x11 (Entspricht Byte0)
send Register 0xE0
-> Liefert bei mir zB. 0x0F dann zurück
Das könnt ihr sogar gegen prüfen in der ili9341.c weiter oben in dem
"ili9341InitCodes" gibts den Befehl "0x01E0" dahinter steht direkt als
erstes Byte im Gamma register 0x0F.
Aber mit einem Befehl zu arbeiten welches offiziell nicht dokumentiert
ist fühlt sich auch irgendwie nicht so richtig an. Wird ja wohl ein
Grund haben das dieser nicht mit aufgeführt ist im Datenblatt.
Warum ich aber die ID4 nicht auf normalen Weg auslesen kann (Ist ja ein
Read-Only Register) sondern nur mit dem geheimen 0xD9 Befehl. Keine
Ahnung.
Mfg
Felix N. schrieb:> Warum ich aber die ID4 nicht auf normalen Weg auslesen kann (Ist ja ein> Read-Only Register) sondern nur mit dem geheimen 0xD9 Befehl. Keine> Ahnung.
Das hast du dir ja schon selbst beantwortet.
Felix N. schrieb:> Achso das wird also> durch den EXTC pin per Hardware bestimmt ob man die Register auslesen> kann.
Vermutlich haben unsere Displays die Leitung hart codiert sodass
das nicht funktioniert. Ich konnte beim näheren Hinschauen auf die
Leiterplatte (unter dem Glas, dem eigentlichen Display) mir
keinen Reim daraus machen.
Wastl schrieb:> Vermutlich haben unsere Displays die Leitung hart codiert sodass> das nicht funktioniert.
Das wird so sein. Nur ob jetzt das Pin auf VSS oder VDD liegt wäre mal
nett zu wissen :)
Wobei dieser EXTC alle Level2 Befehle beeinflusst. Bei jedem Level2
Befehl steht ja immer bei den Restriction bei:
"EXTC should be high to enable this command"
Und auch unter der Pinbeschreibung von EXTC steht ja drin wenn er Low
ist:
Low: extended command set is discarded".
Das die Befehle dann keine Nutzung haben, es gibt neben dem Read ID4
noch den NV Memory Read Status Befehl welcher auch ein Read-Only Befehl
ist. Bei mir liefert dieser 0x00 zurück ist glaubig auch richtig weil
ich bisher noch nie den NV Memory beschreiben habe erst dann würde sich
im Status Register was tun.
Ich glaub ich probiere das später mal aus den NV Memory zu beschreiben.
Es gibt ein Flow-chart wie man das machen kann(Bei mir auf Seite 234 im
Datenblatt) dann sollte NV Memory Status was anderes zurückgeben und
wenn das beschreiben des NV Memory erfolgreich war müsste auch Read
ID1/2/3 einen von mir festlegten Wert zurück liefern. Da bin ich mal
gespannt ob ich geht.
Andererseits bin ich mir sicher das EXTC auf VDD liegt und somit die
Befehle aktiviert sind weil zB. der Positive/Negative Gamma Correction
Register auch dazu gehören und die werden in der Init Sequenz des
ILI9341 mit Werten gefüttert und mit dem 0xD9 Befehl kann man die
Register ja trotzdem auslesen und die Werte die zurückkommen passen ja
mit den die während der Init Sequenz reingeschrieben wurden. Wäre EXTC
ja nicht VDD sondern VSS sprich Low dann dürften keine Daten in den
beiden Gamma Registern stehen. So zumindest meine Theorie :)
Mfg
Felix N. schrieb:> So zumindest meine Theorie :)
Ich interpretiere das so: das EXTC Bit bestimmt einfach dass die
erweiterten Kommandos im regulären Fall nicht erreichbar sind,
jedoch durch die (von dir herausgefundene) Hintertür trotzdem
verfügbar.
Da nicht offiziell dokumentiert - auch "nicht verfügbar".
Wastl schrieb:> jedoch durch die (von dir herausgefundene) Hintertür trotzdem> verfügbar.
Naa also von mir herausgefunden ist jetzt ein bisschen weit gegriffen :)
Hab das ganze selbst auch aus einem anderen Beitrag erfahren.
Muss aber auch mal sagen ich habe mir jetzt mehrere ILI9341 librarys
angeschaut wie TFT_eSPI, Adafruit ILI9341, ESP8266_ILI9341 und ein paar
custom Libs auf github mit wenigen Funktionen.
Also wenn dort ein readID() Funktion drin ist, bezieht sie sich immer
eigentlich auf 0xD3 und ausgelesen wurde bisher in allen Library mit dem
undokumentierten 0xD9 Befehl. Meisten gab es auch eine
readCommand8/16/32 oder readRegister8/16/32 Funktion welche auf dem 0xD9
Befehl basiert.
Das mache ich jetzt bei mir auch so geht ja scheinbar nicht anderes.
Muss ich wohl akzeptieren, auch wenn ich es gerne so hätte wie es im
Datenblatt eigentlich angegeben ist.
Wastl schrieb:> das EXTC Bit bestimmt einfach dass die> erweiterten Kommandos im regulären Fall nicht erreichbar sind
Das interessante ist ja die Beschreibung vom EXTC Pin:
"Please connect EXTC to VDDI to read/write extended registers
(RB0h~RCFh, RE0h~RFFh)"
Heißt für mich wenn EXTC nicht auf VDDI liegt also VSS(0V)=Low das ich
die extended registers nicht lesen und auch nicht beschreiben kann.
Betrifft alle Register von 0xB0 bis 0xCF. Das sind alle Register
angefangen von den Level2 Befehlen bis Power Control B. Heißt aber auch
die NV Memory Register sind vom EXTC Pin beeinflusst und die
Funktionieren! Naja fast.
Ich habe das ganze mal mit der ID1 und dem NV Memory ausprobiert. Und
ich konnte den Wert 0x7E als ID1 abspeichern. Wenn ich jetzt read
ID1(0xDA) ausführe bekomme ich 0x7E als Wert zurück. ID2 und ID3 hab ich
jetzt nicht programmiert.
Lese ich das NV Memory Status Read Register auf normalen Weg aus bekomme
ich in allen Bytes wieder nur 0x00. Lese ich das mit dem 0xD9 Befehl aus
bekomme ich Byte1 ein 0x01 das bedeutet das ich die ID1 1 mal
programmiert habe(Bis zu 3x darf man).
Also bin ich mir nicht sicher ob EXTC High ist xD. Normalerweise müsste
das lesen des Registers auf normalen Wege auch gehen. Normalerweise
reflektiert der 0x04 Befehl(Read display ID infos) die readID1/2/3
Befehle. Da kommt aber auch nur 0x00 obwohl für ID1 in der Theorie 0x7E
zurückkommen müsste, also den Wert den ich vorher einprogrammiert hatte.
Keine Ahnung.
Aber die Displayplatinen gibt es ja auch wie Sand am Meer hab hier 3x
2.8 Zoll Module. 2x davon sind gleich(Wie oben beschreiben) das andere
hat noch Levelshifter und ein F_CS pin mit drauf(Wofür auch immer der
ist).
Aber ich lasse es jetzt mal gut sein sonst komme ich nie weiter mit
meinem eigentlich Projekt. Wollte ja nur Pixel auslesen können :D
Im Ahnung nochmal zwei Bilder vom NV Memory Write und auslesen der ID1
Mfg