W tym poście opiszę sposób implementacji wyświetlacza firmy Waveshare.
Wyświetlacz został skonfigurowany do wersji BSP 2.8b6.
Podłączenie sprzętowe:
Opis pinów wyświetlacza wygląda następująco:
Z wyświetlacza zostały wyprowadzone dwie tasiemki jedna dla panelu dotykowego, druga dla linii wyświetlacza.
Opis linii wyświetlacza:
VLED- - katoda podświetlenia ekranu
VLED+ - anoda podświetlenia ekranu
GND - masa wyświetlacza
VCC - zasilanie wyświetlacza
R0 - R7 - 8 linii wyświetlacza odpowiedzialnych za kolor czerwony.G0 - G7 - 8 linii wyświetlacza odpowiedzialnych za kolor zielony.
B0 - B7 - 8 linii wyświetlacza odpowiedzialnych za kolor niebieski.
CLK - sygnał służący do wysterowania komunikacji.
R/L - Right/Left Selection.
HSync - odświeżanie poziome. Informacja o przejściu do następnej linii.
VSync - odświeżanie pionowe. Informacja o zakończeniu rysowania wszystkich linii.
U/D - Up/Down Selection.
Reset - reset wyświetlacza.
Konfiguracja skanowania w zależności od ustawienia stanu na pinach R/L oraz U/D:
Wyświetlacz domyślnie wykorzystuje paletę kolorów RGB565. Po delikatnych modyfikacjach na wyświetlaczu (zmianie podciągania pinu sterującego z VCC do GND, zmiana wykonana na taśmie wyświetlacza) pozwala na działanie z paletą kolorów RGB888.
Sposób podłączenia wyświetlacza można znaleźć w dokumentacji modułu [link]:
Ustawienia czasowe wyświetlacza można znaleźć w datasheet:
Wyświetlacz wykorzystuje interfejs równoległy. Jego zaletą jest duża prędkość działania oraz bezpośredni zapis danych do wyświetlacza z linii RGB. Pewnym problemem w tego rodzaju rozwiązaniach jest brak standardowego złącza (co dosyć mocno ogranicza zmianę modelu wyświetlacza w już gotowym projekcie), duża ilość linii do podłączenia oraz występujące zakłócenia, które ograniczają możliwość stosowania długiego połączenia. Dodatkowym problemem jest brak możliwości wykrycia wyświetlacza przez programistę. Co oznacza konieczność wprowadzania jego definicji w kodzie sterownika oraz Device Tree systemu.
Modyfikacja sterownika:
Na samym początku należy zmodyfikować plik linux-toradex/drivers/video/fbdev/mxc/mxc_lcdif.c, przez dodanie do niego parametrów wyświetlacza:
- {
- /* RCP-KD LCD WinStar WF70YTIAGDNG0# (7" 800x480 24bit) */
- "WINSTAR-WVGA",
- 60, /* refresh */
- 800, 480, /* xres, yres */
- 30000, /* pixclock */
- .left_margin = 26,
- .right_margin = 210,
- .hsync_len = 20,
- .upper_margin = 13,
- .lower_margin = 22,
- .vsync_len = 10,
- .sync = FB_SYNC_CLK_LAT_FALL,
- .vmode = FB_VMODE_NONINTERLACED,
- .flag = 0,
- },
Powyższa deklaracja zawiera tryby działania wyświetlacza
Definicja struktury do której dane są wprowadzone znajduje się w pliku linux-kernel/include/linux/fb.h:
- struct fb_videomode {
- const char *name; /* optional */
- u32 refresh; /* optional */
- u32 xres;
- u32 yres;
- u32 pixclock;
- u32 left_margin;
- u32 right_margin;
- u32 upper_margin;
- u32 lower_margin;
- u32 hsync_len;
- u32 vsync_len;
- u32 sync;
- u32 vmode;
- u32 flag;
- };
Opis zmiennych jest następujący:
refresh - 60 - Częstotliwość odświeżania.
xres, yres - 800, 480 - widoczny obszar wyświetlacza
left_margin, right_margin - margines lewy i prawy w pixelach.
upper_margin, lower_margin - margines dolny i górny w liniach.
hsync_len, vsync_len - długość sygnałów synchronizacji.
sync - FB_SYNC_CLK_LAT_FALL - negatywna polaryzacja sygnału zegarowego (ang. Negative polarity of pixel clock)
vmode - FB_VMODE_NONINTERLACED - skanowanie linii wyświetlacza od góry do dołu (ang. Non interlaced video) (link)
Modyfikacja Device Tree:
Teraz należy zmodyfikować Device Tree w celu obsługi wszystkich linii wyświetlacza. Przykładowy plik device tree od producenta modułów Colibri można znaleźć pod tym linkiem, dodatkowo można posłużyć się definicjami zapisanymi w plikach imx6dl-colibri-cam-eval-v3.dts czy imx6dl-colibri-aster.dts
- &pinctrl_ipu1_lcd {
- fsl,pins = <
- MX6QDL_PAD_DI0_DISP_CLK__IPU1_DI0_DISP_CLK 0xa1
- MX6QDL_PAD_DI0_PIN15__IPU1_DI0_PIN15 0xa1
- MX6QDL_PAD_DI0_PIN2__IPU1_DI0_PIN02 0xa1
- MX6QDL_PAD_DI0_PIN3__IPU1_DI0_PIN03 0xa1
- MX6QDL_PAD_DISP0_DAT0__IPU1_DISP0_DATA00 0xa1
- MX6QDL_PAD_DISP0_DAT1__IPU1_DISP0_DATA01 0xa1
- MX6QDL_PAD_DISP0_DAT2__IPU1_DISP0_DATA02 0xa1
- MX6QDL_PAD_DISP0_DAT3__IPU1_DISP0_DATA03 0xa1
- MX6QDL_PAD_DISP0_DAT4__IPU1_DISP0_DATA04 0xa1
- MX6QDL_PAD_DISP0_DAT5__IPU1_DISP0_DATA05 0xa1
- MX6QDL_PAD_DISP0_DAT6__IPU1_DISP0_DATA06 0xa1
- MX6QDL_PAD_DISP0_DAT7__IPU1_DISP0_DATA07 0xa1
- MX6QDL_PAD_DISP0_DAT8__IPU1_DISP0_DATA08 0xa1
- MX6QDL_PAD_DISP0_DAT9__IPU1_DISP0_DATA09 0xa1
- MX6QDL_PAD_DISP0_DAT10__IPU1_DISP0_DATA10 0xa1
- MX6QDL_PAD_DISP0_DAT11__IPU1_DISP0_DATA11 0xa1
- MX6QDL_PAD_DISP0_DAT12__IPU1_DISP0_DATA12 0xa1
- MX6QDL_PAD_DISP0_DAT13__IPU1_DISP0_DATA13 0xa1
- MX6QDL_PAD_DISP0_DAT14__IPU1_DISP0_DATA14 0xa1
- MX6QDL_PAD_DISP0_DAT15__IPU1_DISP0_DATA15 0xa1
- MX6QDL_PAD_DISP0_DAT16__IPU1_DISP0_DATA16 0xa1
- MX6QDL_PAD_DISP0_DAT17__IPU1_DISP0_DATA17 0xa1
- MX6QDL_PAD_DISP0_DAT18__IPU1_DISP0_DATA18 0xa1
- MX6QDL_PAD_DISP0_DAT19__IPU1_DISP0_DATA19 0xa1
- MX6QDL_PAD_DISP0_DAT20__IPU1_DISP0_DATA20 0xa1
- MX6QDL_PAD_DISP0_DAT21__IPU1_DISP0_DATA21 0xa1
- MX6QDL_PAD_DISP0_DAT22__IPU1_DISP0_DATA22 0xa1
- MX6QDL_PAD_DISP0_DAT23__IPU1_DISP0_DATA23 0xa1
- >;
- };
Podświetlenie realizowane jest z PWM3:
- &backlight {
- pwms = <&pwm3 0 5000000 1>;
- brightness-levels = <0 4 8 16 32 64 128 255>;
- default-brightness-level = <6>;
- status = "okay";
- };
Należy tutaj pamiętać, że przy takiej konfiguracji nie można osiągnąć czasu wypełnienia impulsu z przedziału od 0 do 50%. Wybranie wartości 1, do której jest przypisana wartość 4, da wypełnienie prawie 100%. Wartość 7 do której przypisana będzie wartość 255 spowoduje wygenerowanie PWM o współczynniku wypełnienia 0.
CTP FT5426 wykorzystujący interfej I2C również musi zostać opisany w DT [link]:
- aliases {
- i2c0 = &i2cddc;
- i2c1 = &i2c2;
- i2c2 = &i2c3;
- };
- &i2c3 {
- status = "okay";
- //...
- //...
- edt_ft5x06: edt-ft5x06@38 {
- compatible = "edt,edt-ft5406", "edt,edt-ft5x06";
- reg = <0x38>;
- interrupt-parent = <&gpio2>;
- interrupts = <24 IRQ_TYPE_EDGE_FALLING>;
- reset-gpios = <&gpio1 14 GPIO_ACTIVE_LOW>;
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_edt_ft5x06>;
- };
- };
- pinctrl_edt_ft5x06: edt-ft5x06 {
- fsl,pins = <
- MX6QDL_PAD_EIM_CS1__GPIO2_IO24 0x130b0 /* Interrupt */
- MX6QDL_PAD_SD2_DAT1__GPIO1_IO14 0x80000000 /* Reset */
- >;
- };
Sterownik jest standardowo umieszczony w projekcie jądra systemu.
Dodatkowo w opcji nconfig (make menuconfig) należy uruchomić sterownik:
Device Drivers->Input device support->Touchscreens->EDT FocalTech FT5x06 I2C Touchscreen support"->y
Następnie zostało skompilowanie jądra systemu z przygotowanych plików.
- //Kompilacja wszystkich plików dts
- make dtbs
- make colibri_imx6_defconfig
- make nconfig
- make -j$(nproc) zImage LOADADDR=10008000 2>&1 | tee build.log
- make imx6dl-colibri-custom-board.dtb
Modyfikacja uEnv.txt:
Urządzenie wyjściowe, czyli ekran, jest kontrolowany przez U-Boot. Oznacza to konieczność modyfikacji wartości zapisanych także w pliku uEnv.txt. Przykładowe konfiguracje można pobrać z tego [link] [link] [link]:
panel=wvga-rgb
vidargs=video=mxcfb0:dev=lcd,WINSTAR-WVGA,if=RGB24,bpp=32 video=mxcfb1:off fbmem=8M
Komenda przyjmuje następujący format:
- video=mxcfb<number>:dev=<Output>,<Mode Specifier>,if=<Output Format>,[bpp=<Framebuffer Depth>]
panel=wvga-rgb - rodzaj wyświetlacza (u-boot-toradex/board/toradex/colibri_imx6/colibri_imx6.c)
vidargs=video=mxcfb0 - Domyślny stosowany ekran
dev=lcd, WINDSTAR-WVGA - wybranie interfejsu wyjściowego, lcd oznacza RGB. Po przecinku podana jest nazwa wyświetlacza.
if=RGB24 - definicja danych wyjściowych.
bpp=32 - wielkość bufora ramki danych.
video=mxcfb1:off - wyłączony inny drugi wyświetlacz
fbmem=8M - rozmiar pamięci przygotowanej dla każdej ramki danych wysyłanej do wyświetlacza.
Uruchomiony ekran z załadowanym domyślnym pulpitem wygląda następująco:
Przed uruchomieniem pulpitu na ekranie powinny wyświetlić się pingwiny. Ich ilość odpowiada ilości rdzeni procesora.
Ustawione parametry wyświetlacza można sprawdzić przez komendę fbset [link];
Panel dotykowy można sprawdzić następującymi komendami:
Sprawdzenie podłączonych urządzeń do interfejsów I2C można sprawdzić przez komendę:
- i2cdetect -y -r <numer_interfejsu>
Panel dotykowy jest podłączony do interfejsu I2C-2. Adres podłączonego układu można sprawdzić odpowiednią komendą:
- evtest /dev/input/event0
Wynik działania komendy jest następujący:
W celu uzyskania punktu kliknięcia na ekranie należy przetworzyć otrzymane wartości (ABS_X, ABS_Y):
- posX = (click/max_x_value) * x_max_screen_resolution
- posY = (click/max_y_value) * y_max_screen_resolution