-
Notifications
You must be signed in to change notification settings - Fork 495
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
Comments
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 Why those modes have this issue is currently a mystery.... |
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? |
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 |
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: RGB332, rgb(255, 255, 255): |
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. |
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)
The best I could get with a stable screen (no stutter or missing elements) is: LIGHTEST = display.create_pen(246, 246, 247) 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)... |
Is this board carried by any US vendors? Otherwise I'll go on a pimoroni shopping spree. :-) |
The display's native format is RGB565 (18-bit) so everything gets upconverted to this. An RGB332 pen, or Or to RGB888 as 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 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
Will have to delve into the driver code and dig into this some more. |
TLDR: pimoroni-pico/drivers/st7789/st7789.cpp Line 92 in b4451c3
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. pimoroni-pico/drivers/st7789/st7789.cpp Line 101 in b4451c3
Long story & debugging process: 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.mp4Note 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::updatevoid 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: pimoroni-pico/drivers/st7789/st7789.cpp Line 92 in b4451c3
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. |
This should, in theory, fix the weird display corruption bug affecting Tufty 2040.
st7789: Remove mystery meat command implicated by #567.
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! |
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()
The text was updated successfully, but these errors were encountered: