Сенсорный экран на XPT2046 - получилось

sva_khv
Offline
Зарегистрирован: 19.12.2016

Проведя неделю в экспериментах удалось победить сенсорный экран на контроллере XPT2046.

железяка такая (в этой ветке разобрано как запустить дисплей):

http://arduino.ru/forum/apparatnye-voprosy/kak-podklyuchit-displei-32-lcd-module#comment-246053

Подключил его по аппаратному ISP. ВНИМАНИЕ у этой железяки сигналы 3,3В! Надо согласовывать!

Проанализировал как проходят сигналы осцилографом. Почитал как другие с ним боролись. И какие проблемы были.

Главная проблема - изучив спецификацию на XPT2046 и проверив осцилографом было выяснено что контроллер не совсем коректно передает данные в мастер. А именно - сигналы данных по MISO  запаздывают на 1 такт (не совсем корректное определение но суть имеено в этом)! При этом в получаем байте СТАРШИЙ БИТ ВСЕГДА 1!!! ) остальные биты смещаются на одну позицию в сторону младшего бита. А самый младший теряется! Причем при 12 разрядной оцифровке при получении 2 байт это происходит в обоих байтах.

https://hubstub.ru/display/51-kak-poluchit-koordinaty-tochki-kasaniya-i-proizvesti-kalibrovku-rezistivnoy-sensornoy-paneli-na-primere-xpt2046.html

Варианты решения проблемы.

- Организовать программный SPI и при отладке это учесть.  (может в библиотеках это и реализовали, но мне с ними запустить не удалось)

- Настроить аппаратный SPI (мне не удалось).

- убрать старший бит в получаемых байтах, а на потерю младшего бита в старшем байте наплевать (в младшем байте там и так нули). Что я и реализовал. На точность это не повлияло. Мне не картинки стилусов рисовать, а кнопки пальцем нажимать надо.

Продолжение следует.....

 

sva_khv
Offline
Зарегистрирован: 19.12.2016

Эти фото наглядно показывают какие преобразоания я сделал с битами в старшем  байте (H) и младшем байте (L) получаемом с АЦП тачпанели. На последнем фото хорошо понятно что я получаю не 12 битное знаение а 11 битное. Грубо говоря точность снижается в 2 раза.  Да, я знаю что правильнее было бы вместо пропавшего бита ставить 0. Но мне лень :-).

sva_khv
Offline
Зарегистрирован: 19.12.2016

Теперь по подключению. Схему прилагаю. На F_CS и CDCS подаем лог 1 чтобы контроллеры CD карты и Флеш памяти не пытались подавать сигналы в SDI. 

Не забудте подключить питание (+5В) и землю (GND)

Сигнал от тача завел на прямую в Мегу. Меге уровня в 3,3В хватает. Хотя может и из за этого схема не работет на высокой частоте передачи данных.

sva_khv
Offline
Зарегистрирован: 19.12.2016

Теперь о настройках SDI.

1. У меня работает устойчиво при уменьшении тактовой частоты  в 8 раз и более. Возможно из за длинных проводов. В программе это настраивается так:

  SPI.setClockDivider(SPI_CLOCK_DIV8);  // SPI_CLOCK_DIV8 начинает работать с 8 и выше
 
2. Эксперементы с  настройками полярности тактовых импульсов и и фазой тактовых импульсов  результата не дали. (старший бит всегда 1)
 
SPI.setDataMode(SPI_MODE3);   //SPI_MODE0 SPI_MODE1 SPI_MODE2  SPI_MODE3  
sva_khv
Offline
Зарегистрирован: 19.12.2016

И сама программа. Постарался понаставить коментариев. Пробуйте, задавайте вопросы.

 


#include <UTFT.h>

#include <SPI.h>
#define csPin 53             // порт выбора устройства T_CS
#define penPin 2             // порт прерывания от тача PEN
#define TochXSme 170         // начальное смещение по X   конечное значение 1960
#define TochXMax 2000        //  X   конечное значение 1960
#define TochYSme 95          // начальное смещение по Y   конечное значение 1930
#define TochYMax 2000        //  Y   конечное значение 1930
#define TochXProp 5.7        //пропорция пересчета в пикселы экрана Х 
#define TochYProp 7.75       //пропорция пересчета в пикселы экрана Y
int iTochXTft,iTochYTft,iTochXAcp,iTochYAcp;                 // позиция каcания в координатах экрана

// описание экрана
UTFT    myGLCD(CTE32_R2,38,39,40,41);
// Declare which fonts we will be using
extern uint8_t BigFont[];

void setup()
{
// инициализация экрана
  myGLCD.InitLCD();
  myGLCD.clrScr(); 
  myGLCD.setFont(BigFont);
  myGLCD.setBackColor(VGA_WHITE);
  myGLCD.setColor(VGA_BLACK); 
 
//Initiallize the SPI1 port.
  SPI.begin(); 
  SPI.setClockDivider(SPI_CLOCK_DIV32);  // SPI_CLOCK_DIV8 начинает работать с 8 и выше
// эффекта не было
//   SPI.setDataMode(SPI_MODE3);   //SPI_MODE0 SPI_MODE1	SPI_MODE2  SPI_MODE3  
  
  
// инициализация порта выбора устройства  
  pinMode(csPin, OUTPUT);
  digitalWrite(csPin, HIGH);

// инициализация порта на который приходит сигнал прерывания от экрана PIN  
  pinMode(penPin, INPUT);

//    pinMode(13, OUTPUT);  digitalWrite(13, HIGH);  // контроль на светодиоде 13 порта прерывания с порта 2

// запуск тач панели - может и не надо.
//   digitalWrite(csPin, LOW);   //   SPI.transfer(0X80); //   digitalWrite(csPin, HIGH);
 
}

void loop()
{
  char Text[25];
  int i,iP;
//   int tmpH, tmpL; 
// переменые для тача
  float flP;
  byte  bX1,bX2,bYH,bYL;
  int x1=0,y1=0,x=0,y=0;

//  digitalWrite(csPin, LOW);

   myGLCD.clrScr();    
// проверяем есть ли сигнал от тача по прерыванию   
   iP=digitalRead(penPin);
//   if(iP==LOW)   digitalWrite(13, LOW);    else digitalWrite(13, HIGH);  //управление светодиодом на 13 порту
// если есть сигнал - принимаем данные от тача   
   if(iP==LOW)
   {
     i=Touch2046ReadXY(5);
     if(i>0)
     {       
     
// показ координат на экране
       itoa(Touch2046GetX(),Text, 10);        
       myGLCD.print(Text, 40,0);   
       itoa(Touch2046GetY(),Text, 10);       
       myGLCD.print(Text,120,0); 
       itoa(i,Text, 10);       
       myGLCD.print(Text,200,0); 
       
// отображения круга в месте касания
      myGLCD.setColor(VGA_SILVER);   
      myGLCD.fillCircle(Touch2046GetX(),Touch2046GetY(),10);      
      myGLCD.setColor(VGA_BLACK);       
      delay(500);      
     } 
   } 
}


// считывание координат нажатия из тачпанели 
// возвращает кол-во правильных считываний
// iKol =0 или 1 - считываем 1 раз  от 2 до 20 - считываем как указано. если >20 то считываем 20 раз
int Touch2046ReadXY(int iKol)
{
  float flP;
  byte  bXH,bXL,bYH,bYL;
  int x1=0,y1=0,x=0,y=0, iKolRead=20,iR,iKolReadOK=0;

      iTochXAcp=0;
      iTochYAcp=0;
  
       if(iKol<2) iKolRead=1;
       if(iKol>1&&iKol<20)  iKolRead=iKol;
// выбор устройства     
       digitalWrite(csPin, LOW);
       for(iR=0;iR<iKolRead;iR++)
       {
//даем команду на пересылку позиции Х
         SPI.transfer(0X90); 
// считываем старший байт
         bXH = SPI.transfer(0);
// убираем не нужный старший бит  !!!!!     
         bXH=bXH&0X7F;  //
         x=bXH;
// сдвигаем в лево на 4
         x=bXH<<4;            
// читаем младший байт
         bXL = SPI.transfer(0);
// убираем ненужный старший бит      
         bXL=bXL<<1;
// ставим нужные 4 байта в младшие разряды  
         bXL=bXL>>4;
         x1=bXL;      
// совмещаем два байта - данные Х с АЦП
         x=x|x1;
//даем команду на пересылку позиции Y
         SPI.transfer(0XD0); 
// считываем старший байт
          bYH = SPI.transfer(0);
// убираем не нужный старший бит  !!!!!     
          bYH=bYH&0X7F;  //
// сдвигаем в лево на 4
          y=bYH<<4;            
// читаем младший байт
          bYL = SPI.transfer(0);
// ставим в младшие разряды       
          bYL=bYL<<1;
          bYL=bYL>>4;
          y1=bYL;      
// совмещаем два байта и получаем данные c АЦП по Y
          y=y|y1;
// проверяем данные с АЦП - в ганицах экрана? Если да то берем среднее с предыдущими - правда разници при 1 и несколких считываний я не заметил
         if(x>=TochXSme&&x<=TochXMax&&y>=TochYSme&&y<=TochYMax)  
         {  iKolReadOK++;
            if(iTochXAcp==0)  iTochXAcp=x;
            else  iTochXAcp=(iTochXAcp+x)/2;
            if(iTochYAcp==0)  iTochYAcp=y;
            else  iTochYAcp=(iTochYAcp+y)/2;  
          
         }
       }   
// отключаем выбор устройства       
       digitalWrite(csPin, HIGH);         
// проверяем выход за границы
      if(iTochXAcp>=TochXSme&&iTochXAcp<=TochXMax&&iTochYAcp>=TochYSme&&iTochYAcp<=TochYMax) 

       { flP=(iTochXAcp-TochXSme)/TochXProp;       //пересчет в координаты дисплея
         iTochXTft=flP;
         flP=(iTochYAcp-TochYSme)/TochYProp;      
         iTochYTft=flP;       
         return(iKolReadOK);
       }  
       else 
       { 
         iTochXTft=0;
         iTochYTft=0;       
         return(0);
       }
   
}


// получение кординаты X
int Touch2046GetX(void)
{
  return(iTochXTft);
}
// получение кординаты Y
int Touch2046GetY(void)
{
  return(iTochYTft);
}

 

sva_khv
Offline
Зарегистрирован: 19.12.2016

Что получилось - координаты в пикселах десплея и круг в точке касания

 

 

slider
Offline
Зарегистрирован: 17.06.2014

:0) ....

и чем вам либа UTouch не угодила?  там хорошая калибровка есть . 

на дешевых шилдах нет делителя для XPT2046 , там тупо последовательно резисторы на 10 кОм.

 

 

sva_khv
Offline
Зарегистрирован: 19.12.2016

slider пишет:

и чем вам либа UTouch не угодила?  там хорошая калибровка есть . 

С этой библиотекой разбирался 2 дня. Сигнал нажатия на тач она отрабатывала. Но дальше дело не пошло. Залез во внутренности библиотеки - она сама получала от тача не верные данные и соответсвенно выдавала не координаты, а ошибку. (Я смотрел значения переменных  внутри библиотеки). Калибровку запускал, но толку не было.

slider пишет:

на дешевых шилдах нет делителя для XPT2046 , там тупо последовательно резисторы на 10 кОм.

Делитель чего? Частоты обмена или делитель уровня сигнала для согласования уровней 5<->3,3?

slider
Offline
Зарегистрирован: 17.06.2014

очередность там вроде такая

1. разархивируете некопанный UTouch (ибо применяя измененный UTouchCD.h могут быть проблемы)

2. в скетче калибровки меняете #define TOUCH_ORIENTATION  PORTRAIT на LANDSCAPE . Изменяете вызов инита UTFT    myGLCD(....,38,39,40,41);  под свой дисп. 

3. загружаете скетч , калибруете. Полученные данные на дисплее меняете в UTouchCD.h , сохраняете.

4. запускаете какой либо пример UTouch_QuickDraw или UTouch_QuickPaint с измененным вызовом инита под свой дисп. проверяете как все хорошо получилось.

 

// по делителю на резисторах что за вопрос, конечно согласованию уровней.

sva_khv
Offline
Зарегистрирован: 19.12.2016

slider пишет:

очередность там вроде такая  ...

 

Я все это мучил 2 дня. И схемы подключения менял и ориентацию экрана.

Калибровку имеет смысл делать если ты хоть какие то осмысленые данные кординаты получашь.

А если сама библиотека получает ерунду или ничего - то и выдает -1 вместо координат. Вот и пришлось копать глубже.

sva_khv
Offline
Зарегистрирован: 19.12.2016

Продолжение про тачпанель.

Набравшись опыта работы с Arduino и получив платы согласования уровня 3.3 <->5 спаял переходник для меги.

Экран сразу заработал. 

Подключил тач через переходник и запустил библиотеку UTouch - заработало! 

Подключение пинов и описание при инициализации

// Initialize touchscreen
// CLK(34),CS(T_CS-33), MOSI (30), MISO(29), PEN(31)   номера на экране 
URTouch  myTouch( 44, 45, 42, 43, 2);   // номера на меге
 

 

prorok1999
Offline
Зарегистрирован: 06.05.2016

[quote=sva_khv]

Продолжение про тачпанель.

Набравшись опыта работы с Arduino и получив платы согласования уровня 3.3 <->5 спаял переходник для меги.

Добрый день. А можно смеху или печатную плату или гербер файл переходника?

sva_khv
Offline
Зарегистрирован: 19.12.2016

prorok1999 пишет:
Добрый день. А можно смеху или печатную плату или гербер файл переходника?

Взял таких несколько штук

https://ru.aliexpress.com/item/IIC-I2C/32946387859.html?spm=a2g0v.10010108.1000014.1.88b035d02BYke1&pvid=ce78955c-29f7-4e59-8e02-b9db2c699a90&gps-id=pcDetailBottomMoreOtherSeller&scm=1007.13338.125185.0&scm-url=1007.13338.125185.0&scm_id=1007.13338.125185.0

И соединил входы-выходы через них.

Как это работает (не мое)

"Двунаправленный конвертер логических уровней позволяет понижать сигналы с 5 до 3.3вольт, или повышать с 3.3 до 5 вольт

К выводу HV подключается источник высокого напряжения (например 5в)
К выводу LV - низкого (например 3.3в)
Общий минус - к выводу GND
Теперь логическая единица высокого напряжения, поступающая на вывод HV - будет преобразована в логическую единицу низкого напряжения на выводе LV

И наоборот, логическая единица низкого напряжения на выводе LV будет преобразована в логическую единицу высокого напряжения на выводе HV"

 

kpmic
Offline
Зарегистрирован: 01.12.2019

Получил с Китаю 3.95" дисплей на ILI9488. Два дня с бубном пока запустил и победил зеркальное изображение.

Теперь проблема с Тачем, не могу запустить его. Кто нибудь запускал данный дисплей?

slider
Offline
Зарегистрирован: 17.06.2014

х.з. что вы делали и какие либы и как подключали. и тем естественно непонятно что у вас может быть. смотрите как подключать в инете , там много должно быть картинок как все вместе подключать.

1. тач тут есть ?   // просто здесь попадались индивиды которые спрашивали как подключить тач, которого на шилде нет.

2. CS c NRF , CS c конвертера уровней microSD , SC от тача , должны приходить на РАЗНЫЕ пины

kpmic
Offline
Зарегистрирован: 01.12.2019

Спасибо! Для данного дисплея ничего нет, он из новых.

Тач там есть - это средняя микросхема, зовется XPT2046.

После прозвонки на какие ноги выходит Тач  и подключения дополнительно библиотеки URTouch к UTouch все заработало.

Но возникла другая проблема, как развязать два устройства, работающие по шине SPI, они мешают друг другу. По раздельности работают, вместе отказываются. В теории все просто, но как их развести по времени в данном случае?

CS приходят на разные ноги, но это не помогло. Пока не выдернул ноги MISO, MOSI с дисплея , чтобы отключить Тач. Тач выходит не напрямую а через два коммутатора, две нижних микросхемы.

kpmic
Offline
Зарегистрирован: 01.12.2019

Данное устройство проектировалось без Тача и там уже присобачены кнопки, но поскольку дисплей с Тач хотелось бы его использовать а кнопки ликвидировать.

Milenko_M
Offline
Зарегистрирован: 11.12.2019

Hello kpmic ,

I have some display as You.The display works fine with ST7796S and ILI9488 driver and 16 bit setup.

But URTouch and UTouch library did not work with those drivers.

So can You show some example with XPT2046 please ?

slider
Offline
Зарегистрирован: 17.06.2014

kpmic , Milenko_M

сделайте качественное фото .

ссылку где покупали ?

на какие пины и как идет сигнал CS от микросхемы XPT2046 , и  CS от microSD ? 

прозвоните мультиметром  прохождение сигналов от XPT2046 и microSD, а то по фото не видать.  (китайцы вполне могут ошибиться с разводкой дорожек , случаи уже были)

что вы пишите в  URTouch  myTouch( .. , .. , .. , .. , .. );  ?

 

kpmic
Offline
Зарегистрирован: 01.12.2019

Здесь можно купить дисплей.

https://aliexpress.ru/item/4000035671218.html?spm=a2g0s.9042311.0.0.264d33edHxWGsY

Зачем Вам схема, вот Вам готовый результат, пользуйтесь. Кому интересно покопаться в потрохах, ДАТАШИТ в помощь.

#include <UTFT.h>
#include <UTouch.h>
#include <URTouch.h>
 
UTFT   Display(TFT32MEGA_2, 38, 39, 40, 41);                        // тип дисплея 3,95 MEGA (480x320 chip ILI9488)
 
#define T_CLK    52
#define T_CS      53
#define T_MOSI  51
#define T_MISO  50
#define T_IRQ    44
 
URTouch myTouch(T_CLK, T_CS, T_MOSI, T_MISO, T_IRQ);      // Создаём объект библиотеки URTouch
 
Milenko_M
Offline
Зарегистрирован: 11.12.2019

kpmic : thanks , the display works well with TFT32MEGA_2 and also the touch is working .

slider :  thanks also to You , the display is same as by kpmic .

http://www.lcdwiki.com/3.95inch_Arduino_Display-Mega2560

#include <UTFT.h>
#include <URTouch.h>

// Инициализация дисплея:
// ----------------------
 UTFT myGLCD(TFT32MEGA_2,  38,39,40,41   );            // тип дисплея 3,2  MEGA (480x320 chip ILI9481)

// Инициализация touchscreen:
// --------------------------
#define T_CLK 52
#define T_CS 53
#define T_MOSI 51
#define T_MISO 50
#define T_IRQ 44
 
URTouch myTouch (T_CLK, T_CS, T_MOSI, T_MISO, T_IRQ); // Create a URTouch library object

 

kpmic
Offline
Зарегистрирован: 01.12.2019

А почему Вы убрали UTouch, в описании к библиотеке URTouch написано, что без UTouch она не работает.

Milenko_M
Offline
Зарегистрирован: 11.12.2019

UTouch is not in use , it is replaced by URTouch.

 

 

slider
Offline
Зарегистрирован: 17.06.2014

kpmic, если бы вы хотя бы забили в яндекс -  Utouch , то вы бы знали 

 

, и что теперь она URTouch . и не надо объявлять 2 библиотеки старую и новую , а использовать только новую.

Milenko_M
Offline
Зарегистрирован: 11.12.2019

slider : спасибо, поздравления

 

kpmic
Offline
Зарегистрирован: 01.12.2019

Жизнь заставила поближе познакомиться с ДАТАШИТом на ILI9488 и обнаружил, что через шину SPI можно не только ТАЧем управлять, но и выводить информацию на дисплей. То есть из двурядной гребенки использовать только пять ножек а освободившиеся ноги использовать для других целей. Отсюда вопрос кто нибудь подключал данный дисплей через SPI и есть ли на него библиотека для подключения по SPI?

slider
Offline
Зарегистрирован: 17.06.2014

kpmic пишет:

Жизнь заставила поближе познакомиться с ДАТАШИТом на ILI9488 и обнаружил, что через шину SPI можно не только ТАЧем управлять, но и выводить информацию на дисплей. То есть из двурядной гребенки использовать только пять ножек а освободившиеся ноги использовать для других целей. Отсюда вопрос кто нибудь подключал данный дисплей через SPI и есть ли на него библиотека для подключения по SPI?

в чем проблема ? конечно подключали , если его spi пины выведены . 
Но походу если вы спрашиваете , скорее всего у вашего диспа они не выведены. 
тогда либо применять микросхему регистр , либо покопаться в шлейфе диспа , в надежде вдруг в него со стекла идут нужные пины , резать иголкой зачищать и подпаиваться к ним. зачастую spi выводы не выводят в шлейф для 8/16 битных.

// если забьете в местный поиск -  дисплей spi , то можно что то доп. найти.
http://arduino.ru/forum/apparatnye-voprosy/pomogite-zapustit-24tft-lcd-s-ili9341-v-rezhime-spi#comment-286963 
http://arduino.ru/forum/apparatnye-voprosy/tft-35-i-arduino?page=25#comment-308079 
 http://arduino.ru/forum/apparatnye-voprosy/tft-35-i-arduino?page=25#comment-308082 
в теме "дисплеи от сотиков" были где-то фотки поиска  SPI дорожек идущих в шлейф. (местный поиск не позволяет отдельно в теме искать, ищет по всему форуму)
// сигналы CS ( ChipSelect ) от тача и дисплея надо приводить на разные пины ардуино , все остальные SPI выводы параллелятся.
 

 

fercmann
Offline
Зарегистрирован: 27.07.2021

sva_khv ! Огромное тебе спасибо за решение по XPT2046.

С уважением, fercmann.