Forum: Mikrocontroller und Digitale Elektronik TFT Touch Panel Probleme (Touch)


von Hanns-Jürgen M. (yogy)


Lesenswert?

Hallo zusamnmen,

ich habe ein TFT-Display mit (resistiver) Touchfunktion wie dieses bei 
ebay Art. Nr. 221075052240, 320 x 240 Pixel, das ich an einer Arduino 
Mega Hardware betreibe.

Das funzt auch alles ganz wunderbar, mit Ausnahme der Touch-Auswertung.

Während die X-Achse (schmale Seite des Display) einen korrekten Wert 
(0...255) liefert, ist das in der Y-Achse (lange Seite) nicht der Fall. 
Zunächst werden 255...0 korrekt ausgegeben, bei 0 ist jedoch nicht 
y-Pixel 320 sondern erst Pixel-Nr. 240 erreicht. Das wäre ja bei einem 
quadratischen Display mit 240 xx 240 Pixel auch richtig, aber hier 
fehlen noch 80 Pixel in Y-Richtung.

Gehe ich nun weiter in Y-Richtung, dann springt die Ausgabe wieder auf 
einen Startwert (nicht exact reproduzierbar), um dann weiter wieder auf 
0 zu gehen, und das 2..3 Mal auf der restlichen 80-Pixel Strecke.

Dies sollte bei einem resistiven Touchpanel insb im Differenzmode doch 
nicht der Fall sein? Oder ist das TFT exotisch verkabelt und die 
Ansteuerung des Touchcontrollers muß "exotisiert" sein?

Ach ja, ich habe drei dieser Displays von unterschiedl. Lieferanten und 
Herstellern, alle zeigen das gleiche Verhalten. Touch-Controller ist der 
XPT2046 bzw. der ADS7843. Angesteuert wird über die 
Arduino-SPI-Schnittstelle. Der Atmel wird mit 16 MHZ getaktet,

SPCR =  0b01010011; // durch 128 -> 125 khz bei 16 mhz MAXWERT fur TOUCH
SPSR =  0b00000000;

Der Touchcontroller läuft im 8-bit Mode (12 bit Mode macht keinen 
Unterschied.) Start des Controller mit:
WriteCharTo7843(0x98);  //y-Achse
bzw.
WriteCharTo7843(0xD8);

Please help... Wer hat eine Idee? Danke.

: Bearbeitet durch User
von Düsendieb (Gast)


Lesenswert?

Hast Du diese Libary im Einsatz?

http://henningkarlsen.com/electronics/library.php?id=52

Da muss das Display kalibriert werden

von Hanns-Jürgen M. (yogy)


Lesenswert?

Düsendieb schrieb:
> Hast Du diese Libary im Einsatz?
>
> http://henningkarlsen.com/electronics/library.php?id=52
>
> Da muss das Display kalibriert werden

Nein, habe ich nicht. Nur um ein paar bytes per SPI zu übertragen ist 
hier eine Lib auch nicht notwendig.

Ebenso ist eine Kalibrierung  der Display-Touchfunktion zum jetztigen 
Zeitpunkt nicht möglich, da die Positionsausgabe der y-Position über die 
Länge gesehen nicht stetig ist und Sprünge aufweist.

von Tassilo H. (tassilo_h)


Lesenswert?

Vor langer Zeit habe ich mal das hier geschrieben um einen solchen 
Touchcontroller auszulesen:
1
//Do data conversion for X, Y
2
// controller clock rate is 16MHz, each cycle takes 62ns to finish
3
void tpReadXY()
4
{
5
  uint8_t dl,dh;
6
  // set CS=0
7
  TPPORT &= ~(_BV(TPCS));
8
  // read X channel
9
  tpTransmitByte(0x90);
10
  dh = tpTransmitByte(0x00);
11
  dl = tpTransmitByte(0xD0); // prepare for Y conversion
12
  // combine into x value
13
  tpXData = (uint16_t)((dh<<5) | (dl>>3));
14
  dh = tpTransmitByte(0x00);
15
  dl = tpTransmitByte(0x00); 
16
  tpYData = (uint16_t)((dh<<5) | (dl>>3));
17
  // set CS=1
18
  TPPORT |= _BV(TPCS);
19
}

von Hanns-Jürgen M. (yogy)


Lesenswert?

Tassilo H. schrieb:
> Vor langer Zeit habe ich mal das hier geschrieben um einen solchen
> Touchcontroller auszulesen:
>
>
1
> 
2
> //Do data conversion for X, Y
3
> // controller clock rate is 16MHz, each cycle takes 62ns to finish
4
> void tpReadXY()
5
> {
6
>   uint8_t dl,dh;
7
>   // set CS=0
8
>   TPPORT &= ~(_BV(TPCS));
9
>   // read X channel
10
>   tpTransmitByte(0x90);
11
>   dh = tpTransmitByte(0x00);
12
>   dl = tpTransmitByte(0xD0); // prepare for Y conversion
13
>   // combine into x value
14
>   tpXData = (uint16_t)((dh<<5) | (dl>>3));
15
>   dh = tpTransmitByte(0x00);
16
>   dl = tpTransmitByte(0x00);
17
>   tpYData = (uint16_t)((dh<<5) | (dl>>3));
18
>   // set CS=1
19
>   TPPORT |= _BV(TPCS);
20
> }
21
>


Meine Methode sieht funktional identisch aus:
(bei mir sind x und y vertauscht)


(Beipiel für x-pos)
1
U16  GetXposFromTouch(void)  // 16bit
2
{
3
  U16 pos;
4
  init_spi_TOUCH();
5
  TOUCH_PORT &= ~TOUCH_CS_PIN;  //SS auf LO
6
  WriteCharTo7843(0xD0);
7
  pos =((U16) ReadCharFrom7843()) << 4;
8
  pos |= ((U16) ReadCharFrom7843()) >> 4;
9
  
10
  TOUCH_PORT |= TOUCH_CS_PIN;  //SS auf HI
11
  return pos;
12
}


ReadCharFrom7843 überträgt dabei0x00 zum Controller.

Diese meine Version erzeugt den 12 Bit Wert. Mein Eingangsposting 
bezieht sich auch die 8-bit Version bzw. auf die oberen 8 bits des 12 
Bit Ergebnisses.

Vielleicht ist mein Problembeschreibung etwas untergegangen.

Mein Problem ist nicht die prinzipielle Ansteuerung des Touch 
Controllers, sondern das dubiose Ergebnis des Y-Wertes ("Meine" 
Y-Richtung des Displays ist größer als die X-Richtung. X: 240 pix; y: 
320 Pix)

von Tassilo H. (tassilo_h)


Lesenswert?

Also die Größe oder Pixelzahl des Displays spielt keine Rolle. Der 
Touchscreen ist einfach ein Spannungsteiler. Entweder die beiden X- oder 
die beiden Y-Anschlüsse werden an GND bzw VCC gelegt. Am "Berührpunkt" 
entsteht ein Abgriff, der dann über eine der anderen beiden Anschlüsse 
(welcher ist egal) ausgelesen wird. Über die Displaybreite oder 
Displayhöhe gibt es dann immer (fast) den ganzen Wertebereich des 
A/D-Wandlers.

Ist Dir aufgefallen, daß Du in deinem Code um vier Bits nach links oder 
rechts schiebst:
1
pos =((U16) ReadCharFrom7843()) << 4;
2
pos |= ((U16) ReadCharFrom7843()) >> 4;

Das ist nicht richtig so, der Tochcontroller spuckt das Ergebnis so aus, 
daß im ersten Byte das MSB und im zweiten Byte die drei LSB 0 sind, also 
erstes Byte um 5 nach links und zweites Byte um 3 nach rechts schieben 
für eine 12-bit Wandlung.

Ach ja: 8-Bit Wandlung brauch man eigentlich nicht. Das Timing sieht 
quasi genauso aus, das Ergebnis ist genauso in den übertragenen Bytes 
verteilt, aber man ist 4 bits eher fertig, d.h. man könnte den zweiten 
Transfer nach 4 clocks abbrechen. Mit einem 8-bit SPI-Interface geht das 
eh' nicht, es sei denn man überlappt die X- und Y-Wandlung geschickt.

: Bearbeitet durch User
von Hanns-Jürgen M. (yogy)


Lesenswert?

Tassilo H. schrieb:
> Also die Größe oder Pixelzahl des Displays spielt keine Rolle. Der
> Touchscreen ist einfach ein Spannungsteiler. Entweder die beiden X- oder
> die beiden Y-Anschlüsse werden an GND bzw VCC gelegt. Am "Berührpunkt"
> entsteht ein Abgriff, der dann über eine der anderen beiden Anschlüsse
> (welcher ist egal) ausgelesen wird. Über die Displaybreite oder
> Displayhöhe gibt es dann immer (fast) den ganzen Wertebereich des
> A/D-Wandlers.

Das ist mir alles klar. Auch, daß der "lange" y-Bereich damit den 
"vollen" Wertebreich umfassen müßte. Nur, das tut er nicht. Und das 
ist mein Problem.


>
> Ist Dir aufgefallen, daß Du in deinem Code um vier Bits nach links oder
> rechts schiebst:
>
1
> pos =((U16) ReadCharFrom7843()) << 4;
2
> pos |= ((U16) ReadCharFrom7843()) >> 4;
3
>
>
> Das ist nicht richtig so, der Tochcontroller spuckt das Ergebnis so aus,
> daß im ersten Byte das MSB und im zweiten Byte die drei LSB 0 sind, also
> erstes Byte um 5 nach links und zweites Byte um 3 nach rechts schieben
> für eine 12-bit Wandlung.

Nun, warum erhalte ich dann einen Wertebereich von 0...4095? Aber, sei 
es drum, das ist ja nicht mein aktuelles Problem (s.o.).

Ich nehme schon an, das "mein" Problem  auf einen von mir gemachten 
Fehler zurückgeht, aber ich finde keinen   :-( . Wie gesagt: X-Richtung 
ist okay, die längere Y-Richtung halt nicht.

von Tassilo H. (tassilo_h)


Lesenswert?

Hanns-Jürgen M. schrieb:
> Nun, warum erhalte ich dann einen Wertebereich von 0...4095? Aber, sei
> es drum, das ist ja nicht mein aktuelles Problem (s.o.).

Doch, dann stimmt da was nicht. Das erste gelesene Byte vom 
Touch-Controller sollte das oberste Bit auf Null haben, also 0xxx xxxx. 
Wenn Du das dann um 4 nach links schiebst, hast Du dann maximal 0xxx 
xxxx 0000; nach dem verodern mit dem um 4 nach rechts geschobenen 
zweiten Byte also maximal 0xxx xxxx xxxx, also 7+4 = 11 mal x, also 
sollte da maximal 2^11-1 = 2047 rauskommen.

Wenn das ein höherer Wert rauskommt, stimmt was nicht, entweder mit der 
SPI-Übertragung oder die y-Leseroutine sieht anders aus als die 
X-Routine die Du gepostet hast. Und das könnte dann auch gut dein 
"aktuelles" Problem erklären.

von Hanns-Jürgen M. (yogy)


Lesenswert?

Tassilo H. schrieb:
> Hanns-Jürgen M. schrieb:
>> Nun, warum erhalte ich dann einen Wertebereich von 0...4095? Aber, sei
>> es drum, das ist ja nicht mein aktuelles Problem (s.o.).
>
> Doch, dann stimmt da was nicht. Das erste gelesene Byte vom
> Touch-Controller sollte das oberste Bit auf Null haben, also 0xxx xxxx.
> Wenn Du das dann um 4 nach links schiebst, hast Du dann maximal 0xxx
> xxxx 0000; nach dem verodern mit dem um 4 nach rechts geschobenen
> zweiten Byte also maximal 0xxx xxxx xxxx, also 7+4 = 11 mal x, also
> sollte da maximal 2^11-1 = 2047 rauskommen.
>
> Wenn das ein höherer Wert rauskommt, stimmt was nicht, entweder mit der
> SPI-Übertragung oder die y-Leseroutine sieht anders aus als die
> X-Routine die Du gepostet hast. Und das könnte dann auch gut dein
> "aktuelles" Problem erklären.

Nun, laut Datenblatt hast Du eigentlich Recht, auch die Datafruit-Lib 
(Soft-SPI) fü+hrt nach dem Conversion-Start einen Dummy-Clock-Zyklus 
ein.  Von daher ist mein "Ergebnis" "eigentlich" unmöglich, aber es ist 
so.

Bei mir sind beide Routinen für x und y identisch (nur das Controlyte 
unterscheidet sich). Ich werde etzt aber mal in die Tiefen 
hinabsteigen..... Das wird ein paar Minuten dauern...

von Hanns-Jürgen M. (yogy)


Lesenswert?

..es blieb mir nichts anderes übrig, als mit dem Oszi mal nachzusehen. 
Und dabei habe ich herausgefunden, daß das Busy-Signal nur rund 300 ns 
lang ist.

Es beginnt bei der fallenden Flanke des 8. Clocks (Ende Übetragung 
Startbyte(Configbyte) und endet deutlich vor der Startflanke 
(Sample-Flanke) der 1. Clocks des ersten Lesebytes.

Clockrate ist 125 kHz (T = 8000 ns), also bleiben zwischen dem Ende des 
Busysignales und der Startflanke 3700 ns Zeit...

Es wird also sofort das MSB 'rausgetaktet.....

von Tassilo H. (tassilo_h)


Lesenswert?

Kann eigetlich nicht sein. Nach Datenblatt ändert sich das Busy-Signal 
erst mit der nächsten fallenden Taktflanke wieder.
Zeig doch auch mal die WriteCharTo und ReadCharFrom-Routinen...

von Hanns-Jürgen M. (yogy)


Lesenswert?

Tassilo H. schrieb:
> Kann eigetlich nicht sein. Nach Datenblatt ändert sich das Busy-Signal
> erst mit der nächsten fallenden Taktflanke wieder.

ja, so verstehe ich die Datenblätter für den ADS sowie für den XPT 
auch...

> Zeig doch auch mal die WriteCharTo und ReadCharFrom-Routinen...


mach ich...
1
void WriteCharTo7843(U8 c)
2
{
3
  SPI_Byte_Transfer(c);
4
}
5
U8 ReadCharFrom7843()
6
{
7
  U8 c;
8
  c=SPI_Byte_Transfer(0x00);
9
  return c;
10
}
11
12
U8 SPI_Byte_Transfer(U8 i)
13
   {
14
  SPDR = i;
15
  while(!(SPSR & (1<<SPIF)))
16
    ;
17
  return SPDR;
18
   }
19
20
void init_spi_TOUCH (void)     // vor jeder touch-berabeitung aufrufen
21
{
22
23
  TOUCH_PORT |= TOUCH_CS_PIN;  //SS auf HI
24
  SPCR =  0b01010111; // durch 128 -> 125 khz bei 16 mhz MAXWERT fur TOUCH
25
  SPSR =  0b00000001;  // LSB MUSS damit Clockteiler richtig 
26
}

von Tassilo H. (tassilo_h)


Lesenswert?

Hanns-Jürgen M. schrieb:
1
> SPCR =  0b01010111; // durch 128 -> 125 khz bei 16 mhz MAXWERT fur TOUCH
2
> SPSR =  0b00000001;  // LSB MUSS damit Clockteiler richtig

Das ist nicht die Initialisierung, die Du im Ursprungsposting 
geschrieben hast!

Bei SPCR=0b01010111 heisst:
SPIE = 0 interrupt aus OK
SPE = 1 SPI enabled OK
DORD = 0 MSB first OK
MSTR = 1 Master OK
CPOL = 0 SCK low when idle OK

CPHA =1 Daten gültig bei zweiter (=fallender) Flanke von SCK - 
FALSCH!!!!!

SPR1=SPR0 = 1 fOsc/128  OK

und SPSR = 0b00000001
SPI2X doppelte SPI-Frequenz FALSCH (macht nämlich 250kHz SPI-Takt bei 
16MHz clock und /128)

Insbesondere das falsche CPHA-Bit sollte zu den komischsten Ergebnissen 
führen, da sich die Daten immer gerade dann ändern, wenn sie gesampelt 
werden.

von Arduinoquäler (Gast)


Lesenswert?

Hanns-Jürgen M. schrieb:
> Ebenso ist eine Kalibrierung  der Display-Touchfunktion zum jetztigen
> Zeitpunkt nicht möglich, da die Positionsausgabe der y-Position über die
> Länge gesehen nicht stetig ist und Sprünge aufweist.

Ich würde auf jeden Fall die 16-Bit-Version des Daten Auslesens
benutzen (so mache ich es jedenfalls). Du bekomst bei den Touch-
Rohdaten nie die Null oder den Vollausschlag geliefert. Somit wird
die 8-Bit Auflösung noch um einiges schlechter als der reine Werte-
bereich der UINT8 vermuten lässt.

In meinem Fall (gleiches 16-Bit Display) waren die Mininmal- und
Maximalwerte die folgenden (aus meiner Source herauskopiert):
1
#define  X_MIN_RAW    60ul
2
#define  X_MAX_RAW  1970ul
3
#define  Y_MIN_RAW   110ul
4
#define  Y_MAX_RAW  1970ul

Die Rohwerte musst du sowieso skalieren um auf das Display-Format
zu kommen.
1
int Touch_GetX (void)
2
{
3
  uint32_t value;
4
5
  value = (touch_raw_x-X_MIN_RAW);
6
  value = value * disp_width;
7
  value = value / (X_MAX_RAW-X_MIN_RAW);
8
9
  return (uint16_t)value;
10
11
}

von Hanns-Jürgen M. (yogy)


Lesenswert?

Tassilo H. schrieb:
> Hanns-Jürgen M. schrieb:
>
1
>> SPCR =  0b01010111; // durch 128 -> 125 khz bei 16 mhz MAXWERT fur TOUCH
2
>> SPSR =  0b00000001;  // LSB MUSS damit Clockteiler richtig
3
>
>
> Das ist nicht die Initialisierung, die Du im Ursprungsposting
> geschrieben hast!

Richtig, nach der 1. Intialisierung SPSR=0 betrug die Clock 
fälschlicherweise da zu hoch laut Spec 250 kHz, ob wohl die Änderung auf 
SPSR = 1 (125 kHz Clock) keine Änderung am ergebnis brachte.

>
> CPHA =1 Daten gültig bei zweiter (=fallender) Flanke von SCK -
> FALSCH!!!!!

Ja, das ist theoretisch falsch und hatte ich nur probeweise auf "§1" 
gesetzt. Brachte keine Änderung des Erscheinungsbildes. CPHA Ist 
mittlerweilöe wieder "0".

> Insbesondere das falsche CPHA-Bit sollte zu den komischsten Ergebnissen
> führen, da sich die Daten immer gerade dann ändern, wenn sie gesampelt
> werden.

Da denke/dachte ich auch, brachte aber keinen pos/neg Änderung.

Aber ich bin mit dem Oszi einer anderen WH-Sache auf der Spur: Da der 
Arduino mit 5 V läuft, werden die Signale zum TFT/TOUCH Modul mittels 
Widerständen (22k Vorw., 33k geg. Masse) auf 2/3 heruntergeteilt. Meine 
OSZI zeigt jedoch ziemlich flaue Flanken beim heruntergeteilten Clock 
an. Das kann natürlich auch am Tastkopf liegen, den ich zwar in Stellung 
1:10 benutze, aber vlt. ist die Eingangskap. zu hoch. Ich werde gleich 
mal einen besseren Tastkopf nehmen und dann ggf. die Widerstandswerte 
verringern.

von Arduinoquäler (Gast)


Lesenswert?

Hanns-Jürgen M. schrieb:
> werden die Signale zum TFT/TOUCH Modul mittels
> Widerständen (22k Vorw., 33k geg. Masse) auf 2/3 heruntergeteilt.

Das ist zu hochohmig, das dürfte bei den üblichen SPI-
Geschwindigkeiten nicht funktionieren.

.... und wie geschieht das "Hochteilen" des MISO-Signals
des Touch Controllers? Noch eine Fehlerquelle ....

von Tassilo H. (tassilo_h)


Lesenswert?

Hanns-Jürgen M. schrieb:
> (22k Vorw., 33k geg. Masse)

Nimm da mal 2k2 und 3k3

von Hanns-Jürgen M. (yogy)


Lesenswert?

Arduinoquäler schrieb:
> Hanns-Jürgen M. schrieb:
>> werden die Signale zum TFT/TOUCH Modul mittels
>> Widerständen (22k Vorw., 33k geg. Masse) auf 2/3 heruntergeteilt.
>
> Das ist zu hochohmig, das dürfte bei den üblichen SPI-
> Geschwindigkeiten nicht funktionieren.
>
> .... und wie geschieht das "Hochteilen" des MISO-Signals
> des Touch Controllers? Noch eine Fehlerquelle ....


So, ja, was soll ich sagen. Das "Problem" waren tatsächlich die 
"hochohmigen" Spannungsteiler. NAchdem ich die Werte auf ein Elftel 
reduziert habe, stimmen die Flanken und auch die aushelesenen Rohwerte 
sind plausibel.

Ich könnte mich selber in den Besagten beißen, daß ich nicht eher zum 
Oszi gegriffen habe... Aber ich habe eine fadenscheinige Ausrede: Das 
SainSmart Adapterboard, das ich kürzlich erstanden habe, benutzt nur 
Vorwiderstande von 10k Ohm, während der effektive Innenwiderstand der 
heruntergeteilten Spannungsquelle 22k || 33k vergleichbare 13 k ergibt. 
Ich vermute, das Adapterboard funzt dann auch nicht richtig. Allerdings 
ist dort defaultmäßig eine Soft-SPI für den Touchcontroller zuständig, 
während die Hard-SPI für die SD Karte zustäöndig ist. Was die dann wohl 
sagt?

Ach ja, bezüglich des "Hochteilens" verwende ich eine Diode und einen 
Pullup auf der 5V Seite. Die Flanken sind okay.

So, nachdem jetzt die Meßwerte vorliegen, kann ich mich an das 
Kalibrieren machen. Aber das sind Peanuts..

Dabke für eure Hilfen und Tipps, und sorry für meine Nichtbeachtung der 
Hardwareprobleme

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.