lovyan03 / LovyanGFX

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

drawFastVLine, drawFastHLineの実行タイミングを変えると表示が潰れる #85

Closed gitnabeshin closed 3 years ago

gitnabeshin commented 3 years ago

素晴らしいライブラリを使わせて頂き、ありがとうございます。

M5Paperで以下のコードの#define ERROR_DISPLAYを有効すると 2行表示していた文字と図が1行目の領域に潰れて表示されます。

この問題は、これらを最後にまとめて実行する事で回避できます。 改善できそうでしょうか?

#include <M5EPD.h>

#define LGFX_M5PAPER
#include <LovyanGFX.hpp>

static LGFX gfx;

// --------------------------------
//  これを有効にすると不具合が再現します
// --------------------------------
//#define ERROR_DISPLAY

void setup() {

    int x = 10;
    int y = 50;
    int y_offset = 120;

    M5.begin(true, true, true, true);
    gfx.init();
    gfx.setFont(&fonts::lgfxJapanGothic_32);

#ifdef ERROR_DISPLAY
    //ここだと表示が潰れる
    gfx.drawFastVLine(70, 0, gfx.height());
#endif

    gfx.setCursor(x, y);
    gfx.println("0.1");
    gfx.fillArc( 270, y + 8, 54, 32, 270 + 20, 270 - 20, TFT_BLACK);

#ifdef ERROR_DISPLAY
    //ここだと表示が潰れる
    gfx.drawFastHLine( 0, 124, gfx.width() );
#endif

    y = y + y_offset;
    gfx.setCursor(x, y);
    gfx.println("0.2");
    gfx.fillArc( 270, y + 22, 42, 28, 90 + 20, 90 - 20, TFT_BLACK);

#ifndef ERROR_DISPLAY
    //ここだと正常に表示できる
    gfx.drawFastVLine(70, 0, gfx.height());
    gfx.drawFastHLine( 0, 124, gfx.width() );
#endif

}

void loop() {}
lovyan03 commented 3 years ago

@gitnabeshin わかりやすいサンプルコードありがとうございます!

まず最初に、解決する方法をお伝えします。

方法1.一連の描画処理を startWrite() / endWrite() で囲む。 https://github.com/lovyan03/LovyanGFX/blob/0.3.4/examples/Advanced/EPD/EPD.ino#L55-L66 一連の描画をまとめて画面に反映できるので、処理速度が向上し、描画順序に依存した問題を防止できます

方法2.描画が崩れるポイントの前で waitDisplay() を配置する。 https://github.com/lovyan03/LovyanGFX/blob/0.3.4/examples/Advanced/EPD/EPD.ino#L184-L196 今回の例では drawFastHLine の直前になります

次に、サンプルコードで何が起こっていたのかをお伝えします。

まずM5Paperに搭載されているIT8951は、通常の表示更新は1回450ミリ秒かかります。 例えば10回の表示更新を行う場合、毎回表示更新の完了を待機していては合計4.5秒かかってしまいます。 しかしIT8951は前回の表示更新の完了を待機せずとも、新たな表示更新が可能です。これにより処理時間を短縮できます。

ただし、表示更新の範囲が重複する指示した場合、IT8951が誤作動して表示が乱れる事があります。 今回の例では、drawFastVLine と drawFastHLine の線が交差していることが該当します。

これを防止するため、LovyanGFXはひとつ前の範囲を記憶しており、重複があれば待機するようになっています。 今回の例であれば、drawFastVLine の直後に drawFastHLine を置いたならば、重複チェックによって待機が行われるので、描画が崩れることはありません。

しかし、今回の例では間にprintln・fillArcがあるため、drawFastVLine と drawFastHLine の重複チェックが行われず、重複した描画更新が実行されてしまい、 IT8951が正しく動作しなくなっていました。

LovyanGFX側で450ミリ秒以内の更新範囲をすべて保持して重複チェックを強化すべきかどうか、というところですが…、とりあえず現状は利用者側での処理の組み方で回避して頂く感じになっています。

よろしくお願いいたします。

gitnabeshin commented 3 years ago

なるほど! すごくわかりやすい解説ありがとうございます。

性能とチェックをどのあたりで両立するか、言った感じのお話ですね。 LovyanGFXは高速性能が得られるのがメリットなので、説明して頂いたあたりの仕組みを分かった上で使うのが良いですね。

サンプル、そんなに読み込んでなかったので、もうちょっと読んでみます!

ありがとうございました。