Forum: Mikrocontroller und Digitale Elektronik Einzelne Pixel bei TFT mit GC9306/ILI9341


von Axel V. (axel-f)


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.

: Verschoben durch Moderator
von Planloser (Gast)


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.

von Axel V. (axel-f)


Angehängte Dateien:

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.

von Johannes S. (Gast)


Lesenswert?

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);

von Axel V. (axel-f)


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.

von Johannes S. (Gast)


Lesenswert?

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.

von Axel V. (axel-f)


Lesenswert?

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
Noch kein Account? Hier anmelden.