neděle 27. března 2016

Displej s dotykovou vrstvou na různých mikrokontrolérech

Podražily OLED displeje, ale zlevnily TFT LCD, tak jsem si koupil další - krásně velký 2,8" s ILI9341 a dotykovou vrstvou, kterou čte XPT2046 (AliExpress):


Tento displej se připojuje k počítači sériově přes SPI, ovšem nenabízí jen jedno SPI rozhraní, ale rovnou tři!

První SPI je pro obrazová data, je na pinech na levé hraně, v dolní části. Druhé SPI rozhraní je pro dotykovou vrstvu a je taktéž na pinech vlevo, ale na horních pěti (označených TOUCH). A poslední SPI rozhraní je pro čtečku SD karet a je vyvedeno na obrázku vpravo (který jsem trošku moc ořízl, takže ty vývody nejsou vidět).

SPI sběrnice umožňuje připojit několik slave zařízení naráz, takže jsem logicky propojil SDI (MOSI) s T_DIN, SDO (MISO) s T_DO a SCK s T_CLK. A pak jsem to zkoušel rozjet na třech různých mikrokontrolérech: Arduinu, STM32F103 a ESP8266.

Ještě než napíšu jak jsem dopadl, musím zdůraznit, že displej je prodejcem inzerován jako "5V/3.3V", což může kvalitně zmást. Pravda je, že napájení (VCC) může být 3,3 nebo 5 V, protože zespodu displeje je lineární regulátor napětí nastavený na 3,0 V. Dokonce bych řekl, že je lepší, když je displej napájený 5 V, protože se mi choval stabilněji, ale možná se mi to jen zdálo (v nepájivém kontaktním poli často zlobí jednotlivé drátky a výsledky pokusů nejsou zrovna směroplatné). Pokud ho napájíme jen 3,3 V, ze kterých si ten regulátor uzobne 0,3 V pro sebe, tak pak displej může dostat i méně než 3 V a nepracuje se mu možná tak dobře. Na to jsou tam ostatně ty dvě pájecí plošky hned pod regulátorem, které můžeme páječkou jednoduše propojit, čímž regulátor vyřadíme z cesty a displej pak má plných 3,3 V.

Zároveň ten prodejcův příslib "5V/3.3V" neznamená, že kterákoliv ze tří SPI sběrnic je 5V tolerantní! Proto pokud připojujeme displej k 5V mikrokontroléru, jakým je například Arduino, musíme zařadit do SPI cesty "level shifter", měnič napěťových úrovní, jinak bychom mohli něco v displeji usmažit. Jako převodník poslouží například obvod CD4050E nebo některý z hotových prodávaných modulů osazených MOSFET tranzistory.

Mimochodem, podsvícení displeje (pin označený jako "LED") funguje stejně dobře na 3,3 V i na 5 V a nevidím tam ani rozdíl v úrovni podsvícení.

Ještě pár slov k použitým knihovnám. Přestože je komunikace s XPT2046 poměrně jednoduchá, neztrácel jsem čas psaním vlastní knihovny, a místo toho jsem si našel již hotová řešení (a pak ztrácel čas s nimi). První knihovnu pro své Teensy napsal Paul Stoffregen a je dostupná pod názvem XPT2046_Touchscreen na https://github.com/PaulStoffregen/XPT2046_Touchscreen. Druhá je od Spirose Papadimitrioua https://github.com/spapadim/XPT2046 a na rozdíl od první vyžaduje zapojení i pinu T_IRQ. Třetí je od Bodmera https://github.com/Bodmer/TFT_Touch/ a nepoužívá hardwarovou SPI sběrnici mikrokontroléru, takže může být připojena na kterékoliv piny a obslouží si je ručně. To jsem zprvu považoval za nevýhodu a knihovnu tak vyřadil z dalších testů, ovšem dnes už to vidím trošku jinak...

Jako grafickou knihovnu pro ILI9341 jsem použil velmi známou Adafruit_GFX se svým Adafruit_ILI9341 ovladačem. Adafruit podporuje už nejen Arduino, ale i ESP8266, takže se mi zdálo super, že použiju jednu knihovnu pro všechny tři mikrokontroléry.

Nyní už tedy jak jsem dopadl: první testy probíhaly na ESP8266. Tam XPT2046_Touchscreen nefungoval při testech vůbec. Ladicí hlášky ukazovaly, že vrací nesmyslně vysoké hodnoty tlaku (od 4 do 8 tisíc) a hodnoty polohy pochodovaly v cyklu v celém ADC rozsahu. Zkusil jsem tedy knihovnu XPT2046 a ta nefungovala taktéž, přestože podle pěkného článku na http://nailbuster.com/?page_id=341 fungovat měla. Asi se ty knihovny nějak nepohodly o právo komunikace na sběrnici, nebo jedna nastavila rychlost, které druhá nestačila nebo něco podobného. Nakonec pomohlo vyměnit grafickou knihovnu od Adafruitu za upravenou verzi zvanou "Adafruit_ILI9341esp" (která je ke stažení na výše uvedeném článku) a pak se vše perfektně rozběhlo. Bohužel jsem nebyl sto na první pohled poznat, co je v té "ILI9341esp" verzi změněno tak, že XPT2046 už s ní nekoliduje (neboť tam bylo příliš mnoho rozdílů), ale neměl jsem dost času, tak jsem to přestal řešit a smířil se s tím, že stačí použít "esp" verzi grafické knihovny a dotyková vrstva funguje (resp. ta daná knihovna pak správně komunikuje).

Další testy proběhly na ARMu STM32F103 - resp. na Maple Mini. Použil jsem "plugin" z www.stm32duino.com, který se "zasune" do Arduino IDE 1.6.x. Díky tomu mi přijela i opět jaksi upravená knihovna Arduino_ILI9341_STM, kterou jsem zkusil a fungovala výborně (asi 20x rychleji než na Arduinu nebo ESP8266). K ní jsem zkusil přidat obě výše zmíněné XPT2046 knihovny, ale dle očekávání žádná nefungovala. Pro sdílení SPI mezi dvěma různými zařízeními jsou totiž potřeba SPI transakce, které ale moje (starší?) verze STM32 "pluginu" pro Arduino IDE nepodporovala. Takže konec, žádné dotyky. Ovšem teď zpětně si říkám, že jsem měl použít tu knihovnu od Bodmera a jednoduše připojit TOUCH piny k některým z 30 volných pinů STM32F103...

Poslední na řadu přišlo Arduino Pro Mini: knihovna XPT2046_Touchscreen fungovala ihned, ale vracela hodnoty otočené o 90 stupňů, nebo prostě prohozené osy X a Y. Chvíli mě to bavilo, ale pak jsem raději přešel na knihovnu XPT2046, která se mi osvědčila na ESP8266. Tady ovšem nefungovala a ještě navíc rozbila kreslení obrazu. Asi se ty dva čipy porvaly o SPI sběrnici jako na ESP8266.

O správném připojení a ovládání více zařízení na jedné SPI sběrnici napsal pěkný článek výše už zmíněný Paul - http://www.dorkbotpdx.org/blog/paul/better_spi_bus_design_in_3_steps. Zkusil jsem upravit knihovnu XPT2046 podle jeho rad: nejdřív jsem do ní přidal podporu transakcí, a když to nestačilo, tak jsem ještě korektně předinicializoval obě CS linky, jak Paul doporučuje.

Přesto příklad kreslicí aplikace XPTPaint (v "examples" u XPT2046) pořád nefungoval, než jsem s úžasem zjistil, že v jedné ose vrací knihovna hodnoty od 0 do 20 a pak naráz skáče až na 56738 a až ke druhé straně obrazovky drží tento nesmyslný ofset (který nevím, kde se bere). Z nedostatku času jsem to vyřešil následujícím hackem (přidáním jednoho řádku do aplikace XPTPaint):

   touch.getPosition(x, y);
   if (x > 56730) x -= 56710; // WTF!?

Od té chvíle fungovalo na Arduinu s Adafruit_ILI9341 a XPT2046 vše v pořádku a mohl jsem nehtem malovat jak na malířském plátně.

Měl bych teď, po správné implementaci transakcí do XPT2046, ji znovu zkusit na ESP8266 s jinými ILI9341 knihovnami, ale nevím, kdy se k tomu dostanu. Taktéž bych měl zjistit, kde se na Arduinu bere ten nesmyslný ofset (možná přeteče nějaká proměnná?). A také bych měl zkusit pohledat na stm32duino.com, jestli už nemají SPI s transakcemi. Hmmm, napíšu, jestli se k něčemu z toho někdy dostanu.

8 komentářů:

  1. Ahoj. Pro ESP8266 to mám funkční včetně podpory transakcí zde http://www.xpablo.cz/?p=923 ...

    OdpovědětVymazat
    Odpovědi
    1. Pro ESP8266 je popsána funkční konfigurace i v mém článku. Zajímavější by byly funkční konfigurace pro ARM či aspoň pro Arduino :-)

      Vymazat
  2. Díky za článek. Chtěl jsem se zeptat, zda jste náhodou neměřil spotřebu displeje?

    David

    OdpovědětVymazat
    Odpovědi
    1. Neměřil. Můžu změřit a doplnit do článku. Je to zajímavá otázka - jestli víc žere to podsvícení nebo elektronika a samotný displej.

      Vymazat
  3. Ahoj, mohl by jste ukázat podrobněji zapojení k arduinu? Mám stejný displej, ale nedaří se mi jej rozchodit.

    Děkuji

    OdpovědětVymazat
    Odpovědi
    1. Je to naprosto standardní SPI zapojení (tj. MOSI displeje na 11 Arduina, CS na 10, SCK na 13 a MISO displeje se na 12 Arduina zapojovat nemusí) s tím, že LED a RESET můžou jít rovnou na VCC displeje.

      Připomínám, že mi displej nechtěl fungovat na 5V logice.

      Vymazat
  4. OK... Grafická část mi jede... UNO, Adafruit_GFX a Adafruit_ILI9341. Level shiftery na všech vstupech...
    Zajímavé je, že se mi to rozjelo až poté, co jsem RESET připojil na D8 UNA..
    Pokud jsem to připojil na VCC, jak píšeš, tak to svítilo bíle a nic nezobrazovalo...
    Nicméně - píšu proto, že se mi nedaří rozchodit dotyková část...
    Pokud propojím SCK s T_CLK, jak je uvedeno v článku, začne se obraz rozpadat :-(
    XPT2046_Touchscreen mi nefunguje vůbec - Hází to v převážné většině případů Pressure = 4103, x = 24, y = 18
    Nemohl bys postnout tu tvou, upravenou knihovnu?
    Dík!

    OdpovědětVymazat
    Odpovědi
    1. Aha, tak s tím resetem jsem si to spletl s jiným displejem, testoval jsem jich vícero (OLED i TFT). Obecně je samozřejmě lepší ten RESET připojit na pin procesoru a pak provést pořádný HW reset programově, než se pokoušet inicializovat displej jen softwarově - to často selže. Možná jsem si to spletl s CS signálem, ten se někdy dá hodit na pevno, pokud na SPI není víc zařízení.
      Co se týče rozpadání obrazu, tak to vypadá, že T_CLK nějak ovlivňuje SCK (což by neměl). Asi by pomohlo rozdělit signál ještě u Arduina na dva vstupy level shifterů a jejich výstupy zapojit zvlášť na SCK a na T_CLK.
      Tu knihovnu můžu někam dát, ale ta úprava byla velmi trapná - měl bych spíš zjistit, co je tam za chybu a opravit to pořádně.

      Vymazat