adafruit / Adafruit_Blinka_Displayio

Displayio for Blinka
MIT License
14 stars 20 forks source link

SSD1327: raspberry pi display corruption #80

Closed koush closed 1 year ago

koush commented 2 years ago

This is the result of attempting to run the "simpletest" example through i2c on a raspberry pi zero 2 and raspberry pi 4. Have tried both displays, for the same results on each. Any suggestions? Seems like a driver bug.

IMG_7238_HEIC

koush commented 2 years ago

The tearing is from taking the photo. The image looks like a waffle iron.

koush commented 2 years ago

I've confirmed that other displays work fine through the same i2c.

ladyada commented 2 years ago

please note that we don't have raspberry pi as one of the official supported system at this time https://learn.adafruit.com/adafruit-grayscale-1-5-128x128-oled-display/circuitpython-wiring-and-usage so it may take a while to get it supported!

makermelissa commented 2 years ago

This was barely tested on Blinka Displayio, so I'm not surprised at this.

AlexKlimaj commented 2 years ago

Ah this is what I am seeing here.

https://github.com/adafruit/Adafruit_CircuitPython_SSD1327/issues/15

AlexKlimaj commented 2 years ago

Looks like this is getting called causing every other byte to be 0x80. It doesn't look like the SSD1327 requires that. https://github.com/adafruit/Adafruit_Blinka_Displayio/blob/main/displayio/_i2cdisplay.py#L101

image

makermelissa commented 2 years ago

Ok, it's probably happening here: https://github.com/adafruit/Adafruit_Blinka_Displayio/blob/main/displayio/_i2cdisplay.py#L101-L102

makermelissa commented 2 years ago

It appears to be the same in CircuitPython's displayio: https://github.com/adafruit/circuitpython/blob/main/shared-module/displayio/I2CDisplay.c#L106-L122 Have you compared the outputs of both?

makermelissa commented 2 years ago

There's no output when connected via SPI. I never programmed in monochrome or grayscale support, so this is likely part of the issue.

AlexKlimaj commented 2 years ago

How do you recommend tackling the problem? I can work on a PR.

makermelissa commented 2 years ago

Perhaps check with your scope when running CircuitPython and compare to output when running Blinka? Maybe it'll provide a clue based on what is different.

AlexKlimaj commented 2 years ago

I think I'm confused about Circuitpython and Blinka. Don't I need Blinka to run Circuitpython on the raspberry pi?

makermelissa commented 2 years ago

No worries. CircuitPython is a version of Python designed to run on MicroControllers. See all the boards it supports here: https://circuitpython.org/downloads. Blinka is the CircuitPython compatibility layer that allows the libraries written for CircuitPython to be run on top of regular Python and Linux.

Note: Since CircuitPython was ported over to run on Bare Metal on the Raspberry Pi (No Linux), it muddied the waters a bit, but for that Blinka isn't necessary.

AlexKlimaj commented 2 years ago

Thanks for the help Melissa. I think my solution will be to switch to the regular 128x128 OLED, non greyscale version.

AlexKlimaj commented 2 years ago

Okay, appears this is the same behavior on the sh1107 as well. Scope capture shows 0x80 inserted every other byte. Looking at the sh1107 datasheet, 0x80 is for contrast control. Is the inserting 0x80 needed for another display?

bablokb commented 2 years ago

I have the same problem on a SSD1306 (corrupt screen). The program works fine on a Qt-RP2040-trinkey.

The displayio code for "native" CircuitPython also inserts the 0x80 and the display has no problems, so that does not seem to be the root-cause. It would be worth investigating the lower-level i2c write code (common_hal_busio_i2c_write), maybe that code removes the 0x80 again?!

bablokb commented 2 years ago

After analyzing the code, I think displayio._refresh_display_area() is the culprit. This code silently assumes that the display can handle 16-bit 565-encoded pixels. So it is neither a raspberry pi nor an I2C issue.

My idea would now be to convert the internal image-buffer to the correct color-depth and then use adafruit_framebuf to get the pixel-encoding right. Does this sound like a sensible thing to try?

makermelissa commented 2 years ago

Thanks for tracing it down. I'd prefer that we didn't use adafruit_framebuf (it currently uses a Pillow image as a buffer like you mentioned). I think the code to convert the pixel encoding should be in _palette.py. Please look at the original CircuitPython displayio module and adapt code from there.

bablokb commented 2 years ago

Hm, I disagree on that. _palette.py is not about pixel-encoding, but color-encoding. And from adafruit_framebuffer I would only use (a subset of ?) the conversion classes:

class MVLSBFormat   # Single bit displays (like SSD1306 OLED)
class RGB565Format  # 16-bit color displays
class MHMSBFormat  # Single bit displays like the Sharp Memory
class RGB888Format # Neopixels and Dotstars

Anyhow, adapting the code from the original displayio module would probably be the right way to go. But honestly even with almost 40 years of experience as a C-programmer this code is a nightmare. Hundreds of lines of code without a single comment. It is like reading a novel: I understand every word but I don't get a grip on the plot. You have my highest respect for porting so much of it already, thank you.

makermelissa commented 2 years ago

Thanks. There's definitely room for improvement. The whole thing was originally thrown together in about a week. Feel free to submit a PR with any improvements.

makermelissa commented 1 year ago

Closing in favor of #105. The issue is not the I2C data, but the grayscale support.