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?
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.
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.
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.
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.
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
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.
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?
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.
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
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.
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.
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.
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
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.
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.)
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.
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!
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
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 ....
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!
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.
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.
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.
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.
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.
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 :)
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".
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.
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 (RB0hRCFh, RE0hRFFh)"
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