Biblioteki graficzne Microchipa: obsługa touch-panela i LCD ze sterownikiem SSD1289
Teraz można było ocenić jakość matrycy wyświetlacza. Pomimo niskiej ceny wyświetlany obraz jest kontrastowy i wyraźny. Nie zauważyłem wyraźniej różnicy pomiędzy tym wyświetlaczem, a wyświetlaczem z fabrycznego modułu MEB. Ekran wyświetla się bez dużych opóźnień. To zapewne zasługa szybkiego mikrokontrolera, ale też 16-bitowej równoległej magistrali (mimo zastosowania programowej emulacji).
W tym momencie możemy uznać, że integracja wyświetlacza z biblioteką zakończyła się częściowym sukcesem. Częściowym, bo przed nami jeszcze ważny element: obsługa interfejsu dotykowego, pozwalająca na interakcję graficznego interfejsu z użytkownikiem.
Panel dotykowy – obsługa sterownika XPT2046
Jak już wspomniałem wyświetlacz jest wyposażony w 4-przewodowy rezystancyjny panel dotykowy. Taki panel może być obsłużony przez mikrokontroler z wbudowanym przetwornikiem analogowo cyfrowym, lub za pomocą dedykowanego kontrolera – naszym przypadku jest to kontroler XPT2046. Biblioteka Microchipa wspiera obsługę przy pomocy przetwornika (plik TouchScreenResistive.c ), oraz za pomocą specjalizowanego kontrolera Microchipa AR1020 (plik AR1020.c ). Jak widać nie ma wsparcia dla XPT2046 i w zasadzie prawie identycznego układu ADS7843. Dlatego trzeba napisać obsługę od podstaw.
Zasada działania pomiaru zmiany rezystancji rezystancyjnego panelu dotykowego jest opisana w wielu źródłach. Można tez o tym poczytać w dokumentacji układu.
XPT2046 komunikuje się z mikrokontrolerem z pomocą szeregowego interfejsu SPI. Podobnie jak w przypadku komunikacji ze sterownikiem wyświetlacza obsługa magistrali została wykonana programowo, bo w trakcie uruchamiania w programowych emulacjach łatwiej jest znaleźć błędy. Po uruchomieniu , kiedy wszystko działa można zamienić programową obsługę na transmisje wykonywana przez sprzętowe moduły komunikacyjne.
Magistrala SPI składa się z linii (z punktu widzenia XPT2046): danych wyjściowych DOUT, danych wejściowych DIN, zegara taktującego DCLK, oraz linii aktywacji interfejsu CS. Interfejs komunikacyjny jest uzupełniony o linię sygnalizacyjną PENIRQ. Na listingu 12 pokazano definicję linii portów, a w tabeli 2 połączenie z wyświetlaczem.
List. 12. Definicja linii interfejsu SPI XPT2046
#define TP_DCLK PORTCbits.RC3 #define TP_DCLK_TRIS TRISCbits.TRISC3 #define TP_DIN PORTGbits.RG1 #define TP_DIN_TRIS TRISGbits.TRISG1 #define TP_DOUT PORTGbits.RG0 #define TP_DOUT_TRIS TRISGbits.TRISG0 #define TP_CS PORTCbits.RC4 #define TP_CS_TRIS TRISCbits.TRISC4 #define TP_PENIRQ PORTAbits.RA6 #define TP_PENIRQ_TRIS TRISAbits.TRISA6
Tab. 2. Połączenie interfejsu SPI z wyświetlaczem
Linia interfejsu |
Wyprowadzenie modułu wyświetlacza |
Linia portu GPIO |
TP_DIN Dane wejściowe DIN |
T_DIN |
RG1 |
TP_DOUT Dane wyjściowe DOUT |
T_DOUT |
RG0 |
TP_CLK Zegar |
T_CLK |
RC3 |
TP_CS Wybór interfejsu |
T_CS |
RC4 |
TP-PENIRQ sygnalizacja naciśnięcia |
T_IRQ |
RA6 |
Po zdefiniowaniu linii trzeba je z zainicjować przez zdefiniowanie kierunku (wejście/wyjście) , oraz stanu początkowego linii – listing 13.
List. 13. Inicjalizacja interfejsu SPI dla XPT2046
void InitTpSpi(void) { TP_CS_TRIS=0; TP_DCLK_TRIS=0; TP_DIN_TRIS=0; TP_DOUT_TRIS=1; TP_PENIRQ_TRIS=1; TP_CS=1; TP_DCLK=1; TP_DIN=1; TP_CS=1; }
Do komunikacji z układem potrzebne będą dwie procedury: zapisu 8-bitowej danej (listing 14) i odczytu 12-bitowej danej (listing 15). Do sterownika będziemy zapisywać komendy sterujące jego pracą, a potem odczytywać 12-bitową wartość rezystancji zmierzoną przez przetwornik analogowo cyfrowy.
List. 14. Zapis danej 8-bitowej do XPT2046
void WriteTpSpi(unsigned char data) { unsigned char i=0; TP_DCLK=0; for(i=0;i<8;i++) { if((data&0x80)==0) TP_DIN=0; else TP_DIN=1; Delay(); TP_DCLK=0; Delay(); TP_DCLK=1; Delay(); data<<=1; } Delay(); }
List. 15. Odczyt danej 12-bitowej z XPT2046
short ReadTpSpi(void) { unsigned char i=0; unsigned short data=0; TP_DOUT=0; for(i=0;i<12;i++) { TP_DCLK=1; ;Delay(); TP_DCLK=0; ;Delay(); if(TP_DOUT) { data|=1; } data<<=1; Delay(); } return(data); }
W trakcie uruchamiania transmisji napotkałem na nieoczekiwane problemy. Procedury zostały sprawdzone ze sprzętowym emulatorem modułu PIC32 Starter Kit i zgodnie z dokumentacją powinny działać prawidłowo. Jednak po normalnym uruchomieniu komunikacja nie działała. Obserwacja przebiegu transmisji na oscyloskopie cyfrowym pokazała, że przyczyną problemów były zbyt małe opóźnienia po zmianach stanów na liniach interfejsu SPI. Dodanie dodatkowego opóźnienia Delay() wyeliminowało ten problem.
Pomiar położenia naciskanego punktu powinien się rozpocząć po wykryciu momentu naciśnięcia folii panelu dotykowego. Wykrycie naciśnięcia można wykonać programowo testując wartości odczytane z modułu. XPT2046 ma wyprowadzenie PENIRQ, które w czasie naciśnięcia folii przechodzi w stan niski. Wystarczy testować stan PENIRQ by wiedzieć czy panel został przyciśnięty, czy nie . Ja oczywiście skorzystałem z tego mechanizmu bo jest dużo prostszy w realizacji i pewny w działaniu.
Po wykryciu naciśnięcia można przystąpić do odczytania położenia naciśniętego miejsca. Takie miejsce jest identyfikowane przez współrzędne x oraz y. Jeżeli wyświetlacz ma rozdzielczość 240x320pikseli, to:
- x zmienia się w zakresie 0<x<319, a
- y w zakresie 0<y<239
dla poziomej orientacji ekranu.
Programowa identyfikacja położenia będzie polegała na odczytaniu współrzędnej x , a potem współrzędnej y . O tym która współrzędna będzie czytana i z jaka rozdzielczością decyduje 8-bitowy kod komendy:
Bit7 |
Bit6 |
Bit5 |
Bit4 |
Bit3 |
Bit2 |
Bit1 |
Bit0 |
S |
A2 |
A1 |
A0 |
MODE |
SER/DFR |
PD1 |
PD0 |
S- bit startu pomiaru (konwersji ADC) – aktywna jedynka
A2…A0 – wybór kanału pomiarowego przetwornika ADC
MODE – rozdzielczość pomiaru: „1” - 12-bitowy, „0” - 8-bitowy
SER/DFR topologia układu wejściowego: jedynka wejście Single Ended, zero wejście różnicowe
PD1…PD0 - tryb poboru mocy w stanie pomiędzy pomiarami
Żeby wyzwolić pomiar trzeba ustawić bit startu S, wybrać kanał pomiarowy i skonfigurować przetwornik ADC. Dla panelu o rozmiarach 320x240 pikseli wybieramy pomiar o rozdzielczości 12-bitowej, z wejściem różnicowym.
Bity PD01..PD0 będą zerowane, tak by pomiędzy pomiaramiXPT2046 przechodził w stan oszczędzania energii Power Down . Odczytanie współrzędnej x będzie wymagało wysłania komendy 0x90, a odczytanie współrzędnej y komendy 0xD0. Po wysłaniu komendy za pomocą WriteTpSpi(cmd) można odczytać wynik konwersji przez wywołanie procedury ReadTpSpi() . Ponieważ SPI jest emulowane programowo, to procedura wysyła tylko 12 taktów zegara i odczytuje 12 bitów wyniku. W przypadku modułów sprzętowych potrzeba będzie wysłać 16 taktów zegara i z wyniku odczytu wziąć 12 młodszych bitów.
Rys. 6. Przebiegi czasowe sekwencji odczytu współrzędnej
Przebiegi czasowe sekwencji odczytu współrzędnej zostały pokazane na rysunku 6. Trzeba pamiętać, że po wysłaniu komendy układ potrzebuje czasu na wykonanie pomiaru i zmierzona wartość można odczytać po pewnym czasie o wysłania komendy. Do sygnalizowania tego stanu jest przeznaczone wyprowadzenie BUSY. My z niego nie skorzystamy, a potrzebne opóźnienie zostanie odliczone programowo. Do odczytania współrzędnych są wykorzystywane 2 funkcje:
- TouchGetXRAW() – listing 16,
- TouchGetYRAW – listing 17.