FPGAを使ったRISC-V SoC(第2回)タッチスクリーンを動かす

FPGAを使ったRISC-V SoC(第2回)タッチスクリーンを動かす

はじめに

今回は、TFTディスプレイとタッチスクリーンを動かすにあたりArty A7のArduinoシールド互換コネクタにそのまま接続できるAdafruit 2.8 TFT Touch Shieldを使うことにしました。

全体の流れ

  • FPAG(Litex SoC) H/W(Pin)構成を、Adafruit 2.8 TFT Touch Shieldに合わせて変更する
  • Linux KernelにFrame Buffer、TFTディスプレイとタッチスクリーンのドライバを追加する
  • DTS(Device Tree Source)にTFTディスプレイ(SPI)とタッチスクリーン(I2C)を追加する
  • デモに必要なパッケージを追加する

使用機材

  • 第1回で使用した機材
  • Adafruit 2.8 TFT Touch Shield
      スペック
        画面                                     : 2.8インチ、240 x 320、18ビットカラー
        TFTコントローラ                   : ILI9341 SPI  I/F
        タッチスクリーンコントローラ : FT6206 I2C接続

Litex SoCのPin構成

FPAG(Litex SoC) H/W(Pin)構成を、Adafruit 2.8 TFT Touch Shieldに合わせて変更

TFTディスプレイ

TFTコントローラ(ILI9341)のDC/RS(LCD register / data selection)をGPIOで制御できるように以下のようにFPGAの構成を変更。
litex-boards/litex_boards/platforms/digilent_arty.py

@@ -22,6 +22,7 @@
     ("user_led", 1, Pins("J5"), IOStandard("LVCMOS33")),
     ("user_led", 2, Pins("T9"), IOStandard("LVCMOS33")),
     ("user_led", 3, Pins("T10"), IOStandard("LVCMOS33")),
+    ("user_led", 4, Pins("M16"), IOStandard("LVCMOS33")),

     ("rgb_led", 0,
         Subsignal("r", Pins("G6")),

タッチスクリーン

タッチスクリーンコントローラ (FT6206)のINT(Interrupt output)をGPIOで制御できるように以下のようにFPGAの構成を変更。
litex-boards/litex_boards/platforms/digilent_arty.py

@@ -52,7 +53,7 @@
     ("user_sw", 0, Pins("A8"), IOStandard("LVCMOS33")),
     ("user_sw", 1, Pins("C11"), IOStandard("LVCMOS33")),
     ("user_sw", 2, Pins("C10"), IOStandard("LVCMOS33")),
-    ("user_sw", 3, Pins("A10"), IOStandard("LVCMOS33")),
+    ("user_sw", 3, Pins("T16"), IOStandard("LVCMOS33")),

     # Buttons
     ("user_btn", 0, Pins("D9"), IOStandard("LVCMOS33")), 

Adafruit 2.8 TFT Touch Shield のPIN配置は以下の様になる。

Linux Kernelの変更

TFTディスプレイ

TFTコントローラ(ILI9341)をLinuxフレームバッファとして機能されるため、LinuxカーネルコンフィグレーションとDTS(Device Tree Source)に以下の変更を加える。
Linuxカーネルコンフィグレーションの以下を有効とする

$ cd ˜/buildroot/
$ make linux-menuconfig
  -> Device Drivers
    -> Graphics support
      -> Frame buffer Devices
        -> Support for frame buffer devices
      -> Display Panels
         -> Ilitek ILI9341 240x320 QVGA panels
    -> Staging drivers
      -> Support for small TFT LCD display modules
        -> FB driver for the ILI9341 LCD Controller 

タッチスクリーン

以下のサイトからダウンロードしたドライバをLinuxカーネルに組み込み変更を行う。
t6236.cのダウンロード

$ cd ~/buildroot/output/build/linux-ae80e67c6b48bbedcd13db753237a25b3dec8301/drivers/input/touchscreen
$ wget https://raw.githubusercontent.com/ipts-linux-org/ipts-linux/master/drivers/input/touchscreen/ft6236.c 

drivers/input/ft6236.cの変更

@@ -22,6 +22,9 @@
#include <linux/module.h>
#include <linux/property.h>

+#include <linux/gpio.h>
+#include <linux/kernel.h>
+
#define FT6236_MAX_TOUCH_POINTS                2

#define FT6236_REG_TH_GROUP                    0x80
@@ -278,10 +281,24 @@
                                    INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED);
        if (error)
                  return error;
-
+#if 0
        error = devm_request_threaded_irq(dev, client->irq, NULL,
                                          ft6236_interrupt, IRQF_ONESHOT,
                                          client->name, ft6236);
+#else
+{
+       int ft5x06_gpio_irq = 505;
+       error = gpio_request(ft5x06_gpio_irq, "edt_ft6236 irq");
+       printk ( " gpio_request=%d (%d:%d)\n", error, ft5x06_gpio_irq, gpio_to_irq(ft5x06_gpio_irq) );
+       if (!error) {
+               gpio_direction_input(ft5x06_gpio_irq);
+
+               error = request_irq(gpio_to_irq(ft5x06_gpio_irq),
+                                       ft6236_interrupt, IRQF_ONESHOT,
+                                               client->name, ft6236);
+       }
+}
+#endif
        if (error) {
                dev_err(dev, "request irq %d failed: %d¥n", client->irq, error);
                return error; 

drivers/input/Makefileの変更

@@ -44,6 +44,7 @@
obj-$(CONFIG_TOUCHSCREEN_EGALAX) += egalax_ts.o
obj-$(CONFIG_TOUCHSCREEN_EGALAX_SERIAL) += egalax_ts_serial.o
obj-$(CONFIG_TOUCHSCREEN_EXC3000) += exc3000.o
+obj-$(CONFIG_TOUCHSCREEN_FT6236) += ft6236.o
obj-$(CONFIG_TOUCHSCREEN_FUJITSU) += fujitsu_ts.o
obj-$(CONFIG_TOUCHSCREEN_GOODIX) += goodix_ts.o+
obj-$(CONFIG_TOUCHSCREEN_HIDEEP) += hideep.o 

drivers/input/Kconfigの変更

@@ -372,6 +372,18 @@
          To compile this driver as a module, choose M here: the
          module will be called exc3000.

+config TOUCHSCREEN_FT6236
+       tristate "FT6236 I2C touchscreen"
+       depends on I2C
+       depends on GPIOLIB || COMPILE_TEST
+       help
+         Say Y here to enable support for the I2C connected FT6x06 and
+         FT6x36 family of capacitive touchscreen drivers.
+
+         If unsure, say N.
+
+         To compile this driver as a module
+
config TOUCHSCREEN_FUJITSU
        tristate "Fujitsu serial touchscreen"
        select SERIO 

Linuxカーネルコンフィグレーションの変更

$ make linux-menuconfig
  -> Device Drivers
    -> Input device support
      -> Generic input layer (needed for keyboard, mouse, ...)
        -> Event interface
        -> Touchscreens
          -> FT6236 I2C touchscreen

DTS(Device Tree Source)の変更

TFTディスプレイ

TFTディスプレイをLinuxフレームバッファとして機能させるため、DTSに以下の変更を行う
˜/litex-vexriscv/linux-on-litex-vexriscv/build/arty_a7/arty_a7_mmc.dts

@@ -237,10 +237,12 @@
                 #address-cells = <1>;
                 #size-cells = <0>;

-                spidev0: spidev@0 {
-                    compatible = "linux,spidev";
-                    reg = <0>;
-                    spi-max-frequency = <1000000>;
+                display@0 {
+                    compatible = "adafruit,yx240qv29", "ilitek,ili9341";
+                    reg = <0x00>;
+                    spi-max-frequency = <3000000>;
+                    rotation = <90>;
+                    dc-gpios = <&leds 4 0>;
                     status = "okay";
                 };
             };
@@ -330,7 +351,7 @@
};

&leds {
-        litex,ngpio = <4>;
+        litex,ngpio = <5>;
         status = "okay";
};

タッチスクリーン

FT6206をタッチスクリーンとして機能させるため、DTSに以下の変更を行う。
˜/litex-vexriscv/linux-on-litex-vexriscv/build/arty_a7/arty_a7_mmc.dts

@@ -251,6 +253,14 @@
                 #address-cells = <1>;
                 #size-cells = <0>;
                 status = "okay";
+                touchscreen@38 {
+                    compatible = "focaltech,ft6236";
+                    interrupt-parent = <&switches>;
+                    interrupts = <0 2>; /* TOUCH_INT# */
+                    reg = <0x38>;
+                    touchscreen-size-x = <240>;
+                    touchscreen-size-y = <320>;
+                };
             };

             hwmon0: xadc@f000b800 {
@@ -336,7 +357,7 @@
&switches {
-        litex,ngpio = <4>;
+        litex,ngpio = <5>;
        status = "okay";
}; 

タッチイベント不具合対応

input_event構造体の問題で、タッチイベントをアプリでうまく取得することが出来なかった為、input.hに以下の修正を加えました。
「~/buildroot/output/build/linux-ae80e67c6b48bbedcd13db753237a25b3dec8301/include/uapi/linux/input.h」

#define input_event_usec time.tv_usec
#else
-       __kernel_ulong_t __sec;
+       __u64 __sec;
#if defined(__sparc__) && defined(__arch64__)
        unsigned int __usec;
        unsigned int __pad;
#else
-       __kernel_ulong_t  __usec;
+       __u64 __usec;
#endif 

QTアプリ(お絵描きソフト)

QTアプリを動かすために事前準備として、LinuxカーネルコンフィグレーションでUnix domain Socketを有効する。
Unix domain Socketを有効

$ cd buildroot/
$ make linux-menuconfig
  -> Networking support
    -> Networking options
      -> Unix domain sockets 

QTアプリを動かす為には、Buildrootのコンフィグレーションでライブラリの追加とQTの追加が必要です。
タッチスクリーン系のライブラリとフォントを有効

$ cd buildroot/
$ make menuconfig
  -> Toolchain
    -> Enable C++ support
  -> Target packages
    -> Fonts, cursors, icons, sounds and themes
      -> Liberation (Free fonts)
    -> Libraries
      -> Hardware handling
        -> tslib
      -> Other
        -> libevdev 

QTアプリの有効化

$ make menuconfig
  -> Target packages
    -> Graphic libraries and applications (graphic/text)
      -> Qt5
        -> qt5base
          -> Compile and install examples (with code)
          -> concurrent module
          -> gui module
            -> widgets module
            -> fontconfig support
            -> harfbuzz support
            -> GIF support
            -> JPEG support
            -> PNG support
          -> DBus module
          -> Enable ICU support
          -> Enable Tslib support 

変更後ビルドを実行し、SDカードに書き込む。
ターゲット起動後、タッチスクリーンのキャリブレーションを実行する。

# ts_calibrate 

※実行後タッチスクリーンにキャリブレーション用の画面が表示されるので指示に従い実行。

環境変数を設定し、QTのお絵描きアプリ「scribble」を実行する。

# export QT_QPA_FB_NO_LIBINPUT='1'
# export QT_QPA_FB_TSLIB='1'
# export QT_QPA_PLATFORM='linuxfb'
# /usr/lib/qt/examples/widgets/widgets/scribble/scribble 

おわり

タッチスクリーンと描画、両方の制御ができるので、今回はQTをチョイスしました。
QTには他にもサンプルアプリがあるので動かしてみてください。
課題として残ったことを以下に記載します。

  • 画面タッチ後の反応と描画が遅い
  • linux kernelのinput_event構造体を変更した