Anyone looking for components for electronics projects, especially robotics, microcontrollers, and IoT devices, has likely heard of Waveshare. They are additionally well-known suppliers of low-cost displays with a wide range of resolutions, sizes, and capabilities, but as [Dmitry Grinberg] found, they’re not all winners. He thought the price on this 2.8-inch display might outweigh its poor design and lack of documentation, and documented his process of bringing it up to a much higher standard with a custom driver for it.
The display is a 320×240 full-color LCD which also has a touchscreen function, but out-of-the-box only provides documentation for sending data to it manually. This makes it slow and, as [Dmitry] puts it, “pure insanity”. His ultimate solution after much poking and prodding was to bit-bang an SPI bus using GPIO on an RP2040 but even this wasn’t as straightforward as it should have been because there are a bunch of other peripherals, like an SD card, which share the bus. Additionally, an interrupt is needed to handle the touchscreen since its default touch system is borderline useless as well, but after everything was neatly stitched together he has a much faster and more versatile driver for this display and is able to fully take advantage of its low price.
For anyone else attracted to the low price of these displays, at least the grunt work is done now if a usable driver is needed to get them up and running. And, if you were curious as to what [Dmitry] is going to use this for, he’s been slowly building up a PalmOS port on hardware he’s assembling himself, and this screen is the perfect size and supports a touch interface. We’ll keep up with that project as it progresses, and for some of [Dmitry]’s other wizardry with esoteric displays make sure to see what he’s done with some inexpensive e-ink displays as well.
I don’t really understand all the rant about a SPI-connected display being slow – that’s a normal limitation of choosing SPI over parallel, and the shared bus to touch controller also makes sense if you are saving pins.
But yeah, what they did is probably the fastest way to transfer data to such a display.
For a display SPI *is* slow. But the module/board was designed in way that pretty much forced all communication with it to be done in software, which is also extremely inefficient. When you have something like a display, ideally you would set up a buffer to transfer each frame and let the DMA+peripherals do the work. Having to wait for transfers to complete or constantly handle interrupts to send SPI data a pixel at a time pretty much kills off any hope of doing other tasks.
Basically, this. Yes.
This, basically
Hmm, I think RP2040’s DMA chaining can help there. You can run eg. one frame transfer, one touchscreen transfer and repeat from start, with just spi peripheral and dma.
But the color / grayscale mapping using PIO is indeed clever and conserves CPU ram.
It is not that easy, because the maximum SPI speed for the display is 62.5 MHz, but for the touch controller is 2.5 MHz so you will need to reconfigure the SPI controller, not just give it a different things to send. Suddenly your DNMA training starts getting complicated. Now you need to manage chip select pins, configurations of the unit itself, and the data. Plus, if you only sample touch, once per frame, you end up with Temporal resolution of just 45 Hz. That is not good enough for smooth inking.
Because the linked article does not even tell:
it´s a plain ST7789 driver.
Otherwise the (linked) article is well written with exhaustive details and the whole code would benefit – a lot – to the Micropython version of LittleVGL
LVGL a great graphic library that needs more people optimizing and developing drivers, this part of micropython/LVGL dramatically needs care.
Have a look of a demo of LVGL: https://www.youtube.com/watch?v=ZWtTmmne6Bo
Port it there :).
The Arduino environment has supported these displays with the Pico for several years now with the awesome and fast TFT_eSPI library by Bodmer and of course Adafruit’s graphic library. As well as others. I must be missing something here. Folks run real time video on SPI displays all the time…
https://github.com/Bodmer/TFT_eSPI
Compare the perf and see :)
https://www.youtube.com/watch?v=njFXIzCTQ_Q
https://forum.arduino.cc/t/tft_espi-support-for-raspberry-pi-pico-added/702551/2
Pretty decent performance with standard Arduino library. I have run this example on both Arduino implementations (it is much faster on the official version but still runs well on the Philhower version.)
There is also a discussion about the Pico’s two channel hardware interpolator here and an example of real-time smooth image rotation which is really interesting.
Here is another library that is well done:
https://www.instructables.com/ArduinoGFX/
On the Pico Pi
https://youtu.be/Ip3VahOQS9w
Summary:
– APIs provided by display vendor were for updating pixels or a line of pixels only
– User wished to have a fast way to write entire RAM framebuffer to display
– Further complication in that display and touchscreen shared same SPI interface
Solution:
– User was able to have Pico’s PIO and DMA engines update display over SPI
– PIO also takes care of reading touchscreen
– Main CPU can just worry about updating the framebuffer now
Comment:
For relatively static display applications, the original APIs were probably fine. For video, obviously not.
also greyscale and indexed color modes are provided that the original display has no support for at all.
Well, those are framebuffer modes, which are not relevant when you don’t have a memory-mapped framebuffer.
He bought the wrong display for his application, then was upset that it did not fit his application. Admirable job making it work, I guess. If you just want your pico painting some buttons and showing some status, you probably do not care about frame rates and are fine with drawing a new screen when needed.
I did coincidentally get a good wade through the waveshare sample code for a similar display recently, and it is indeed quite inefficient, but I refer to how it inefficiently uses the spi bus. Fixed that, and the result was a library that draws the same way as theirs, but much faster. I don’t think doing it that way makes me an idiot. (Plenty of other things do.)
I see that you were also confused by the article’s description. He bought a perfectly suitable display that just didn’t have the software interface that he wanted, so he implemented a new interface for it that took advantage of the Pico’s PIO’s and DMA hardware. Hardware-wise, the only unsuitable bit for him was that the display and touchscreen both utilized the same interface bus, but he was able to work around this issue with just a bit of framerate loss. Possibly, he could have also worked around it with some hardware mods, but he didn’t go in that direction.
Why does the author of this post state that Dmitry ended up “bit-banging the SPI using the GPIO” while in reality he used the DMA and the PIO hardware, which is quite the opposite of bit-banging…?
Initial setup is done via bit-banging; once the initialization is complete, then he switches to DMA/PIO.
I really dislike that the author is calling the display “poorly designed”, the creator of the display “idiots”, etc. He is using the wrong tool for his job and now complains that it doesn’t do what he wants. These SPI displays are well suited if you want to display mostly static information while using a low number of pins. They were never intended for high frame rates, there are other interfaces for these applications.
When you use the display as intended it makes sense to combine as many functions as possible on a single bus.
So the author bought a screwdriver and complains that it is very bad at driving nails into the wall.
Hard disagree. While designing a screwdriver you design is as well as possible, not as flimsily as possible under the excuse that screwdrivers need not be sturdy. Also, they ARE designed for high frame-rates, that is why they are capable of 62MHz bus speeds.
And sticking multiple things meant to be used concurrently on the same SPI bus is indeed idiotic when you have plenty of pins available.
There are never plenty of pins :-)
It just means you haven’t thought about all the gadgets that you can add to your project.
I would agree, though, with making it optional whether the peripherals share the bus or use different ones. Different strokes for different folks.
Worth it as proof of concept. Tft-Espi is the goto for reasonable small tft apps.