rm-hull / luma.lcd

Python module to drive PCD8544, HT1621, ST7735, ST7567 and UC1701X-based LCDs
https://luma-lcd.readthedocs.io
MIT License
156 stars 56 forks source link

ILI9486 (Waveshare 3.5-inch (B)) support #136

Closed mattblovell closed 3 years ago

mattblovell commented 3 years ago

The following additions, primarily to device.py are working for me when using this ILI9486-based display:

https://www.waveshare.com/3.5inch-rpi-lcd-b.htm

attached directly to the GPIO header of an RPi4 Model B. That particular display (or the controller) wants to run in portrait mode, 320x480. Rotation is thus necessary to use it as 480x320. (I was stuck for quite a while getting an odd display trying to use it in landscape mode.)

The various demos within luma.examples all seem to be happy, using either full_frame or the diff algorithm to update the framebuffer. Some misc observations:

Thanks, Matt

fixes #135

Gradient screen from colors.py @ 32 MHz

IMG-0715_gradient_32MHz

Gradient screen from colors.py @ 28 MHz

IMG-0716_gradient_28MHz

rm-hull commented 3 years ago

Nice!

Out of interest, have you tried the Linux framebuffer driver with this display?

To get this PR through we ought add some simple regression tests and update the documentation

rm-hull commented 3 years ago

... and probably convert the CI from Travis to GitHub actions (in another PR) beforehand

thijstriemstra commented 3 years ago

... and probably convert the CI from Travis to GitHub actions (in another PR) beforehand

See #137

mattblovell commented 3 years ago

Out of interest, have you tried the Linux framebuffer driver with this display?

Yes, I first tried out the display via the repository that Waveshare provides:

https://github.com/waveshare/LCD-show.git

I didn't use their shell scripts, but inspected what overlay they make use of and loaded it myself. The dtoverlay uses a compatible string of ilitek,ili9486 with these addition parameters:

            waveshare35b@0 {
                compatible = "ilitek,ili9486";
                reg = <0x00000000>;
                pinctrl-names = "default";
                pinctrl-0 = <0x00000001>;
                spi-max-frequency = <0x00e4e1c0>;
                txbuflen = <0x00008000>;
                rotate = <0x0000005a>;
                bgr = <0x00000000>;
                fps = <0x0000001e>;
                buswidth = <0x00000008>;
                regwidth = <0x00000010>;
                reset-gpios = <0xffffffff 0x00000019 0x00000001>;
                dc-gpios = <0xffffffff 0x00000018 0x00000000>;

in addition to an array of init bytes. The spi-max-frequency above is 15 MHz. The overlay file looks to be identical to the GPL-licensed one at

https://github.com/TobiasVanDyk/RaspberryPi-GPIO-Displays/blob/master/ili9486/Waveshare/waveshare35b-v2.dts

(The relationship between that github repository and Waveshare's is unclear to me.)

The luma.examples work fine via linux_framebuffer, with bounce achieving >20 fps when using the diff algorithm. The combination of luma.core's diff algorithm with whatever approach the device driver is taking for updates leads to a fair amount of tearing. Using full_frame, bounce gets 6.2 fps through the framebuffer.

Using luma.lcd directly at 50 MHz (a frequency that is certainly questionable for this display), bounce is achieving 5.3 fps with full_frame and 19 to 23 fps with diff. There's much less tearing, though! :)

To get this PR through we ought add some simple regression tests and update the documentation

I'll take a look at what the tests require. Since the tests presumably run without actual display hardware, are they just performing some sanity checks? The ili9486 addition mimics the structure of the ili9341 support identically.

My chief concern is that other ili9486 displays may not have the 16-bit registers of the particular Waveshare that I have. Looking around github at other (open license) implementations for ili9486 support, the byte padding only gets mentioned in conjunction with Waveshare. That would seem straightforward to support -- use a conditional to control whether padding gets added or not -- but that conditional would be unique to the ili9486. I also have no means of HW testing it.

mattblovell commented 3 years ago

Any hints on how one runs tests? I'm still relatively new to Python development, and the amount of infrastructure around Python projects is impressive. That said, I don't know how to run much!

thijstriemstra commented 3 years ago

@mattblovell from repo checkout directory:

make sure to install tox, pytest etc first using:

pip install -e .[test]

then run tests:

tox -e py37

or py38 or whatever version you're using.

also run:

tox -e qa

to check for any lint errors.

rm-hull commented 3 years ago

I tend to develop luma code & run tests on a Mac or desktop Linux machine rather than on an RPi. It was often painfully slow - certainly on RPi 2B, but might be better now on 4B

rm-hull commented 3 years ago

Also, I can help out with the tests. We can mostly do a cut’n’paste job from ili9341

mattblovell commented 3 years ago

Also, I can help out with the tests. We can mostly do a cut’n’paste job from ili9341

That would be most appreciated! I'll see if I can free up some time tonight to try out tox (per @thijstriemstra's reply above), but I don't necessarily know what I'm doing with the test infrastructure.

mattblovell commented 3 years ago

I double-checked that the padding zeros are indeed needed for the Column Address Set (0x2A) and Page Address Set (0x2B) commands within ili9486.display(). Removing any of the zero padding (either after the command or those in between any of the command's parameters) results in the diff_to_previous algorithm not getting drawn correctly on-screen.

"Armed" with that information, I thought I would reexamine the positive and negative gamma settings for ili9486 in both juh/fbcp-ili9341 and ImpulseAdventure/Waveshare_ILI9486. Adding the commands with byte pads just yields terrible colors -- blues and purples end up with really bad saturation.

Dumping the initialization bytes from the dtoverlay that Waveshare makes available and pulling the gamma correction from those, colors seem fine but don't appear noticeably different than what the display uses without any gamma controls specified.

The Waveshare overlay is using 18-bit colors, which matches the initialization I'm trying (via Memory Access Control, 0x36). The other two repositories are only set up for 16-bit colors. Perhaps that explains the difference.

Anyway, just thought I'd explore the gamma settings a bit further.

mattblovell commented 3 years ago

I think I have the entries in test_ili9486.py working. I only have one screen size (full) supported.

tests/test_ili9486.py::test_init_320x480 PASSED                                                                    [ 56%]
tests/test_ili9486.py::test_init_invalid_dimensions PASSED                                                         [ 58%]
tests/test_ili9486.py::test_offsets PASSED                                                                         [ 60%]
tests/test_ili9486.py::test_contrast PASSED                                                                        [ 61%]
tests/test_ili9486.py::test_hide PASSED                                                                            [ 63%]
tests/test_ili9486.py::test_show PASSED                                                                            [ 64%]
tests/test_ili9486.py::test_display_full_frame PASSED                                                              [ 66%]

Execution time for tox -e py37 on an RPi4:

real    0m14.644s
user    0m9.499s
sys     0m1.141s

I don't immediately know why the Python 3.8 tests are unhappy.

mattblovell commented 3 years ago

I don't immediately know why the Python 3.8 tests are unhappy.

Ah, linting woes. I like blank lines, though! :)

I'll try to clean that up...

rm-hull commented 3 years ago

FYI, you can run tox -e qa to run the PEP8 and documentation checks, and usually flake8 can be used to auto format (we should probably have a tox target that does this)

mattblovell commented 3 years ago

I’ve got one of these on order now because of you!

Excellent! Hopefully it even works! 😄

Did you get the Waveshare one or a different ILI9486-based one? I have to say that the IPS panel is a nice feature.

mattblovell commented 3 years ago

Great!

I'm very glad to contribute back to luma.lcd. The excellent documentation for this project, and the breadth of supported displays, is what encouraged me to give these little LCD displays a try in the first place. I've learned a lot since September.

rm-hull commented 3 years ago

v2.8.0 released with this in :rocket: https://pypi.org/project/luma.lcd/2.8.0/

Matthew1471 commented 1 year ago

16-bit

RE: 16-bit registers, I just found this : https://github.com/torvalds/linux/blob/master/drivers/gpu/drm/tiny/ili9486.c#L38