參考連結
前言
Linux 並沒有正式支援 SPI 界面的 LCD 螢幕,在 Armbian 下是透過 Overlay 來連接 SPI 界面的 LCD 螢幕。
在網路上找到的資料,都是舊的作法,香橙派的用户手册中查找到的驱动方法,也是只能在 linux 4.9 下驅動屏幕的方案。 但 Orange PI zero3 最近的系统是 debian bookworm linux6.1.31,因此不能用舊的方法驅動。
最先是在 CSDN 找到一篇,是新的作法,照著做,可以成功地輸出顯示到 LCD,但觸控功能沒有啟動。後來又找到相關的作法,把觸控功能也啟動了。
在淘寶買 spi lcd屏幕時,要注意使用的晶片。第一次貪大,買了 3.5" 的 LCD,使用的晶片為 ILI9488,必須自己編譯 Kernel 的 module。要選較舊的 ILI9341 晶片的 LCD,在 Armbian 的 kernel 就有現成的 module 可用。
另外,觸控功能的 IC 是 XPT2046,是 TI 的 ADS7843 的相容 IC,因此是用 ADS7843 的驅動程式。
正文
香橙派接腳定義如下圖。
連接 Orange PI 與屏幕,參考。SPI 是一對多的協定,其中 SDI, SDO, SCK 是共用的,使用 CS 選擇要溝通的裝置。
--------------
OPi Zero3 wiring:
Pin 23 - PH6 <--> SPI1 SCK & T_CLK
Pin 21 - PH8 <--> SPI1 SDO<MISO> & T_DO
Pin 19 - PH7 <--> SPI1 SDI<MOSI> & T_DIN
Pin 11 - PC6 <--> DC
Pin 7 - PC9 <--> RESET
Pin 13 - PC5 <--> LED
Pin 22 - PC7 <--> SPI1 CS (PH9, originally)
Pin 18 - PC14 <--> T_CS
Pin 16 - PC15 <--> T_IRQ
Pin 1 - 3.3V
Pin 6 - GND
--------------经过查找,发现有 ili9341 的驱动模块,位於下面的目錄:
- /lib/modules/6.1.31-sun50iw9/kernel/drivers/staging/fbtft/fb_ili9341.ko
- /lib/modules/6.1.31-sun50iw9/kernel/drivers/input/touchscreen/ads7846.ko
于是通过设备树 overlay 添加 ili9341 的设备节点,如下:
在 /boot/dtb/allwinner/overlay/ 目錄下,建立檔案 ili9341_lcd.dts。檔名可自己任意決定。
/dts-v1/;
/plugin/;
/ {
compatible = "xunlong,orangepi-zero3", "allwinner,sun50i-h616";
fragment@0 {
target = <&spi1>;
__overlay__ {
status = "okay";
/*cs-gpios = <&pio 7 9 0>;*/ /* PH9*/
cs-gpios = <&pio 2 7 0>, <&pio 2 14 0>; /* PC7 PC14 */
ili9341: ili9341@0 {
compatible = "ilitek,ili9341";
reg = <0>; /* Chip Select 0 */
#spi-cs-high;
spi-max-frequency = <40000000>;
rotate = <90>;
bgr = <0>;
fps = <30>;
width = <240>;
height = <320>;
buswidth = <8>;
reset-gpios = <&pio 2 9 1>; /*RESET=PC9*/
dc-gpios = <&pio 2 6 0>; /*DC_RS=PC6*/
led-gpios = <&pio 2 5 0>; /*LED=PC5*/
debug = <4>;
};
ads7846: ads7846@0 {
compatible = "ti,ads7846";
reg = <1>; /* Chip Select 1 */
#spi-cs-high;
spi-max-frequency = <1000000>;
interrupt-parent = <&pio>;
interrupts = <2 15 2>; /* PC15 IRQ_TYPE_EDGE_FALLING */
pendown-gpio = <&pio 2 15 0>; /* PC15 */
/* ti,swap-xy = <0x1>; */
ti,x-min = /bits/ 16 <0>;
ti,y-min = /bits/ 16 <0>;
ti,x-max = /bits/ 16 <0x0FFF>;
ti,y-max = /bits/ 16 <0x0FFF>;
ti,pressure-min = /bits/ 16 <0>;
ti,pressure-max = /bits/ 16 <0xFFFF>;
ti,x-plate-ohms = /bits/ 16 <400>;
};
};
};
};
执行下面的指令,會產生 ili9341_lcd.dtbo,放在 /boot/overlay-user/ 的目錄下。
$ sudo orangepi-add-overlay ili9341_lcd.dts
Compiling the overlay
Copying the compiled overlay file to /boot/overlay-user/
Overlay ili9341_lcd was already added to /boot/orangepiEnv.txt, skipping
Reboot is required to apply the changes
如訊息所說,會在 /boot/orangepiEnv.txt 的檔案中加入該 overlay。
$ cat /boot/orangepiEnv.txt
verbosity=1
bootlogo=false
console=both
disp_mode=1920x1080p60
overlay_prefix=sun50i-h616
rootdev=UUID=535922e7-511d-46ea-82e6-573f913006af
rootfstype=ext4
user_overlays=opi_z3_ili9341_lcd
若要暫時停用該 overlay,可將其註解掉。例如,要使用 ADXL345 测量谐振時,也是用 SPI 來連接。
重新啟動,可以成功點亮 LCD。
疑难杂症
香橙派的 SPI1 CS 對應到 CPU 的 PH9,但使用 PH9,會報錯,dmesg 訊息如下:
-----------------
pin PH9 already requested by 5011000.spi;
-----------------
若是将 ili9341.dts 中的 cs-gpio 一行注释掉,則 fb0 可成功挂载,但是屏幕白屏
可以尝试更换cs的引脚,在此是把 cs 的引脚从 PH9 更换至 PC7 后可以正常点亮。另外,觸控的 CS 信號則是用 PC14。
具体操作:修改 ili9341_lcd.dts,
-----------------
/* cs-gpios = <&pio 7 9 0>; */
cs-gpios = <&pio 2 7 0>;
-----------------
"<&pio " 後面接的第一個數字,0 ~ 7 對應 Port A ~ Port H。最後一個數字,應是指定輸出 / 輸入。
只接 LCD 時,SPI1 SDO 不用接。開始時,照著 CSDN 的作法,成功點亮了 LCD。後來加上觸控的設定,沒注意到 SPI1 SDO 沒接,測了好久不成功,才發現一支腳沒接。
LCD 的設定
開機後,LCD 即會輸出顯示,但啟動 X 的應用程式,沒有顯示。
fb_tft 透過 fb_ili934 控制 LCD。在 X 的設定目錄下,建立 fbdev 的相關設定檔,如下。
$ cat /etc/X11/xorg.conf.d/98-fbdev.conf
Section "Device"
Identifier "myfb"
Driver "fbdev"
Option "fbdev" "/dev/fb0"
EndSection
重新啟動後,成功啟動 KlipperScreen。
觸控校正與設定
觸控是使用 XPT2046, 其為 ADS7846 的相容 IC。觸控要校正,才會和 LCD 的顯示一致。最先找到的作法,不能成功設定,但有了相關概令。參考 Arch Linux 的 Calibrating Touchscreen,只要設定 libinput 的 TransformationMatrix 參數即可。
設定的內容如下。
$ cat /etc/X11/xorg.conf.d/99-calibration.conf
Section "InputClass"
Identifier "calibration"
MatchProduct "ADS7846 Touchscreen"
Option "TransformationMatrix" "0 1.15 -0.1 1.1 0 -0.05 0 0 1"
EndSection
轉換公式計算如下。X / Y range 是指傳回的數值的範圍,這裡是 0xFFF,即 4096。
-----------------------------------------------------
[ 0 1.15 -0.1 ][X] [ 1.15*Y - 0.10*Y_range ]
[ 1.1 0 -0.05 ][Y] = [ 1.10*X - 0.05*X_range ]
[ 0 0 1 ][1] [ 1 ]
-----------------------------------------------------
網路上可以找到計算的公式,但後發現直接觀察修正最快。因為 KlipperScreen 不會顯示游標,我也不會啟動遠端的 X,只好另外裝 LightDM,啟動 lightdm,再慢慢調上面的參數。