lovyan03 / LovyanGFX

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

readRect() function not working properly #506

Closed markradev closed 3 months ago

markradev commented 3 months ago

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

Environment ( 実行環境 )

Problem Description ( 問題の内容 )

readRect() function not working properly under LovyanGFX. However, if you use the tft_eSPI library it works. I cut out a piece of the bottom left 8 and pasted it back into the top right. The colors are not correct. I've already tried a lot of different SPI settings and speeds for read and write and different color settings. The read test also shows some errors, but it is successful under tft_eSPI.

Expected Behavior ( 期待される動作 )

Correct representation of the colors/pixels top right (cut/taken from bottom left) with tft_eSPI tft_eSPI

Pixel value written = 1 Pixel value read = 1 PASS Pixel value written = 2 Pixel value read = 2 PASS Pixel value written = 4 Pixel value read = 4 PASS Pixel value written = 8 Pixel value read = 8 PASS Pixel value written = 10 Pixel value read = 10 PASS Pixel value written = 20 Pixel value read = 20 PASS Pixel value written = 40 Pixel value read = 40 PASS Pixel value written = 400 Pixel value read = 400 PASS Pixel value written = 100 Pixel value read = 100 PASS Pixel value written = 200 Pixel value read = 200 PASS Pixel value written = 400 Pixel value read = 400 PASS Pixel value written = 800 Pixel value read = 800 PASS Pixel value written = 1000 Pixel value read = 1000 PASS Pixel value written = 2000 Pixel value read = 2000 PASS Pixel value written = 4000 Pixel value read = 4000 PASS Pixel value written = 8000 Pixel value read = 8000 PASS

Actual Behavior ( 実際の動作 )

Wrong colors top right (cut/taken from bottom left) and ERROR output on read example with LovyanGFX LovyanGFX

Pixel value written = 1 Pixel value read = 0 ERROR ^^^^ Pixel value written = 2 Pixel value read = 0 ERROR ^^^^ Pixel value written = 4 Pixel value read = 0 ERROR ^^^^ Pixel value written = 8 Pixel value read = 40 ERROR ^^^^ Pixel value written = 10 Pixel value read = 80 ERROR ^^^^ Pixel value written = 20 Pixel value read = 100 ERROR ^^^^ Pixel value written = 40 Pixel value read = 200 ERROR ^^^^ Pixel value written = 80 Pixel value read = 400 ERROR ^^^^ Pixel value written = 100 Pixel value read = 0 ERROR ^^^^ Pixel value written = 200 Pixel value read = 0 ERROR ^^^^ Pixel value written = 400 Pixel value read = 0 ERROR ^^^^ Pixel value written = 800 Pixel value read = 800 PASS Pixel value written = 1000 Pixel value read = 1000 PASS Pixel value written = 2000 Pixel value read = 2000 PASS Pixel value written = 4000 Pixel value read = 4000 PASS Pixel value written = 8000 Pixel value read = 8000 PASS

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

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

#include <LovyanGFX.hpp>
//#include <LGFX_TFT_eSPI.hpp>
//#include <LGFX_AUTODETECT.hpp> 
#include "DSEG7_custom.h"
//#include "textFont.h"

class LGFX : public lgfx::LGFX_Device
{

    lgfx::Panel_ST7789    _panel_instance;
    lgfx::Bus_SPI           _bus_instance;   
    lgfx::Light_PWM         _light_instance;

  public:

    LGFX(void)
    {
        { 
            auto cfg = _bus_instance.config();    

            // SPI
            cfg.spi_host = SPI2_HOST;     // VSPI_HOST 
            cfg.spi_mode = 0;             // SPI (0 - 3)
            cfg.freq_write = 80000000;    
            cfg.freq_read  = 7000000;    
            cfg.spi_3wire  = true;        
            cfg.use_lock   = true;        
            cfg.dma_channel = SPI_DMA_CH_AUTO; // DMA(0=DMA / 1=1ch / 2=ch / SPI_DMA_CH_AUTO)

            cfg.pin_sclk = 12;            // SPI SCLK
            cfg.pin_mosi = 11;            // SPI MOSI
            cfg.pin_miso = -1;            // SPI MISO (-1 = disable)
            cfg.pin_dc   =  8;            // SPI D/C

            _bus_instance.config(cfg);    
            _panel_instance.setBus(&_bus_instance);      
        }

        { 
            auto cfg = _panel_instance.config();    

            cfg.pin_cs           =    10;  // CS
            cfg.pin_rst          =     9;  // RST
            cfg.pin_busy         =    -1;  // BUSY (-1 = disable)

            cfg.panel_width      =   170;   
            cfg.panel_height     =   320;  
            cfg.offset_x         =    35;   
            cfg.offset_y         =     0;  
            cfg.offset_rotation  =     0;  
            //cfg.dummy_read_pixel =     8;  
            //cfg.dummy_read_bits  =     1;  
            cfg.readable         =  true;  
            cfg.invert           =  true;   // Display invert
            cfg.rgb_order        = false;  
            cfg.dlen_16bit       = false;   // 16bit SPI
            cfg.bus_shared       = false;   // SD true (drawJpgFile)

            //cfg.memory_width     =   240;  
               //cfg.memory_height    =   320;  

            _panel_instance.config(cfg);
        }

        { 
            auto cfg = _light_instance.config();    

            cfg.pin_bl = 17;              
            cfg.invert = false;           
            cfg.freq   = 44100;           
            cfg.pwm_channel = 7;          

            _light_instance.config(cfg);
            _panel_instance.setLight(&_light_instance);  
        }
        setPanel(&_panel_instance); 
  }
};

#define TFT_BL 17            
#define TFT_BACKLIGHT_ON HIGH               

LGFX tft;                                                           
LGFX_Sprite bgSprite(&tft);                                         
LGFX_Sprite numSprite(&tft);

//static TFT_eSPI tft;               
//static TFT_eSprite bgSprite(&tft);
//static TFT_eSprite numSprite(&tft);

uint16_t bg[900] = {0};

unsigned long previousMillis = 0;                   
const long interval = 10;                         
int counter = 0;                                    
int counterSec = 0;

void TFT_SET_BL(uint8_t Value) {
  if (Value < 0 || Value > 100) {
    log_e("ERROR! Value out of range. Value is set to 50 percent.");
    Value = 50;
    analogWrite(TFT_BL, Value * 2.55);
  } else {
    analogWrite(TFT_BL, Value * 2.55);
  }
}

void setup() {
  Serial.begin(921600);

  tft.init(); 

  //tft.setColorDepth(16);
  //bgSprite.setColorDepth(16);
  //numSprite.setColorDepth(16);

  tft.setRotation(1);                                 
  tft.fillScreen(TFT_BLACK);                                       
  tft.setFreeFont(&DSEG7_Classic_Bold_Italic_44);
  tft.setTextDatum(TR_DATUM);

  bgSprite.createSprite(320, 170);                    
  bgSprite.setTextColor(TFT_BLACK, 0x1111);   
  bgSprite.setTextSize(1); 
  bgSprite.fillSprite(0x3333);
  bgSprite.setTextDatum(BL_DATUM);
  bgSprite.setFreeFont(&DSEG7_Classic_Bold_Italic_44);
  bgSprite.drawString("8765432", 10, 151);
  bgSprite.pushSprite(0, 0);

  numSprite.createSprite(152, 65);                    
  numSprite.setTextColor(TFT_BLACK, 0x5555);   
  numSprite.setTextSize(1);                              
  numSprite.fillSprite(0x5555);
  numSprite.setTextDatum(BR_DATUM);
  numSprite.setFreeFont(&DSEG7_Classic_Bold_Italic_44);

  delay(300);                                       
  pinMode(TFT_BL, OUTPUT);
  TFT_SET_BL(30);
  //tft.setBrightness(30);
}

void loop() {
  //log_e("LOOP START");
  unsigned long currentMillis = millis();             

  if (currentMillis - previousMillis >= interval) {   
    previousMillis = currentMillis;                  
    counter++;                                      

    if(counter>99){
      counter=0; 
      counterSec++; 
      numSprite.drawNumber(counterSec, 70, 55);

      tft.readRect(15, 120, 30, 30, bg);         // <----     
      delay(100);
      tft.pushRect(260, 20, 30, 30, bg);            // <----

      delay(1000);
    }
    numSprite.drawNumber(counter, 145, 55);     
    tft.drawNumber(counter, 240, 55);
    numSprite.pushSprite(5, 22);
  }
}
/*

// --------------------Read Test------------------------
// Walking 1 write and read pixel test

//#include <TFT_eSPI.h>
#include <SPI.h>

#define TDELAY 500

//TFT_eSPI tft = TFT_eSPI(170,320); 
static LGFX tft;

void setup() {
  Serial.begin(921600);

  tft.init();
  tft.fillScreen(0xF81F);
}

void loop() {
  static uint32_t wr = 1;
  static uint32_t rd = 0xFFFFFFFF;

  delay(TDELAY);

  tft.drawPixel(30,30,wr);
  Serial.print(" Pixel value written = ");Serial.println(wr,HEX);

  rd = tft.readPixel(30,30);
                Serial.print(" Pixel value read    = ");Serial.println(rd,HEX);

  if (rd!=wr) {
    Serial.println(" ERROR                 ^^^^");
    //while(1) yield();
  }
  else Serial.println(" PASS ");
  // Walking 1 test
  wr = wr<<1;
  if (wr >= 0x10000) wr = 1;
}
*/
tobozo commented 3 months ago

hi,

have you tried readRectRGB() ?

markradev commented 3 months ago

hi,

have you tried readRectRGB() ?

Thanks. It seems the function cannot be overloaded with readRectRGB() and uint16_t. When I set the array to uint8_t it only briefly shows me a black display and doesn't even draw the section at the top right.

tobozo commented 3 months ago

that's because a rgb pixel is composed of 3x uint8_t, so you need to change the data type and the data size in your buffer:

uint8_t * my_buffer = (uint8_t *) malloc( width * height * 3 );

also you'll need to use the relevant method with a hint to the color type:

tft.pushImage( x, y, width, height, (lgfx:: rgb888_t*)my_buffer  );
markradev commented 3 months ago

that's because a rgb pixel is composed of 3x uint8_t, so you need to change the data type and the data size in your buffer:

uint8_t * my_buffer = (uint8_t *) malloc( width * height * 3 );

also you'll need to use the relevant method with a hint to the color type:

tft.pushImage( x, y, width, height, (lgfx:: rgb888_t*)my_buffer  );

That gives me this result Screen_3

tobozo commented 3 months ago

that's an odd result indeed, looks worse than the first test with the wrong colors. I don't have the exact same display model so I can't verify.

I did some research and found out that TFT_eSPI's ST7789 read frequency is 20MHz, however your setup uses 7MHz, is there any reason this particular value was picked?

    cfg.freq_read  = 7000000;    

sometimes a wrong freq_read value can mess up the colors, which means your initial approach with tft.readRect() may have been right and you should play with cfg.freq_read value while ignoring my previous suggestions to try with tft.readRectRGB()

btw I wonder why you use pinMode and TFT_SET_BL, is there anything broken with tft.setBrightness()?

markradev commented 3 months ago

that's an odd result indeed, looks worse than the first test with the wrong colors. I don't have the exact same display model so I can't verify.

I did some research and found out that TFT_eSPI's ST7789 read frequency is 20MHz, however your setup uses 7MHz, is there any reason this particular value was picked?

    cfg.freq_read  = 7000000;    

sometimes a wrong freq_read value can mess up the colors, which means your initial approach with tft.readRect() may have been right and you should play with cfg.freq_read value while ignoring my previous suggestions to try with tft.readRectRGB()

btw I wonder why you use pinMode and TFT_SET_BL, is there anything broken with tft.setBrightness()?

I also assume that it has to do with the SPI frequency for read. I have now tested again with tft_eSPI. For more than 11 MHz, tft_eSPI also shows me the wrong color (red background). Likewise, from 11 MHz with LovyanGFX, the errors in the read test increase.

7 MHz was the maximum in order not to produce errors with tft_eSPI, which is why I chose that, that was before my display output. With LovyanGFX the errors only increase from 11 MHz. Nothing changes underneath. Strangely enough, with tft_eSPI, the errors become incorrect with numbers above 800 and with LovyanGFX below 800 errors occur.

I tried all the settings in combination, which unfortunately didn't result in any improvement. Various SPI hosts, speeds (down to 10 kHz and up to 20 MHz) and SPI modes.

It looks like I can't use LovyanGFX for read functions with my display, so I'll have to resort to tft_eSPI or use another method for output, because of limitation of SPI capability.

tft.setBrightness() works, I only used the other lines for tft_eSPI.

tobozo commented 3 months ago

It looks like I can't use LovyanGFX for read functions with my display

it's unfair to blame LovyanGFX just because I failed to find the problem in your code

let's do a last test:

  // cfg.spi_host = SPI2_HOST; 
  // cfg.freq_write = 80000000;    
  // cfg.freq_read  = 7000000;  
lovyan03 commented 3 months ago

読出し周波数に依存して以下のパラメータを適切に変更する必要があります。 cfg.dummy_read_pixel = 8;
cfg.dummy_read_bits = 1;
すべてのパネルと周波数で安定する設定は存在しません。必要に応じて自分で設定値を見つけてください。

lovyan03 commented 3 months ago

LovyanGFXが使えないと思うなら、あなたは別のドライバを使えばいいと思います。

markradev commented 3 months ago

I'm sorry, but there has been a big misunderstanding here. I didn't mean LovyanGFX or even blamed it, but rather my hardware, the display and its SPI capability. LovyanGFX is a great library, otherwise I wouldn't use it. I also wanted to kindly express that I don't want to bother you any further. Thank you for your time and effort to help. It's not your fault either.

Unfortunately, your last suggestion didn't bring about any change. That doesn't matter, I'll think of a solution. Thanks again for your time.

I also have to say that I am new to this topic.

cfg.dummy_read_pixel = 8;
cfg.dummy_read_bits = 1;

For these two, I thought it was just for demonstration purposes or examples, so I commented it out. However, the default setting for the ST7789 is still used, which is the following:

cfg.dummy_read_pixel = 16;
cfg.dummy_read_bits = 1;

This was also used in another project with the ST7789. Unfortunately it didn't work for me. I tested everything from 0 to 82 bits. Unfortunately there was nothing suitable, but the setting with cfg.dummy_read_pixel = 32 came closest; and at 56, it was still wrong. Maybe it's because I'm using the ST7789v3.

As I said, I'll think of another solution and thank you.

lovyan03 commented 3 months ago
//  static uint32_t wr = 1;  /// ← this is RGB888 value
static uint16_t wr = 1;  /// ← this is RGB565 value