Einzelne Pixel bei TFT mit GC9306/ILI9341

OP #6588335
Lesenswert?

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.
Gast #6588371
Lesenswert?

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.
OP #6589295
Lesenswert?

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.
Angehängte Dateien:
OP #6589453
Lesenswert?

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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren