lovyan03 / LovyanGFX

SPI LCD graphics library for ESP32 (ESP-IDF/ArduinoESP32) / ESP8266 (ArduinoESP8266) / SAMD51(Seeed ArduinoSAMD51)
Other
1.08k stars 191 forks source link

RaspberryPi Pico (RP2040) + ILI9341 not working properly #437

Closed suzukiplan closed 10 months ago

suzukiplan commented 10 months ago

Carefully written Issues are more likely to be given priority. 丁寧に記述された報告は優先して対応される可能性が高くなります。

Environment ( 実行環境 )

Problem Description ( 問題の内容 )

単純な Hello, World を表示するプログラムを動かしたところ LGFX_Device::startWrite を実行後にハングアップして正常に動作しません。

Expected Behavior ( 期待される動作 )

image

※上記は M5StampS3 で同じプログラムを実行した時の結果です

Actual Behavior ( 実際の動作 )

image

LGFX_Device::startWrite でハングアップしているようです。

Steps to reproduce ( 再現のための前提条件 )

  1. pio init
  2. platformio.ini を編集(後述)
  3. src/app.cpp を編集(後述)
  4. pio run -t upload

Code to reproduce this issue ( 再現させるためのコード )

PIN assign

RaspberryPi Pico ILI9341 LCD
3.3V VCC
3.3V GPIO27 LED
GND GND
GPIO17 (SPI0 CS) CS
GPIO22 RESET
GPIO28 DC
GPIO19 (SPI0 TX) SDI (MOSI)
GPIO18 (SPI0 SCK) SCK
GPIO20 T_CS
GPIO16 (SPI0 MISO) T_DO (MISO)
GPIO18 (SPI0 SCK) T_CLK
GPIO19 (SPI0 MOSI) T_DIN (MOSI)

platformio.ini

[env:pico]
platform = raspberrypi
board = pico
framework = arduino
lib_deps = lovyan03/LovyanGFX

src/app.cpp

#include <LovyanGFX.hpp>

class ILI9341 : public lgfx::LGFX_Device
{
  private:
    const int pinLed = 27;
    const int pinCs = 17;
    const int pinReset = 22;
    const int pinDc = 28;
    const int pinMosi = 19;
    const int pinSck = 18;
    const int pinMiso = -1;
    const int pinBusy = -1;

    lgfx::Panel_ILI9341 panel;
    lgfx::Bus_SPI bus;

    void initBusConfig()
    {
        auto cfg = this->bus.config();
        cfg.spi_host = 0;
        cfg.spi_mode = 0;
        cfg.freq_write = 40000000;
        cfg.freq_read = 16000000;
        cfg.pin_sclk = this->pinSck;
        cfg.pin_mosi = this->pinMosi;
        cfg.pin_miso = this->pinMiso;
        cfg.pin_dc = this->pinDc;
        this->bus.config(cfg);
    }

    void initPanelConfig()
    {
        auto cfg = this->panel.config();
        cfg.pin_cs = this->pinCs;
        cfg.pin_rst = this->pinReset;
        cfg.pin_busy = -1;
        cfg.panel_width = 240;
        cfg.panel_height = 320;
        cfg.offset_x = 0;
        cfg.offset_y = 0;
        cfg.offset_rotation = 2;
        cfg.dummy_read_pixel = 8;
        cfg.dummy_read_bits = 1;
        cfg.readable = false;
        cfg.invert = false;
        cfg.rgb_order = false;
        cfg.dlen_16bit = false;
        cfg.bus_shared = true;
        this->panel.config(cfg);
    }

  public:
    void init(void)
    {
        this->initBusConfig();
        this->initPanelConfig();
        this->panel.setBus(&this->bus);
        setPanel(&this->panel);
        pinMode(this->pinLed, OUTPUT);
    }

    void led(bool on)
    {
        digitalWrite(this->pinLed, on ? HIGH : LOW);
    }
};

static ILI9341 gfx;

void setup()
{
    // 初期化中は本体LEDを点灯
    pinMode(25, OUTPUT);
    digitalWrite(25, HIGH);

    // ディスプレイを初期化
    gfx.init();
    gfx.led(true);
    gfx.startWrite();
    gfx.setRotation(2);
    gfx.writeFillRect(0, 0, gfx.width(), gfx.height(), 0x003F);
    gfx.setTextSize(2);
    gfx.setTextColor(0xFFFF, 0x0000);
    gfx.setCursor(0, 0);
    gfx.println("Hello, World!");
    gfx.println("Using LovyanGFX.");
    gfx.endWrite();
}

void loop()
{
    delay(1000);
    digitalWrite(25, LOW);
    delay(1000);
    digitalWrite(25, HIGH);
}

Additional Info ( 補足情報 )

再現コードと同じ PIN assign で Adafruit ILI9341 で動かしてみたところ問題なく動作したので、本件はハードウェアの問題ではないと考えられます。

platformio.ini

[env:pico]
platform = raspberrypi
board = pico
framework = arduino
lib_deps = adafruit/Adafruit GFX Library, adafruit/Adafruit ILI9341

src/app.cpp

#include <Adafruit_ILI9341.h>

#define PIN_CS 17
#define PIN_DC 28
#define PIN_RST 22
#define PIN_LED 27
#define PIN_MOSI 19
#define PIN_SCLK 18

static Adafruit_ILI9341 lcd(PIN_CS, PIN_DC, PIN_MOSI, PIN_SCLK, PIN_RST);

void setup()
{
    pinMode(PIN_LED, OUTPUT);
    digitalWrite(PIN_LED, HIGH);
    lcd.begin();
    lcd.startWrite();
    lcd.setRotation(2);
    lcd.writeFillRect(0, 0, lcd.width(), lcd.height(), 0x0007);
    const char* hello = "Hello, World!";
    int16_t x, y;
    uint16_t w, h;
    lcd.setTextSize(3);
    lcd.setTextColor(0xFFFF, 0x0000);
    lcd.getTextBounds(hello, 0, 0, &x, &y, &w, &h);
    lcd.setCursor(lcd.width() / 2 - w / 2, lcd.height() / 2 - h / 2);
    lcd.print(hello);
    lcd.endWrite();
}

void loop() { }

Actual Behavior ( 実際の動作 )

image

suzukiplan commented 10 months ago

追加情報です。

コチラの定義に則り、platformio.ini の内容を次のように変更してみましたが、結果は同じでした。

[env:pico]
platform = https://github.com/maxgerhardt/platform-raspberrypi.git
board = pico
board_build.core = earlephilhower
framework = arduino
lib_deps = lovyan03/LovyanGFX

また、念のため RP2040 を最初にサポートしたバージョン(&macOSでビルド可能なバージョン)1.1.6 でも試してみましたが、結果は変わりませんでした。

[env:pico]
platform = https://github.com/maxgerhardt/platform-raspberrypi.git
board = pico
board_build.core = earlephilhower
framework = arduino
lib_deps = lovyan03/LovyanGFX@1.1.6
suzukiplan commented 10 months ago

すみません、自己解決しました 🙇

RP2040版 lgfx::LGFX_Device の内部実装で init メソッドを使用しており、それを自前の派生クラス ILI9341 で意図せずオーバーライドしていたことが原因でした。

そこで、ソースコードの

    init(void)

の箇所を、

    ILI9341(void)

と、コンストラクタに書き換えてみたところ、正常に動作することを確認しました。

(正常に動作する修正後ソース)

#include <LovyanGFX.hpp>

class ILI9341 : public lgfx::LGFX_Device
{
  private:
    const int pinLed = 27;
    const int pinCs = 17;
    const int pinReset = 22;
    const int pinDc = 28;
    const int pinMosi = 19;
    const int pinSck = 18;
    const int pinMiso = -1;
    const int pinBusy = -1;

    lgfx::Panel_ILI9341 panel;
    lgfx::Bus_SPI bus;

    void initBusConfig()
    {
        auto cfg = this->bus.config();
        cfg.spi_host = 0;
        cfg.spi_mode = 0;
        cfg.freq_write = 40000000;
        cfg.freq_read = 16000000;
        cfg.pin_sclk = this->pinSck;
        cfg.pin_mosi = this->pinMosi;
        cfg.pin_miso = this->pinMiso;
        cfg.pin_dc = this->pinDc;
        this->bus.config(cfg);
    }

    void initPanelConfig()
    {
        auto cfg = this->panel.config();
        cfg.pin_cs = this->pinCs;
        cfg.pin_rst = this->pinReset;
        cfg.pin_busy = -1;
        cfg.panel_width = 240;
        cfg.panel_height = 320;
        cfg.offset_x = 0;
        cfg.offset_y = 0;
        cfg.offset_rotation = 2;
        cfg.dummy_read_pixel = 8;
        cfg.dummy_read_bits = 1;
        cfg.readable = false;
        cfg.invert = false;
        cfg.rgb_order = false;
        cfg.dlen_16bit = false;
        cfg.bus_shared = true;
        this->panel.config(cfg);
    }

  public:
    ILI9341(void)
    {
        this->initBusConfig();
        this->initPanelConfig();
        this->panel.setBus(&this->bus);
        setPanel(&this->panel);
        pinMode(this->pinLed, OUTPUT);
    }

    void led(bool on)
    {
        digitalWrite(this->pinLed, on ? HIGH : LOW);
    }
};

static ILI9341 gfx;

void setup()
{
    // 初期化中は本体LEDを点灯
    pinMode(25, OUTPUT);
    digitalWrite(25, HIGH);

    // ディスプレイを初期化
    gfx.init();
    gfx.led(true);
    gfx.startWrite();
    gfx.setRotation(2);
    gfx.writeFillRect(0, 0, gfx.width(), gfx.height(), 0x003F);
    gfx.setTextSize(2);
    gfx.setTextColor(0xFFFF, 0x0000);
    gfx.setCursor(0, 0);
    gfx.println("Hello, World!");
    gfx.println("Using LovyanGFX.");
    gfx.endWrite();
}

void loop()
{
    delay(1000);
    digitalWrite(25, LOW);
    delay(1000);
    digitalWrite(25, HIGH);
}