Forum: Mikrocontroller und Digitale Elektronik SSD1963 - TFT-Controller - Pixel auslesen


von Frank B. (jeanluc7)


Angehängte Dateien:

Lesenswert?

Salut,

ich arbeite gerade an einem Grafik-Touchscreen-Terminal, das Teil eines 
größeren Projekts ist, um alten Elektronik-Experimentierkästen (Philips, 
Schuco, Kosmos) wieder neues Leben einzuhauchen. Das Projekt wird in 
einem anderen Forum beschrieben 
(http://server23.hostpoint.ch/~rigertc/rigert.com/ee-forum/viewtopic.php?f=35&t=1601). 
Das Grafik-Touchscreen-Terminal verwendet eine China-Standardplatine mit 
4,3"-TFT-Touchscreen und dem SSD1963 als Controller. Die Ansteuerung von 
außen zum Experimentieren erfolgt rein seriell und wird durch zwei MC's 
(644 für die Grafik und 88 für Touch/Tasten) geleistet. Das ganze 
basiert auf der UTFT-Library und bietet die Möglichkeit, mit ganz wenig 
Aufwand ein Terminal oder Diagramme oder Eingabeeelemente wie Menüs, 
Listen usw. zu nutzen. Unser Ziel ist, eine möglichst vielseitige 
Platine zu schaffen und den Nutzern den Einstieg möglichst einfach zu 
machen - soweit die Einführung zum Projekt. Ein paar Bilder habe ich 
angehängt. Codes dazu und die ganze Anleitung gibt's hier: 
https://www.dropbox.com/l/kX19SfyLe0x575egbAjxKc

Nun aber zu meinem Problem: Ich habe es bisher nicht geschafft, aus dem 
SSD1963 einzelne Pixeldaten auszulesen. Leider ist google hier nicht 
mein Freund - es gibt zwar die Doku, nach der es funktionieren sollte, 
aber keinen lauffähigen Codeteil, der zeigt, wie es richtig gemacht 
wird. Die Tipps, die ich finden konnte, führten zum folgenden Code:
1
unsigned int getPixel(unsigned int x0, unsigned int y0)
2
{ 
3
    unsigned int pixeldat, r /*, g, b */;
4
         
5
    setXY(x0,y0,x0,y0);
6
    LCD_Write_COM(0x2E);    // Read_Memory_Start
7
             
8
    sbi(PORTD, B_WR);
9
    sbi(PORTD, B_RS);
10
    
11
    set_direction_registers_read(); 
12
    PORTA = 0xFF;
13
    PORTC = 0xFF;
14
    
15
    pulse_low(PORTD, B_RD); //R_D = 0;  //dummy read   
16
    pulse_low(PORTD, B_RD); // R_D = 0;
17
18
    r = PINA; 
19
    pixeldat = (r << 8) + PINC;
20
    
21
/* 
22
    cbi(PORTD, B_RD); // R_D = 0;
23
    sbi(PORTD, B_RD); // R_D = 1;
24
    g = PINA;
25
    
26
    cbi(PORTD, B_RD); // R_D = 0;
27
    sbi(PORTD, B_RD); // R_D = 1;
28
    b = PINA;
29
*/     
30
     
31
  //pixeldat = (b<<11)+(g<<5)+(r<<0);
32
     
33
    set_direction_registers_write();
34
    sbi(PORTD, B_CS);     
35
    return pixeldat;   
36
}

Wie unschwer zu erraten ist, funktioniert er leider nicht. Es kommt 
immer dieselbe Farbe zurück. Ich habe die Routine benutzt, um ein 50x50 
Pixdel großes Rechteck auszulesen und zu "kopieren" - leider ohne 
Erfolg. Der "dummy read" im Code stammt bereits aus einem der Tipps zum 
Auslesen. Es funktioniert mit genauso wenig wie ohne.

Falls jemand das Auslesen des Speichers erfolgreich gelöst hat, würde 
ich mich über eine  Unterstützung freuen.

Viele Grüße,
Frank

von Mehmet K. (mkmk)


Lesenswert?

Ich arbeite mit einem HX8352A Controller. Keine Ahnung wiesehr sich 
dieser mit Deinem SSD1963 deckt. Aber vielleicht gibt es Dir 'ne Idee.
1
#define LCD_REGISTER (*((volatile unsigned short *) 0x60000000)) // RS = 0 
2
#define LCD_RAM      (*((volatile unsigned short *) 0x60020000)) // RS = 1
3
4
//=================================
5
// WriteReg
6
//=================================
7
void MyLcd::WriteReg(unsigned lcd_register, unsigned lcd_register_value)
8
{
9
  LCD_REGISTER = lcd_register;
10
  asm("nop.w");
11
  LCD_RAM = lcd_register_value;
12
}
13
14
//=================================
15
// SetAddress
16
//=================================
17
void MyLcd::SetAddress(unsigned x1, unsigned y1, unsigned x2, unsigned y2)
18
{
19
// Column address start register R02~03h
20
// Column address end register   R04~05h
21
// Row address start register    R06~07h
22
// Row address end register      R08~09h
23
24
  this->WriteReg(0x02, x1 >> 8);
25
  this->WriteReg(0x03, x1);
26
  this->WriteReg(0x04, x2 >> 8);
27
  this->WriteReg(0x05, x2);
28
  this->WriteReg(0x06, y1 >> 8);
29
  this->WriteReg(0x07, y1);
30
  this->WriteReg(0x08, y2 >> 8);
31
  this->WriteReg(0x09, y2);
32
  LCD_REGISTER = 0x22;
33
}
34
35
//===================
36
// SetPixel
37
//===================
38
void MyLcd::SetPixel(unsigned x, unsigned y, unsigned color)
39
{
40
  this->SetAddress(x, y, x, y);
41
  this->WriteData(color);
42
}
43
44
//===================
45
// GetPixel
46
//===================
47
unsigned MyLcd::GetPixel(unsigned x, unsigned y)
48
{
49
  unsigned dummy;
50
51
  this->SetAddress(x, y, x, y);
52
  dummy = LCD_RAM;
53
  return LCD_RAM;
54
}

von Mehmet K. (mkmk)


Lesenswert?

Vollstaendigkeitshalber:
1
//===================
2
// GetPixelArea
3
//===================
4
void MyLcd::GetPixelArea(unsigned x, unsigned y, unsigned breite, unsigned hoehe, uint16_t *ptr)
5
{
6
  volatile unsigned dummy;
7
  unsigned h = y + hoehe  -1;
8
  unsigned b = x + breite -1;
9
10
  this->SetAddress(x, y, b, h);
11
  dummy = LCD_RAM;
12
  for (int x = 0; x < (breite * hoehe); x++)
13
    *ptr++ = LCD_RAM;
14
}
15
16
//===================
17
// SetPixelArea
18
//===================
19
void MyLcd::SetPixelArea(unsigned x, unsigned y, unsigned breite, unsigned hoehe, uint16_t *ptr)
20
{
21
  unsigned h = y + hoehe  -1;
22
  unsigned b = x + breite -1;
23
24
  this->SetAddress(x, y, b, h);
25
  for (int x = 0; x < (breite * hoehe); x++)
26
    LCD_RAM = *ptr++;
27
}

von J. -. (Gast)


Lesenswert?

>    setXY(x0,y0,x0,y0);
>    LCD_Write_COM(0x2E);    // Read_Memory_Start

Ich nehme mal an, Dein Problem ist bereits gelöst ;)
Falls nicht:
Wahrscheinlich wird beim setXY-Befehl nur das Fenster incl. Koordinaten 
zum Schreiben gültig(*).
Der LCD_Write_COM(0x2E) läuft dann ins Leere bzw liest kein Fenster, 
sondern nur ein einziges Pixel aus (das von x0,y0).
Ich habe den getXY-Command genauso aufgebaut wie den setXY, also erst 
die beiden Words für die columns, dann die beiden Words für die pages, 
und dann als einzigen Unterschied zum setXY nicht den 0x2C-Befehl zum 
Schreiben, sondern wie Du auch 0x2E zum Lesen.

getXY:
1
  TFT_Write_COM(CMD_SET_COL_ADDRESS); //0x2A
2
  TFT_Write_DATA((x1>>8) & 0xFF);
3
  TFT_Write_DATA(x1 & 0xFF);
4
  TFT_Write_DATA((x2>>8) & 0xFF);
5
  TFT_Write_DATA(x2);
6
  TFT_Write_COM(CMD_SET_PAGE_ADDRESS); //0x2B
7
  TFT_Write_DATA((y1>>8) & 0xFF);
8
  TFT_Write_DATA(y1);
9
  TFT_Write_DATA((y2>>8) & 0xFF);
10
  TFT_Write_DATA(y2);
11
  TFT_Write_COM(CMD_READ_MEM_START); //0x2E

Also Fenster setzen, und dann die Bytes für die Pixeldaten ohne weiteres 
Kommando abholen.
So geht es bei mir zumindest.

(*)was noch zu beweisen wäre: Setz doch mal mit setXY auf Deine maximale 
Displaygröße, also anstatt nur auf ein einzelndes Pixel(x0,y0) auf den 
ganzen Screen, z.B. bei 320x240-Display -> setXY(0,0,320-1,240-1).
Wenn Du dann danach dann 0x2E schickst, könnte es trotzdem klappen - hab 
ich ehrlich gesagt noch nicht probiert ;)

von Frank B. (jeanluc7)


Lesenswert?

Salut,

mein Problem habe ich zwischenzeitlich leider noch nicht lösen können 
und deshalb die Funktion erst einmal außen vor gelassen.

Daher vielen Dank für deinen Tipp - ich werde es ausprobieren und dann 
berichten. Wäre echt klasse, wenn das Pixelauslesen dann auch endlich 
klappt.

Grüße, Frank

von J. -. (Gast)


Lesenswert?

Das sollte schon gehen, mir ist noch beim Umschalten der Ports was 
aufgefallen:
1
unsigned int getPixel(unsigned int x0, unsigned int y0)
2
{ 
3
    unsigned int pixeldat, r /*, g, b */;  
4
5
    getXY(x0,y0,x0,y0);
6
             
7
    sbi(PORTD, B_WR);
8
    sbi(PORTD, B_RS);
9
    
10
    set_direction_registers_read(); 
11
//    PORTA = 0xFF; //pullups nicht notwendig
12
//    PORTC = 0xFF;
13
    
14
    pulse_low(PORTD, B_RD); //R_D = 0;  //dummy read   
15
    pulse_low(PORTD, B_RD); // R_D = 0;
16
17
    r = PINA; 
18
    pixeldat = (r << 8) | PINC; //+ geht aber auch
19
20
    pulse_high(PORTD, B_RD); // R_D = 1;
21
22
/* sonst knallt der Ausgangstreiber vom LCD auf die Ausgangstreiber vom AVR, wenn Du im nächsten Befehl umschaltest:*/
23
     
24
    set_direction_registers_write();
25
    sbi(PORTD, B_CS);     
26
    return pixeldat;   
27
}

Hoffentlich klappt's ;)

von Torsten S. (tse)


Lesenswert?

Der SSD1963 ist zwar fix beim Schreiben aber ziemlich lahm beim Lesen. 
bau mal ein paar Warteschleifen ein.

von Harald Ma. (Gast)


Lesenswert?

Hallo zusammen !

Ich bin ein absoluter Anfänger was dieses Thema betrifft. Aber wir haben 
ein TFT Display des Typs SSD1963 und da ist ein SD Karten Slot drauf. 
Auf dem TFT ist ein Teil zum Bedienen vorbereitet und auf dem oberen 
Teil ist das Logo des Herstellers drauf, jetzt habe Ich die SD Karte 
entnommen und wollte dort unser Logo einfügen, aber leider hat es nicht 
geklappt da es nur Wirre Linien und Punkte anzeigt. Kann mir jemand von 
euch helfen ? Bitte !

von Harald Ma. (Gast)


Lesenswert?

Hallo alle zusammen,

Ein Freak hat mal wieder ganze Arbeit geleistet! Vielen Dank er trägt
seinen Namen zurecht. Mein Problem ist soweit gelöst !
Vielen Dank

von Frank B. (jeanluc7)


Lesenswert?

Hallo,
ich habe heute das Problem gelöst und kann nun aus dem 
SSD1963-Controller einzelne Pixel auslesen. Es ist aber tatsächlich ein 
wenig umständlich und steht so auch nicht in der Doku - vielleicht ist 
das der Grund, warum man bei google keine einzige funktionierende 
Version von getPixel findet.
1
unsigned int getPixel(int x,int y)
2
{
3
  unsigned char Hi, Lo;
4
  unsigned int color;
5
6
// erste Runde, liefert Lo-Byte
7
  cbi (PORTD, B_CS);
8
  setXY(x,y, x, y);
9
  LCD_Write_COM(0x2E);  // Read_Memory_Start
10
  set_direction_registers_read(); 
11
12
  cbi(PORTD, B_RD);  // Einmal Lesebefehl als Dummy absetzen
13
  NOP;
14
  sbi(PORTD, B_RD);
15
  cbi(PORTD, B_RD);
16
  Lo = PINC;
17
  sbi(PORTD, B_RD);
18
19
  set_direction_registers_write();
20
// zweite Runde, liefert Hi-Byte
21
  LCD_Write_COM(0x2E);  // Read_Memory_Start
22
  set_direction_registers_read(); 
23
24
  cbi(PORTD, B_RD);  // Einmal Lesebefehl als Dummy absetzen
25
  NOP;
26
  sbi(PORTD, B_RD);  
27
  cbi(PORTD, B_RD);
28
  Hi = PINA;
29
  sbi(PORTD, B_RD);
30
31
  set_direction_registers_write();
32
  sbi (PORTD, B_CS);    
33
// Farben zusammensetzen
34
  color = ((int)Hi << 8) + Lo;
35
  return color;
36
}

Die Pinbelegungen hängen natürlich davon ab, wie das Panel an den AVR 
angeschlossen ist, die grunsätzliche Vorgehensweise ist aber immer die 
selbe: es muss zweimal ausgelesen werden. Beim ersten Mal bekommt man 
ein gültiges Lo-Byte an den Pins D0-D7, beim zweiten Versuch ein 
gültiges Hi-Byte an den Pins D8-D15. Die jeweils korrespondierenden 
Bytes am jeweils anderen Port sind ungültig.

Außerdem streikt der Controller bei Farbwerten, bei denen Grün und Blau 
voll ausgesteuert sind - er liefert dann einfach Schwarz als Farbe. Es 
sieht so aus, als würde da ein Überlauf entstehen. Ich konnte mich hier 
darauf beschränken, einfach keine voll ausgesteuerten Farben mehr zu 
benutzen; ich ziehe immer das LSB von jeder Farbe ab, wenn sie maximal 
wird.

von Peter D. (peter_d592)


Lesenswert?

Hi Frank - I am using a 5-inch TFT touch screen and the UTFT library 
from Rinky-Dink electronics with an Arduino Mega 2560, and I would like 
to add a getPixel() command. I am trying to use your code from your 
2015-01-24 14:12 post with the title "Solved: SSD1963 - TFT controller - 
read out pixels". I have added your code at the end of the UTFT.cpp, and 
included an entry in the header file, but I am having difficulties in 
converting your commands "set_direction_registers_read" and 
"set_direction_registers_write" into the appropriate commands understood 
by the rest of the UTFT library. There is a command 
"_set_direction_registers(mode)" which might be nearly the same, but I 
would be grateful if you could help. Can you point me to the source code 
for "set_direction_registers_read" and "set_direction_registers_write"? 
I can send you the UTFT.cpp and UTFT.h files if you think it would help 
- best regards - Peter

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.