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

Tufty2040 display corruption when using large areas of pure white #567

Closed
ajnbrs opened this issue Nov 9, 2022 · 10 comments
Closed

Tufty2040 display corruption when using large areas of pure white #567

ajnbrs opened this issue Nov 9, 2022 · 10 comments
Labels
[- tufty2040 -] https://shop.pimoroni.com/products/tufty-2040 bug Something isn't working

Comments

@ajnbrs
Copy link

ajnbrs commented Nov 9, 2022

Basic test code here, image attached shows results when it goes bad...

from picographics import PicoGraphics, DISPLAY_TUFTY_2040, PEN_P4

PEN_P4 but results are the same with P8 and RGB_565,

RGB332 is fine but create_pen(255, 255, 255) is not giving me pure white, it has a yellowish hue

display = PicoGraphics(display=DISPLAY_TUFTY_2040, pen_type=PEN_P4)
display.set_backlight(0.5)

BLACK = display.create_pen(0, 0, 0)

display.set_pen(BLACK)
display.clear()

1. pure white small rectangle, works fine

#WHITE = display.create_pen(255, 255, 255)
#display.set_pen(WHITE)
#display.rectangle(0, 0, 100, 100)

2. pure white, larger rectangle, corrupt

#WHITE = display.create_pen(255, 255, 255)
#display.set_pen(WHITE)
#display.rectangle(0, 0, 180, 180)

3. slightly off white, larger rectangle, works

#WHITE = display.create_pen(240, 240, 240)
#display.set_pen(WHITE)
#display.rectangle(0, 0, 180, 180)

4. Slightly varying values close to 255, some work, some don't

doesn't work

#WHITE = display.create_pen(248, 252, 255)

works

#WHITE = display.create_pen(253, 250, 254)

works, closest I can get adjusting red

#WHITE = display.create_pen(247, 255, 255)

works, closest I can get adjusting green

#WHITE = display.create_pen(255, 251, 255)

works, closest I can get adjusting blue

WHITE = display.create_pen(255, 255, 247)

display.set_pen(WHITE)
display.rectangle(0, 0, 180, 180)

display.update()

IMG_0349

@ZodiusInfuser
Copy link
Member

Thanks for reporting. This is a bit of a head scratcher for us, as it seems like it would have been picked up pretty early in the product's life, yet nobody has reported such an issue. After some quick investigating, it looks like the issue occurs if the pen type is changed from the default PEN_RGB332 to any of the others. We tested the PEN_P4 you used and PEN_RGB565 and both have this issue. RGB565 is analogous to what the CircuitPython build uses.

Why those modes have this issue is currently a mystery....

@ajnbrs ajnbrs closed this as completed Nov 10, 2022
@ajnbrs ajnbrs reopened this Nov 10, 2022
@ajnbrs
Copy link
Author

ajnbrs commented Nov 10, 2022

I'm a newbie to MicroPython and MCU programming, and C/C++ and the bit operations I've seen for converting between colour formats is all a bit beyond me, but happy to help if you want anything tested.

I don't know if it's relevant but both my Tufty's have been purchased in the last month, any recent revisions to the boards?

Also is there anything useful about the thresholds I can get to when changing values for individual channels e.g. 247 for red and blue channels, 251 for green?

@ZodiusInfuser
Copy link
Member

If you want to look into the code then you're welcome to, but given that I was unable to resolve the issues with CircuitPython I suspect it will take some deep investigation to figure out what is wrong.

The boards haven't had any revisions since their launch, as far as I am aware.

I don't think knowing the exact colour thresholds will be that useful (it's something we can discover if we find it to be relevant). What you can do though is just confirm that the PEN_RGB332 type works for you, so that you can continue using the boards as you originally intended.

@ajnbrs
Copy link
Author

ajnbrs commented Nov 10, 2022

Thanks, no issue using the board now I know how to work around - I can't tell the difference between rgb(255, 255, 255) and rgb(250, 250, 250) anyway!

Re. RGB332, no corruption issues using rgb(255, 255, 255) however the resulting colour is not pure white, it has a distinct yellow hue. Difficult to capture on camera well but here you go:

P4, rgb(250, 250, 250):
IMG_0352

RGB332, rgb(255, 255, 255):

IMG_0353

@ZodiusInfuser
Copy link
Member

That's very interesting! I wonder if that's why the issue has not been noticed then. We'll have to investigate, but I have no idea when we will have the time to do so.

@insanire-monachus
Copy link

insanire-monachus commented Nov 14, 2022

I too experience this odd issue...

When I try to use the pure white (255, 255, 255) with PicoGraphics(display=DISPLAY_TUFTY_2040,pen_type=PEN_RGB565) the screen stutters or does not draw correctly the border [i.e. missing right edge on screen]).

Here is the code (which I modified, the one the unit already had as an example):


LIGHTEST = display.create_pen(255, 255, 255)
LIGHT = display.create_pen(245, 245, 245)
DARK = display.create_pen(0,101,189)
DARKEST = display.create_pen(0,140,255)

# draw company text
display.set_pen(LIGHT)
display.set_font("bitmap6")
display.text(COMPANY_NAME, BORDER_SIZE + PADDING, BORDER_SIZE + PADDING, WIDTH, 3)

# draw name text
display.set_pen(LIGHTEST)
display.set_font("bitmap8")
display.text(NAME, BORDER_SIZE + PADDING, BORDER_SIZE + PADDING + COMPANY_HEIGHT, WIDTH, 4)

# draws the blurb text (4 - 5 words on each line works best)
display.set_pen(LIGHTEST)
display.text(TITLE, BORDER_SIZE + PADDING + 120 + PADDING, 105, 160, 2)
display.text(SAYING, BORDER_SIZE + PADDING + 132 + PADDING, 140, 160, 2)

The best I could get with a stable screen (no stutter or missing elements) is:

LIGHTEST = display.create_pen(246, 246, 247)
LIGHT = display.create_pen(245, 245, 245)

There is no issue with pen_type=PEN_RGB332 hitting pure white (255,255,255) with the above code, and the QR image it generates (as well)...

@tannewt
Copy link

tannewt commented Nov 15, 2022

Is this board carried by any US vendors? Otherwise I'll go on a pimoroni shopping spree. :-)

@ZodiusInfuser ZodiusInfuser added the [- tufty2040 -] https://shop.pimoroni.com/products/tufty-2040 label Jan 20, 2023
@Gadgetoid
Copy link
Member

Gadgetoid commented May 15, 2023

The display's native format is RGB565 (18-bit) so everything gets upconverted to this.

An RGB332 pen, or 0b111_111_11 would get converted into 18-bit like so: 0b1110011100011000.

Or to RGB888 as 224, 224, 192.

This is why @ajnbrs has noted that white in RGB332 mode is actually yellow, since the Red and Green channels (Red + Green make yellow) are more saturated than blue. This is a side-effect of the colourspace.

Notably this might also suggest why the RGB332 pen type never sees this issue, since it never reaches the full 255, 255, 255 values. In RGB565 the maximum colour values are 248, 252, 248.

I can replicate this issue with the following code:

from picographics import PicoGraphics, DISPLAY_TUFTY_2040, PEN_RGB565 as PEN

lcd = PicoGraphics(DISPLAY_TUFTY_2040, pen_type=PEN)

lcd.set_backlight(0.8)

v = 255

while True:
    lcd.set_pen(lcd.create_pen(v, v, v))
    lcd.clear()
    lcd.set_pen(lcd.create_pen(0, 0, 0))
    lcd.rectangle(10, 10, 50, 50)
    lcd.update()

It only seems to affect RGB565 pen mode for me, which is the native pen mode of the display and uses a slightly different code path (no on the fly colourspace conversion) for screen updates. It's clear there's a bug with this code somewhere- potentially with some crossed wires about what's a command vs what's data.

Edit: As a note to myself as much as anything else, the largest working byteswapped RGB565 value which can be sent to the display is 0b1001111111110111 which corresponds to 240, 240, 248. Larger values might appear to work, but those bits are being truncated down to this value. This value is marginal and I seem to have more luck with 0b1001111011110111 or:

byte swap to:
0b1111011110011110

  RRRRR  GGGGGG  BBBBB
0b11110  111100  11110

240, 240, 240.

Will have to delve into the driver code and dig into this some more.

@emield12
Copy link

TLDR:
I had exaclty the same issue and, fixed it by removing this command in the display initialization code:

command(0xd6, 1, "\xa1"); // ???

I guess the same command should also be removed in the Pico Display pack initialization code a few lines further, but I don't have that display in order to test this.
command(0xd6, 1, "\xa1"); // ???


Long story & debugging process:
I had the same issue as described here, meaning the display "bugs out" after setting the complete frame buffer to white in RGB565 mode (0xffff). Lowering the intensity of the white "fixes" the problem. Note that the problem was not occurring consistently at the same threshold, sometimes 240, sometimes 238,...

I did a second test by filling the display with progressively more white pixels. This also produced a similar problem when I filled the screen with more than 135 fully white lines. However, something interesting happened when I set the threshold right on the limit between a working and "bugged out" screen. It first shows the image correctly, but then it started flickering and broke the image. This is clearer with a short video:

VID_20231215_122025.mp4

Note that in this test, I only update the screen once at the start of the code. After updating the screen, the main loop simply updates the LED every 0.5s to show that the Pico is still running properly. This behavior made me think that the problem wasn't directly linked to the DMA data transfer to the ST7789, as the screen worked correctly at the beginning.

However, I still went ahead and changed the code so that the RGB565 pen code followed a similar code path as the RGB332 code (as suggested by @Gadgetoid). So, I commented out the alternative code path in the ST7789::update method and added a frame_convert method to the PicoGraphics_PenRGB565 class:

ST7789::update
void ST7789::update(PicoGraphics *graphics) {
    uint8_t cmd = reg::RAMWR;

    // if(graphics->pen_type == PicoGraphics::PEN_RGB565) { // Display buffer is screen native
    //   command(cmd, width * height * sizeof(uint16_t), (const char*)graphics->frame_buffer);
    // } else {
      gpio_put(dc, 0); // command mode
      gpio_put(cs, 0);
      if(spi) { // SPI Bus
        spi_write_blocking(spi, &cmd, 1);
      } else { // Parallel Bus
        write_blocking_parallel(&cmd, 1);
      }

      gpio_put(dc, 1); // data mode

      graphics->frame_convert(PicoGraphics::PEN_RGB565, [this](void *data, size_t length) {
        if (length > 0) {
          write_blocking_dma((const uint8_t*)data, length);
        }
        else {
          dma_channel_wait_for_finish_blocking(st_dma);
        }
      });

      gpio_put(cs, 1);
    // }
  }
PicoGraphics_PenRGB565::frame_convert
    void PicoGraphics_PenRGB565::frame_convert(PenType type, conversion_callback_func callback) {
        if(type == PEN_RGB565) {
            uint16_t *src = (uint16_t *)frame_buffer; 

            frame_convert_rgb565(callback, [&](){
                // No conversion needed as it is alread in the correct format.
                return *src++;
            });
        }
    }

However, this did not fix the issue.

At that point, I decided to check the configuration of the display and I immediately stumbled upon this one command that wrote to a register that is not documented in the datasheet of the ST7789:

command(0xd6, 1, "\xa1"); // ???

By removing that command, everything works correctly on my display. I have no idea why that command is there and what it is supposed to do. If anybody has an idea, I would be interested to know 😄.

Hopefully someone else can reproduce this, so that it can be fixed in the main code.

Gadgetoid added a commit that referenced this issue Jan 23, 2024
This should, in theory, fix the weird display corruption bug affecting Tufty 2040.
Gadgetoid added a commit that referenced this issue Jan 23, 2024
st7789: Remove mystery meat command implicated by #567.
@Gadgetoid
Copy link
Member

Fix (for Tufty 2040 at least) merged in #898, I managed to repro and posted code, before and after images for posterity- lest this crop up with any of our other ST7789 displays.

Excellent find, thank you, and sorry for the enormous delay actually getting it merged- it's been quite a tumultuous few months!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[- tufty2040 -] https://shop.pimoroni.com/products/tufty-2040 bug Something isn't working
Projects
None yet
Development

No branches or pull requests

6 participants