Xinyuan-LilyGO / LilyGo-AMOLED-Series

LilyGo AMOLED Series
MIT License
88 stars 14 forks source link

T4-S3 display driver chip strange behaviour #16

Closed clydebarrow closed 3 months ago

clydebarrow commented 3 months ago

I'm testing on a T4-S3 AMOLED display, and have determined that when setting the address window for the display update, the starting x-position and width must both be even, otherwise the display is not updated correctly. This occurs both with my own code and I have reproduced it in the sample code.

To reproduce:

Edit src/LV_Helper.cpp and set the full_refresh flag to false:

    disp_drv.full_refresh = 0;

Edit src/LilyGo_AMOLED.cpp and add a logging line to note the address window:

void LilyGo_AMOLED::setAddrWindow(uint16_t xs, uint16_t ys, uint16_t xe, uint16_t ye)
{
  Serial.printf("setaddrwindow %d/%d, %d/%d\n", xs, ys, xe, ye);

Build and run the example. Observe the initial (full) redraw of the screen - the log line is:

setaddrwindow 0/0, 449/599

And the display looks like this - all correct:

PXL_20240129_005637746 MP

Now touch the screen and cause the window to scroll; observe the log line and note that the x-start address is an odd number:

setaddrwindow 121/195, 328/404

And the screen display becomes garbled: PXL_20240129_005649846 MP

I have done further testing and confirmed that if the x-start of setAddrWindow is an odd number or the x-end is an even number, then the problem occurs. It seems that the chip will only set an address window of even length starting on an even boundary.

I have been unable to find a datasheet for the RM690B0 to see if this behaviour is configurable. The same code on a T-Display-S3 (using an RM67162 for which there is a datasheet) works correctly.

The compiled demo program is attached.

x.zip

lewisxhe commented 3 months ago

This is not a problem with the driver chip, but more like a problem with the QSPI driver. There is a related issue here https://github.com/Xinyuan-LilyGO/LilyGo-AMOLED-Series/issues/6 Currently, all products using QSPI cannot use partial refresh and are displayed through full refresh.

clydebarrow commented 3 months ago

Partial refresh works just fine on the T-Display S3 AMOLED using the same QSPI driver, so that's not the issue. Is there a datasheet for the chip?

lewisxhe commented 3 months ago

T-Display S3 is a parallel interface, not QSPI

lewisxhe commented 3 months ago

The datasheet is already linked in the README, and all resources are outlined in the README.

clydebarrow commented 3 months ago

T-Display S3 is a parallel interface, not QSPI

T-Display S3 AMOLED is definitely QSPI, and partial refresh works fine on it. The exact same compiled file I uploaded runs correctly on it.

lewisxhe commented 3 months ago

T-Display S3 AMOLED and T-Display S3 are two products..

lewisxhe commented 3 months ago

https://github.com/Xinyuan-LilyGO/LilyGo-AMOLED-Series/blob/master/datasheet/RM690B0%20DataSheet_V0.2.pdf

clydebarrow commented 3 months ago

The datasheet is already linked in the README, and all resources are outlined in the README.

Ah, I see it is there now - was not when I looked previously. Thanks.

clydebarrow commented 3 months ago

This is not a problem with the driver chip, but more like a problem with the QSPI driver.

The SPI uses only single bit mode for sending commands and their parameters (see page 28 of the datasheet.) Quad SPI is used only for pixel data transmission. All other commands other than CASET work normally using the same transmission.

Because of the high pixel count of this display having to do a full display update whenever anything changes has a significant performance impact.

There is another problem - the left hand 18 pixels are not visible unless an offset is used. Here's an image from the display: Photo

And this is what it should look like:

Screenshot 2024-01-29 at 3 26 37 pm

If I set an offset of 18, then it displays correctly. I confirmed this with the Factory firmware demo by adding a rectangle to the first page - it gets cut off along one edge.

(I initially thought the width was less than 450, but it's actually impossible to tell the difference with the naked eye between an unlit pixel and the edge of the display, so the offset was all that was needed.)

In all other respects this is a very nice board - the display is bright and crisp, and the QSPI is fast - the datasheet shows up to 50MHz and I have successfully used 80MHz.

lewisxhe commented 3 months ago

Which direction are you talking about? In the default factory firmware, it seems that opening the window is correct.

clydebarrow commented 3 months ago

The long side, near the WiFi antenna, opposite the USB, is affected. In the factory demo as built from source this is the top of the display. The required offset is about 18 pixels, it's hard to tell exactly because the screen is so black it's impossible to tell where the actual edge of the display is. I tried using the 0x23 command to turn on all pixels, which works, but then you can't see anything that's drawn :-)

Photo Jan 29

  auto lvobjtype_2 = lv_obj_create(parent);
  lv_obj_set_style_bg_color(lvobjtype_2, lv_color_hex(0xFFFFFF), (int)LV_STATE_DEFAULT|(int)LV_PART_MAIN);
  lv_obj_set_style_border_color(lvobjtype_2, lv_color_hex(0x0000FF), (int)LV_STATE_DEFAULT|(int)LV_PART_MAIN);
  lv_obj_set_style_border_width(lvobjtype_2, 2, (int)LV_STATE_DEFAULT|(int)LV_PART_MAIN);
  lv_obj_set_style_width(lvobjtype_2, 50, (int)LV_STATE_DEFAULT|(int)LV_PART_MAIN);
  lv_obj_set_style_outline_width(lvobjtype_2, 0, (int)LV_STATE_DEFAULT|(int)LV_PART_MAIN);
  lv_obj_set_style_height(lvobjtype_2, lv_pct(100), (int)LV_STATE_DEFAULT|(int)LV_PART_MAIN);
  lv_obj_align(lvobjtype_2, LV_ALIGN_CENTER, 0, 0);
lewisxhe commented 3 months ago

I just tested the screen completely refreshed, added the border test, and found that pixel offset is also needed. I have not tested the screen border before. Thank you for your feedback, can you submit a fix? The screen I have now has a display problem and is damaged at the border. I need to wait until a new screen arrives before I can repair it.

clydebarrow commented 3 months ago

I'll let you fix your code (you just need to add 18 to the xs and xe values (or ys and ye if in portrait) in setAddrWindow.) This is my fix in ESPHome:

display:
  - platform: qspi_amoled
    model: RM690B0
    data_rate: 80MHz
    dimensions:
      width: 450
      height: 600
      offset_width: 18  ## Correction for display edge offset
    color_order: rgb
    brightness: 255
    cs_pin: 11
    reset_pin: 13
    enable_pin: 9

See https://gist.github.com/clydebarrow/ef89e9a93bd44771483b9144ae9042a1 and https://deploy-preview-3510--esphome.netlify.app/components/lvgl for more details.

lewisxhe commented 3 months ago

OK . Thanks . I'll fix it after the new screen arrives

clydebarrow commented 3 months ago

This is the set_addr_window code in my driver:

  void set_addr_window_(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2) {
    uint8_t buf[4];
    x1 += this->offset_x_;
    x2 += this->offset_x_;
    y1 += this->offset_y_;
    y2 += this->offset_y_;
    put16_be(buf, x1);
    put16_be(buf + 2, x2);
    this->write_command_(CASET, buf, sizeof buf);
    put16_be(buf, y1);
    put16_be(buf + 2, y2);
    this->write_command_(RASET, buf, sizeof buf);
clydebarrow commented 3 months ago

I'll fix it after the new screen arrives

What's the new screen? Something exciting I hope!

lewisxhe commented 3 months ago

What I mean is that the screen of the T4-S3 I have is damaged and there is a problem with the border display. I need to wait until I get a new T4-S3 to solve it.

clydebarrow commented 3 months ago

After some more tests, using the ALL_ON (0x23) command alternating with NORMAL_DISPLAY_ON (0x13) I have determined that the correct offset value is 16.

In fact, I wonder if it should really be 15 - this would make sense given that the RM6090B0 can drive a 480 wide display, so using only 450 leaves 30 spare, so half each side is 15. But 15 as an offset is unusable, since that triggers the same problem as partial refresh and results in the display data skewed at 45 degrees.

lewisxhe commented 3 months ago

Hi, I was working on other problems in the morning, now I have time to test this I can confirm from this screen I have that offset 16 can be resolved, although it is broken, I will submit an update, thank you again for your contribution image

image

image

image

clydebarrow commented 3 months ago

I have worked around the odd-boundary problem on partial refresh with this in the LVGL setup:

  static void rounder_cb(lv_disp_drv_t *disp_drv, lv_area_t *area) {
    // make sure all coordinates are even
    if (area->x1 & 1)
      area->x1--;
    if (!(area->x2 & 1))
      area->x2++;
    if (area->y1 & 1)
      area->y1--;
    if (!(area->y2 & 1))
      area->y2++;
  }

...
// in setup()
    this->disp_drv_.rounder_cb = rounder_cb;

This avoids the problem and allows partial refresh when using LVGL, with minimal impact on any other display.

lewisxhe commented 3 months ago

I will test it tomorrow, thanks again

lewisxhe commented 3 months ago

@clydebarrow It has been tested and is OK. Partial updates are normal. Thank you for your contribution.