Raspberry pi pico W と WAVESHARE-27057(waveshare 1.69インチタッチスクリーンディスプレイ) を LovyanGFX を使って繋いだ

前回の続きです。

https://qiita.com/uduki-oh-yeah/items/7f53ee1c5ad0c5869f18

## 今回の思惑

- 前回のデモコードベースで何かしらを作るのは現実的じゃないのでライブラリを使いたい
- ディスプレイの表示は確認したけど、タッチの制御がうまくいかないのでタッチパネルの制御をしたい
- 日本語表示もしたい

## 使う描画ライブラリ

M5Stack系で大変お世話になっている **LovyanGFX** を使いたいと思います。

ありがたいことにRP2040にも対応していらっしゃる。

https://github.com/lovyan03/LovyanGFX

### LovyanGFXの特長

- PlatformIO、Arduino、pico-sdkなどのプラットフォームに関わらず使えます
- GPIO指定でグラフィックライブラリなので、プラットフォーム依存が少ない（多分）
- 面倒な設定をしなくても日本語フォントが表示できます
- 基本的な描画が出来ます、線、円、四角…など
- 色の制御もできます
- M5Stack界隈で使われることが多いです
- 日本人作者（[らびやん様](https://x.com/lovyan03)）のライブラリなので日本語情報が多い **（重要）**

## 環境

- Windows11
- VSCode + Raspberry pi pico 拡張機能 (pico-sdk利用)
- Raspberry pi pico W
- LovyanGFX ライブラリ
- WAVESHARE-27057(waveshare 1.69インチタッチスクリーンディスプレイ)
    - 解像度：240 x 280 ピクセル
    - ディスプレイドライバ：ST7789V2
    - ディスプレイインターフェース：4線式SPI
    - タッチドライバ：CST816T
    - 仕様：[https://www.waveshare.com/1.69inch-touch-lcd-module.htm](https://www.waveshare.com/1.69inch-touch-lcd-module.htm)

繋ぎ方

以前と同じ。

https://qiita.com/uduki-oh-yeah/items/7f53ee1c5ad0c5869f18

上記ページより抜粋

| ピン名（上から順） | ピン概要 | PicoW GPIO |
| --- | --- | --- |
| VCC | 電源（3.3 / 5 V 入力） | 3.3V（36番：右の上から5番目）<br> |
| GND | グランド | GND（38番：右の上から3番目）<br> |
| LCD\_DIN | SPI MOSI ピン | GP11（15番：左の下から6番目）<br> |
| LCD\_CLK | SPI クロック ピン | GP10（14番：左の下から7番目）<br> |
| LCD\_CS | LCD チップセレクション、Low アクティブ | GP9（12番：左の下から9番目）<br> |
| LCD\_DC | LCD データ/コマンドセレクション（データ用 High、コマンド用 Low） | GP14（19番：左の下から2番目）<br> |
| LCD\_RST | LCD リセット、Low アクティブ | GP8（11番：左の下から10番目）<br> |
| LCD\_BL | LCD バックライト | GP15（20番：左の下から1番目）<br> |
| TP\_SDA | タッチパネル データピン | GP6（9番：左の上から9番目）<br> |
| TP\_SCL | タッチパネル クロックピン | GP7（10番：左の上から10番目）<br> |
| TP\_RST | タッチパネル リセット、Low アクティブ | GP16（21番：右の下から1番目）<br> |
| TP\_IRQ | タッチパネル 割り込みピン | GP17（22番：右の下から2番目）<br> |

## 記録

LovyanGFX をzip でダウンロードし、 VSCode で作ったプロジェクトのルートディレクトリに配置しました。

https://github.com/lovyan03/LovyanGFX

### フォルダ構成 

```:フォルダ構成
projectFolder
┗LovyanGFX
┗CMakeLists.txt
┗main.cpp
┗LGFX_config.hpp
```

<br>

### まずはサンプルコードを動かす

`LovyanGFX\examples_for_picosdk\i2c`  にサンプルコードが入っているので、こちらを `main.cpp`  に貼り付けて動かしてみます。



```cpp:main.cpp
#include <pico/stdlib.h>

#include <LovyanGFX.hpp>
#include "LGFX_config.hpp"

#include "LovyanGFX/examples/Sprite/PartyParrot/partyparrot.h" //サンプルコードからここだけ変更

static LGFX lcd;
static LGFX_Sprite sprite[10];

void setup(void);
void loop(void);

static uint32_t count = 0;
static float zoom = 0;

extern const unsigned char parrot00[];
extern const unsigned char parrot01[];
extern const unsigned char parrot02[];
extern const unsigned char parrot03[];
extern const unsigned char parrot04[];
extern const unsigned char parrot05[];
extern const unsigned char parrot06[];
extern const unsigned char parrot07[];
extern const unsigned char parrot08[];
extern const unsigned char parrot09[];

int main()
{
	stdio_init_all();

	setup();

	while (1) {
		loop();
	}

	return 0;
}

void setup(void)
{
  lcd.init();
  lcd.setRotation(0);
  if (lcd.width() < lcd.height()) { lcd.setRotation(lcd.getRotation() ^ 1); }

  zoom = (float)lcd.width() / 128;
  float ztmp = (float)lcd.height() / 96;
  if (zoom > ztmp) { zoom = ztmp; }

  lcd.setPivot(lcd.width() >> 1, lcd.height() >> 1);
  lcd.fillScreen(0xFFFFFFU);

  sprite[0].createFromBmp(parrot00);
  sprite[1].createFromBmp(parrot01);
  sprite[2].createFromBmp(parrot02);
  sprite[3].createFromBmp(parrot03);
  sprite[4].createFromBmp(parrot04);
  sprite[5].createFromBmp(parrot05);
  sprite[6].createFromBmp(parrot06);
  sprite[7].createFromBmp(parrot07);
  sprite[8].createFromBmp(parrot08);
  sprite[9].createFromBmp(parrot09);
}

void loop(void)
{
  if (++count == 10) count = 0;
  sprite[count].pushRotateZoom(&lcd, lcd.width() >> 1, lcd.height() >> 1, 0, zoom, zoom);
}
```

```cmake:CMakeLists.txt
# Generated Cmake Pico project file

cmake_minimum_required(VERSION 3.13)

set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

if (NOT (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/LovyanGFX)) # 追加
    message(FATAL_ERROR "Please copy \"LovyanGFX\" directory to \"${CMAKE_CURRENT_SOURCE_DIR}\".") # 追加
endif() # 追加

# Initialise pico_sdk from installed location
# (note this can come from environment, CMake cache etc)

# == DO NOT EDIT THE FOLLOWING LINES for the Raspberry Pi Pico VS Code Extension to work ==
if(WIN32)
    set(USERHOME $ENV{USERPROFILE})
else()
    set(USERHOME $ENV{HOME})
endif()
set(sdkVersion 2.1.0)
set(toolchainVersion 13_3_Rel1)
set(picotoolVersion 2.1.0)
set(picoVscode ${USERHOME}/.pico-sdk/cmake/pico-vscode.cmake)
if (EXISTS ${picoVscode})
    include(${picoVscode})
endif()
# ====================================================================================
set(PICO_BOARD pico_w CACHE STRING "Board type")

# Pull in Raspberry Pi Pico SDK (must be before project)
include(pico_sdk_import.cmake)

project(MyProject C CXX ASM)

# Initialise the Raspberry Pi Pico SDK
pico_sdk_init()

add_subdirectory( # 追加
    LovyanGFX # 追加
) # 追加


# Add executable. Default name is the project name, version 0.1

add_executable(MyProject MyProject.cpp )

pico_set_program_name(MyProject "MyProject")
pico_set_program_version(MyProject "0.1")

# Modify the below lines to enable/disable output over UART/USB
pico_enable_stdio_uart(MyProject 1)
pico_enable_stdio_usb(MyProject 1)

# Add the standard library to the build
target_link_libraries(MyProject
        pico_stdlib)

# Add the standard include files to the build
target_include_directories(MyProject PRIVATE
        ${CMAKE_CURRENT_LIST_DIR}
)

# Add any user requested libraries
target_link_libraries(MyProject 
        pico_cyw43_arch_none
        LovyanGFX # 追加
        )

pico_add_extra_outputs(MyProject)
```


さらに、サンプルで使用しているヘッダもコピーしてきます。

`LovyanGFX\examples_for_picosdk\i2c\LGFX_config.hpp`  を プロジェクトのルートディレクトリにコピー。

この環境で Raspberry pi pico 拡張機能からビルド実行すると、無事にビルドが通るところまで確認できました。

ただ、Raspberry pi pico W に書き込むと反応がありません。そりゃそうか。設定値が違うもんね。

### WAVESHARE-27057(waveshare 1.69インチタッチスクリーンディスプレイ) の設定を書く

<br>

以下の設定で、ディスプレイの表示はできます。

**タッチパネルの操作はできません。** (後述)




```cpp:LGFX\_config.hpp
#include <LovyanGFX.hpp>

#define TFT_MISO -1
#define TFT_MOSI 11
#define TFT_SCLK 10
#define TFT_CS   9
#define TFT_DC   14
#define TFT_RST  8
#define TFT_BL   15
#define TOUCH_SDA 6
#define TOUCH_SCL 7
#define TOUCH_RST 16
#define TOUCH_IRQ 17

class LGFX : public lgfx::LGFX_Device
{
  lgfx::Panel_ST7789 _panel_instance;
  lgfx::Bus_SPI _bus_instance; // SPIバスのインスタンス
  lgfx::Touch_CST816S _touch_instance;//TODO: CS816Tがない…
  lgfx::Light_PWM     _light_instance;

public:
  LGFX(void)
  {
    {                                    // バス制御の設定を行います。
      auto cfg = _bus_instance.config(); // バス設定用の構造体を取得します。

      cfg.spi_host = 1;          // 使用するSPIを選択-
      cfg.spi_mode = 0;          // SPI通信モードを設定 (0 ~ 3)
      cfg.freq_write = 10000000; // 送信時のSPIクロック (最大80MHz, 80MHzを整数で割った値に丸められます)
      cfg.freq_read = 10000000;  // 受信時のSPIクロック

      cfg.pin_sclk = TFT_SCLK; // SPIのSCLKピン番号を設定
      cfg.pin_mosi = TFT_MOSI; // SPIのMOSIピン番号を設定
      cfg.pin_miso = TFT_MISO; // SPIのMISOピン番号を設定 (-1 = disable)
      cfg.pin_dc = TFT_DC;     // SPIのD/Cピン番号を設定  (-1 = disable)

      _bus_instance.config(cfg);              // 設定値をバスに反映します。
      _panel_instance.setBus(&_bus_instance); // バスをパネルにセットします。
    }

    {                                      // 表示パネル制御の設定を行います。
      auto cfg = _panel_instance.config(); // 表示パネル設定用の構造体を取得します。

      cfg.pin_cs = TFT_CS;   // CSが接続されているピン番号   (-1 = disable)
      cfg.pin_rst = TFT_RST; // RSTが接続されているピン番号  (-1 = disable)
      cfg.pin_busy = -1;     // BUSYが接続されているピン番号 (-1 = disable)

      cfg.panel_width = 240;  // 実際に表示可能な幅
      cfg.panel_height = 280; // 実際に表示可能な高さ

      cfg.offset_x = 0;       // パネルのX方向オフセット量
      cfg.offset_y = 20; // パネルのY方向オフセット量

      cfg.rgb_order = true;// パネルの赤と青が入れ替わってしまうのでtrueに設定
      cfg.readable = true;
      cfg.invert = true; // パネルの明暗が反転してしまう場合 trueに設定

      _panel_instance.config(cfg);
    }

    {
      auto cfg = _light_instance.config();
      cfg.pin_bl      = TFT_BL; // バックライトの制御ピン番号
      cfg.pwm_channel = 1;
      _light_instance.config(cfg);
      _panel_instance.setLight(&_light_instance);
    }

    {
      auto cfg = _touch_instance.config();
      cfg.i2c_port = 1;
      //cfg.i2c_addr = 0x15;
      cfg.x_min = 0;
      cfg.x_max = 240;
      cfg.y_min = 0;
      cfg.y_max = 280;
      cfg.pin_sda = TOUCH_SDA;
      cfg.bus_shared = true;
      cfg.pin_scl = TOUCH_SCL;
      cfg.pin_rst = TOUCH_RST;
      cfg.pin_int = TOUCH_IRQ;
      cfg.freq = 400000;
      _touch_instance.config(cfg);
      _panel_instance.setTouch(&_touch_instance);
    }

    setPanel(&_panel_instance); // 使用するパネルをセットします。
  }
};
```

#### 変更点のメモ

- `cfg.spi_host = 1;`  は大事。これがないと表示されない
- `cfg.freq_write = 10000000;`  を `80000000` にしても動く。デモの鳥がめちゃくちゃ早く動くようになる
- `cfg.freq_read = 20000000;`  はあってもなくても動く。詳しく調べてない。
- `_panel_instance.setLight(&_light_instance);`  この一文がないと画面が真っ暗（バックライトなし）で、うまく表示できていたのに見過ごしていた。 **バックライト大事。**
- タッチパネルの設定を頑張ったけど動きませんでした
    - **そもそもLovyanGFX は RP2040 向けのタッチスクリーン対応が非対応…**
    - いろいろ試したけど、サポートされてないんだから動かなくても **泣かない！**

#### コンフィグ作成で参考にさせていただいたページ

https://qiita.com/Saqoosha/items/80a1f52e640c95fb1106

https://wondercode.hatenablog.jp/entry/2023/04/23/171135  

https://qiita.com/masaya3/items/f469ca80e8c1e133d405 

https://aloseed.com/it/lovyangfx-setting-example/#toc7

### 日本語表示したい

無事に日本語表示はできました。
必要なコードだけ抜粋。簡単…ありがたい…

```cpp
lcd.setFont(&fonts::efontJA_10);
lcd.drawString("Hello, world!こんにちは★", 10, 100);
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3883973/466c5553-6934-4325-9620-1f6d1ab7e67f.png)



## 成果

- デモコードベースで何かしらを作るのは現実的じゃないのでライブラリを使いたい
    - **できました**
- ディスプレイの表示は確認したけど、タッチの制御がうまくいかないのでタッチパネルの制御をしたい
    - **できませんでした。**
    - よく見たらライブラリの説明のGithubに TouchScreens 欄の「RP2040」がsupported になってなかった…
    - Touch_CST816S の設定を使ってるけど、 WAVESHARE-27057 は CST816T なので、設定が異なる可能性がある
    - 次はもうちょっとほかのライブラリを使ってみます
    - でもあとちょっとな気がするんだよな…何か足りてないのかもしれない…
- 日本語表示もしたい
    - **できました。**

## 結論

画面の表示制御だけあれば、 RP2040 + WAVESHARE-27057 + pico-sdk + LovyanGFX でいけそう。