Guten Abend, seit einigen Tagen ärgere ich mich mit einem Display herum, auf dem sich einzelne Pixel nicht recht darstellen lassen wollen. Aber beginnen wir von vorn: Display 24TQV058D, 320x240, SPI Ansteuerung Controller: GC9306 Der GC9306 (GalaxyCore Inc.) scheint mir ein Klon des ILI9341 zu sein; jedenfalls sieht das Datenblatt exakt aus wie vom ILI abgeschrieben. Bildschirm löschen: funktioniert. Horizontale Linie: funktioniert. Vertikale Linie: funktioniert. Schräge Linie: funktioniert nicht! Es wird nur das letzte Pixel der Linie gesetzt. Einzelnes Pixel setzen funktioniert. Aber sobald ich ein zweites Pixel setzen will, wird nur das letzte Pixel gezeichnet und das auch noch mit invertierter Farbe!! Ein ganz seltsames Verhalten. Habe alles mögliche ausprobiert. Habe das SPI-Timing x-Mal nachgemessen, habe das Timing drastisch verlangsamt, habe verschiedene Initialisierungen (die hier in diversen Bibliotheken existieren) getestet- keine Änderung. Ist dieses Verhalten jemand bekannt, kann jemand sachdienliche Hinweise geben? Bin auf dem Gebiet kein Neuling, habe div. TFT einfach zum Laufen bekommen; per SPI, parallel und auch RGB, kein Problem. Danke schonmal, Axel F.
:
Verschoben durch Moderator
Bei der Informationsfülle läßt sich gut raten... - SPI: 4-line oder 3-line - Welches Display - Welcher Rechner/welche CPU/MCU - Wo ist der Code Ohne mehr Infos wird das nur Kaffeesatzleserei. Der Fehler liegt höchstwahrscheinlich in der Software.
Hallo Planloser, danke, dass Du mir helfen willst! -Scchnittstelle ist nicht SPI wie irrtümlich angegeben, sondern 8Bit parallel. Die sog. 8080-I Schnittstelle lt. Datenblatt. - Display ist ein 24TQV058D, stand so aber auch in meinem Post ;-) Darüber läßt sich kaum etwas im Netz finden, aber die Kollegin aus China war so freundlich, mir ein Datenblatt zu schicken. Meiner Meinung kaum die Elektronen wert, aber ich werde es anhängen. - µController ist ein ATSAM4SD16C, also ein Cortex M4. Der relevante Code:
1 | /* Testprogramm SAM4S16C für TFT 24TQV058D
|
2 | *
|
3 | *
|
4 | */
|
5 | |
6 | #include "asf.h" |
7 | #include <stdio.h> |
8 | #include <stdlib.h> |
9 | #include <stdint.h> |
10 | #include "conf_pins.h" |
11 | #include "timer.h" |
12 | #include "gc9306.h" |
13 | |
14 | uint32_t status_GC9306; |
15 | volatile uint8_t ticks= 0; |
16 | |
17 | /* Write a byte as command to the display controller
|
18 | * Requirement: P_CS active, P_RD= 1, P_WR= 1;
|
19 | * Results: P_CS active, P_DATA= 0, P_RD= 1, P_WR= 1, P_RS= 0;
|
20 | */
|
21 | void writeCommand_GC9306(uint8_t data) |
22 | {
|
23 | PIOC->PIO_SODR = P_WR | P_RD; |
24 | PIOC->PIO_CODR = P_RS; |
25 | PIOC->PIO_CODR = P_RS; |
26 | PIOC->PIO_CODR = P_DATA; |
27 | PIOC->PIO_SODR = data; |
28 | PIOC->PIO_SODR = data; |
29 | PIOC->PIO_CODR = P_WR; |
30 | PIOC->PIO_CODR = P_WR; |
31 | PIOC->PIO_SODR = P_WR; |
32 | PIOC->PIO_SODR = P_WR; |
33 | }
|
34 | |
35 | /* Write a byte as data (parameter) to the display controller
|
36 | * Requirement: P_CS active, RD= 1, P_WR= 1;
|
37 | * Results: P_CS active, P_RD= 1, P_WR= 1, P_RS= 1;
|
38 | */
|
39 | void writeData_GC9306(uint8_t data) |
40 | {
|
41 | PIOC->PIO_SODR = P_WR | P_RD; |
42 | PIOC->PIO_SODR = P_RS; |
43 | PIOC->PIO_CODR = P_DATA; |
44 | PIOC->PIO_SODR = data; |
45 | PIOC->PIO_OER = P_DATA; |
46 | PIOC->PIO_CODR = P_WR; |
47 | PIOC->PIO_SODR = data; |
48 | PIOC->PIO_SODR = P_WR; |
49 | PIOC->PIO_SODR = P_WR; |
50 | PIOC->PIO_CODR = P_DATA; |
51 | }
|
52 | |
53 | /* Write a byte pixel data to the controller
|
54 | * Requirement: P_CS active, P_RD= 1, P_WR= 1, P_RS= 1;
|
55 | * Results: P_CS active, P_RD= 1, P_WR= 1, P_RS= 1;
|
56 | */
|
57 | void writeFRAM_GC9306(uint8_t data) |
58 | {
|
59 | PIOC->PIO_SODR = P_RS; |
60 | PIOC->PIO_SODR = P_RD; |
61 | PIOC->PIO_CODR = P_WR | P_DATA; |
62 | PIOC->PIO_CODR = P_WR; |
63 | PIOC->PIO_CODR = P_WR; |
64 | PIOC->PIO_CODR = P_DATA; |
65 | PIOC->PIO_SODR = data; |
66 | PIOC->PIO_SODR = data; |
67 | PIOC->PIO_SODR = data; |
68 | PIOC->PIO_SODR = P_WR; |
69 | PIOC->PIO_SODR = P_WR; |
70 | }
|
71 | |
72 | void setOrientation_GC9306(uint8_t orientation) |
73 | {
|
74 | writeCommand_GC9306(MEM_ACCESS); /* Memory Data Access Control */ |
75 | |
76 | switch(orientation) |
77 | {
|
78 | case 1: |
79 | writeData_GC9306(0x68); /* MX + MV */ |
80 | displayGC9306.width = RES_Y; |
81 | displayGC9306.height = RES_X; |
82 | break; |
83 | |
84 | case 2: |
85 | writeData_GC9306(0xC8); /* MY + MX */ |
86 | displayGC9306.width = RES_X; |
87 | displayGC9306.height = RES_Y; |
88 | break; |
89 | |
90 | case 3: |
91 | writeData_GC9306(0xA8); /* MY + MV */ |
92 | displayGC9306.width = RES_Y; |
93 | displayGC9306.height = RES_X; |
94 | break; |
95 | |
96 | default:
|
97 | writeData_GC9306(0x08); /* None */ |
98 | displayGC9306.width = RES_X; |
99 | displayGC9306.height = RES_Y; |
100 | break; |
101 | }
|
102 | }
|
103 | |
104 | |
105 | uint32_t lcd_gc9306_init(void) |
106 | {
|
107 | /* Hardware reset */
|
108 | delay_ms(150); |
109 | PIOC->PIO_SODR = P_RSTn; /* Reset OFF */ |
110 | delay_ms(250); /* Wait before use */ |
111 | |
112 | P_CS_AKTIV; |
113 | writeCommand_GC9306(DISPLAY_OFF); |
114 | delay_ms(150); |
115 | /* Software reset; Wait minimum 120ms */
|
116 | /* Sleep out; Wait minimum 120ms */
|
117 | |
118 | writeCommand_GC9306(SLEEP_OUT); |
119 | delay_ms(150); |
120 | /* Set the orientation and the gamma */
|
121 | setOrientation_GC9306(0); |
122 | |
123 | writeCommand_GC9306(PIXEL_FMT); writeData_GC9306(0x06); // 18 Bits per Pixel |
124 | delay_ms(150); |
125 | /* Display ON; Wait 100ms before start */
|
126 | writeCommand_GC9306(DISPLAY_ON); |
127 | delay_ms(150); |
128 | |
129 | P_CS_INAKTIV; |
130 | |
131 | return 0; |
132 | } /* lcdst_init */ |
133 | |
134 | uint8_t lcdGC9306_setWindow(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2) |
135 | {
|
136 | Union16 d; |
137 | /* Accept: 0 <= x1 <= x2 < activeDisplay->width */
|
138 | if(x2 < x1) return 1; |
139 | if(x2 >= displayGC9306.width) return 1; |
140 | |
141 | /* Accept: 0 <= y1 <= y2 < activeDisplay->height */
|
142 | if(y2 < y1) return 1; |
143 | if(y2 >= displayGC9306.height) return 1; |
144 | |
145 | /* Set column address */
|
146 | d.u16= x1; |
147 | writeCommand_GC9306(COL_ADRESS); |
148 | writeData_GC9306(d.u8[1]); writeData_GC9306(d.u8[0]); |
149 | d.u16= x2; |
150 | writeData_GC9306(d.u8[1]); writeData_GC9306(d.u8[0]); |
151 | |
152 | /* Set row address */
|
153 | d.u16= y1; |
154 | writeCommand_GC9306(PAGE_ADRESS); |
155 | writeData_GC9306(d.u8[1]); writeData_GC9306(d.u8[0]); |
156 | d.u16= y2; |
157 | writeData_GC9306(d.u8[1]); writeData_GC9306(d.u8[0]); |
158 | |
159 | /* Activate RAW write */
|
160 | writeCommand_GC9306(RAM_WRITE); |
161 | PIOC->PIO_SODR = P_RS; |
162 | return 0; |
163 | } /* lcdst_setWindow */ |
164 | |
165 | void lcdGC9306_drawPx(uint16_t x, uint16_t y, uint8_t r, uint8_t g, uint8_t b) |
166 | {
|
167 | if(lcdGC9306_setWindow(x, y, x, y)) return; |
168 | |
169 | writeFRAM_GC9306(r); writeFRAM_GC9306(g); writeFRAM_GC9306(b); |
170 | } /* lcdst_drawPx */ |
171 | |
172 | void lcdGC9306_drawHLine(uint16_t x, uint16_t y, uint16_t l, uint8_t r, uint8_t g, uint8_t b) |
173 | {
|
174 | /* Draw only in the display space */
|
175 | if(l == 0) return; |
176 | if((x+l-1) >= displayGC9306.width) l = displayGC9306.width - x; |
177 | |
178 | /* Draw the line */
|
179 | if(lcdGC9306_setWindow(x, y, x+l-1, y)) return; |
180 | while(l--) {writeFRAM_GC9306(r); writeFRAM_GC9306(g); writeFRAM_GC9306(b);} |
181 | } /* lcdst_drawHLine */ |
182 | |
183 | void lcdGC9306_drawVLine(uint16_t x, uint16_t y, uint16_t l, uint8_t r, uint8_t g, uint8_t b) |
184 | {
|
185 | /* Draw only in the display space */
|
186 | if(l == 0) return; |
187 | if((y+l-1) >= displayGC9306.height) l = displayGC9306.height - y; |
188 | |
189 | /* Draw the line */
|
190 | if(lcdGC9306_setWindow(x, y, x, y+l-1)) return; |
191 | while(l--) {writeFRAM_GC9306(r); writeFRAM_GC9306(g); writeFRAM_GC9306(b);} |
192 | } /* lcdst_drawVLine */ |
193 | |
194 | /****************************************************************/
|
195 | |
196 | int main(void) |
197 | {
|
198 | // zunächst die INIT's
|
199 | sysclk_init(); |
200 | init_PINS(); |
201 | irq_initialize_vectors(); |
202 | cpu_irq_enable(); |
203 | delay_ms(200); |
204 | status_GC9306= lcd_gc9306_init(); |
205 | |
206 | P_CS_AKTIV; |
207 | lcdGC9306_drawScreen(GC9306_BLACK); |
208 | P_CS_INAKTIV; |
209 | |
210 | UNUSED(x); UNUSED(y); UNUSED(w); UNUSED(z); UNUSED(u); |
211 | PIOA->PIO_SODR = EN_VBL; |
212 | |
213 | while (1) |
214 | {
|
215 | if( sekunde) |
216 | {
|
217 | sekunde = 0; |
218 | P_CS_AKTIV; |
219 | lcdGC9306_drawScreen(GC9306_BLACK); // dauert 52 ms |
220 | |
221 | lcdGC9306_drawPx(20, 25, 255, 165, 0); // Befehl 1 |
222 | lcdGC9306_drawHLine(5, 35, 120, 255, 165, 0); // Befehl 2 |
223 | lcdGC9306_drawPx(25, 30, 255, 165, 0); // Befehl 3 |
224 | lcdGC9306_drawPx(20, 45, 255, 165, 0); // Befehl 4 |
225 | lcdGC9306_drawPx(20, 65, 255, 165, 0); // Befehl 5 |
226 | |
227 | P_CS_INAKTIV; |
228 | }
|
229 | }
|
230 | }
|
Die Low-Level Routinen haben einige Füll-Befehle, um die Zugriffe einfach mal zu verlangsamen. Aber auch ohne diese Füller werden die Timings eingehalten! Tests, die ich u.a. durchgeführt habe: - Nur Befehl 1: 1 Pixel Orange auf Pos. (20, 25). - Nur Befehl 2: hor. Linie ab (5, 35) , 120 Px lang in Orange. - Befehl 1+2: hor. Linie ab (5, 35) , 120 Px lang in Grün(!), kein weiteres Pixel. - Befehle 1-5: hor. Linie ab (5, 35) , 120 Px lang; dazu 1 Pixel bei (20, 65) beides in Grün. Das Zeichnen auf diesen kleinen Displays geht ja immer nach dem gleichen Prinzip: Fensterbereich setzen, mit Pixel(n) füllen, fertig. Bei einem anderen Display (das mit SPI) ging das ohne Probleme. Selbst Schrift und Bitmaps kein Problem. Aber hier... Meine Hoffnung war, daß jemand schon mal dasselbe Problem hatte.
vielleicht ist die Größe 0 für einen Pixel zu klein? Hier wird für den Pixel x1=x2 und y1=y2 gesetzt, in anderen Libs habe ich sowas: setAddrWindow(x,y,x+1,y+1);
Ja, exakt das Gleiche habe ich mir auch schon überlegt und ausprobiert- selbiger Effekt. Ich hatte auch das Fenster auf (x,y,x+10,y+10), sollte ja nichts schaden, auch wenn nur ein Pixel gezeichnet wird. Bringt nichts. Weiterer Versuch von mir: drawHLine mit Länge 1: nichts wird gezeichnet, drawHLine mit Länge 2: 1 Pixel wird gezeichnet.
ohne alles gelesen zu haben, kann das Display überhaupt 3*8 Bit Farbtiefe? Und ist es dafür initialisiert? Ich habe ein ILI9341 und das wird mit 16 Bit, RGB565, betrieben. Edit: Lt. DB kann der ILI bis 18 Bit Farbtiefe.
Bei mir im init: writeCommand_GC9306(PIXEL_FMT); writeData_GC9306(0x06); // 18 Bits per Pixel Dann wird per Farbe 1 Byte gesendet, wovon der GC9306 die oberen 6 Bit verwendet.
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.