Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

T4-S3 display driver chip strange behaviour #16

Closed
clydebarrow opened this issue Jan 29, 2024 · 22 comments
Closed

T4-S3 display driver chip strange behaviour #16

clydebarrow opened this issue Jan 29, 2024 · 22 comments

Comments

@clydebarrow
Copy link

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:

  • configure the sample code platformio.ini to select the lvgl scroll demo:
src_dir = examples/lvgl/scroll
  • Edit examples/lvgl/scroll/lv_example_scroll_1.c and change the width of the scroll window to 198:
void lv_example_scroll_1(void)
{
    /*Create an object with the new style*/
    lv_obj_t *panel = lv_obj_create(lv_scr_act());
    lv_obj_set_size(panel, 198, 200);
    lv_obj_center(panel);

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
Copy link
Contributor

lewisxhe commented Jan 29, 2024

This is not a problem with the driver chip, but more like a problem with the QSPI driver.
There is a related issue here #6
Currently, all products using QSPI cannot use partial refresh and are displayed through full refresh.

@clydebarrow
Copy link
Author

clydebarrow commented Jan 29, 2024

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
Copy link
Contributor

T-Display S3 is a parallel interface, not QSPI

@lewisxhe
Copy link
Contributor

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

@clydebarrow
Copy link
Author

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
Copy link
Contributor

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

@clydebarrow
Copy link
Author

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
Copy link
Author

clydebarrow commented Jan 29, 2024

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
Copy link
Contributor

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

@clydebarrow
Copy link
Author

clydebarrow commented Jan 29, 2024

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
Copy link
Contributor

lewisxhe commented Jan 29, 2024

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
Copy link
Author

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
Copy link
Contributor

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

@clydebarrow
Copy link
Author

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
Copy link
Author

I'll fix it after the new screen arrives

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

@lewisxhe
Copy link
Contributor

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
Copy link
Author

clydebarrow commented Jan 29, 2024

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
Copy link
Contributor

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
Copy link
Author

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
Copy link
Contributor

I will test it tomorrow, thanks again

@lewisxhe
Copy link
Contributor

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants