Fast refresh rates up to 60fps with an SPI display (ILI9341)
-
Hey all,
check out this video about a proof of concept display driver for a SPI-based 320x240 TFT running Retropie games at up to 60fps refresh rate:
I wrote this project last weekend after I finally had time to sit down to get more acquainted with a Raspberry Pi and the SPI-based display I had to go with it, and was surprised by its bad performance. Searching the web, many people have complained the same issues, which is why I wanted to share this. The source code can be found here:
While developing this, it was interesting to realize that even though hardware limitations of the SPI bus are often cited as the issue for bad performance, it's not really that bad. Even still, I do recommend everyone stay clear of SPI, if HDMI is an option, because the GPU will handle the display in a dedicated manner.
At this point the project is more a tech demo rather than a maintained piece of software, for one because I did already get a couple of HDMI displays for my projects, but mainly because of this issue turned out to become a blocker. If you'd like to see power efficiency of your SPI based "framebuffer cloning" display driver get better in the future, consider giving that issue a +1 at GitHub - perhaps if it gets enough attention it might get more attention to get resolved soon.
I hope you enjoyed this!
-
@juj looking good!!! I have been using the ili9341 screens on my projects and they dont deserve the bad reputation they get really. I have played about with the settings and managed to get the basic fbtft and fbcp combo running reasonably well
im interested to learn how you are measuring your FPS? in your demo video, the sections you mention it being 16FPS looks much higher to me. I would expect much more stuttering (maybe its just me?) The only way i have been able to get any indication of FPS is to use the debug options within fbtft, which reports the time taken to fill each frame of the screen. best i can manage is about 33 before the screen starts to panic and just scramble
-
@moosepr Sweet project, looking to get to hardware building side of things soon as well :)
To measure fps, I applied this change to the rpi-fbcp driver:
diff --git a/main.c b/main.c index 7fb0d78..1feb3c2 100644 --- a/main.c +++ b/main.c @@ -7,6 +7,14 @@ #include <bcm_host.h> +#include <time.h> + +long long tick() { + struct timespec start; + clock_gettime(CLOCK_REALTIME, &start); + return start.tv_sec * 1000000 + start.tv_nsec / 1000; +} + int process() { DISPMANX_DISPLAY_HANDLE_T display; DISPMANX_MODEINFO_T display_info; @@ -72,10 +80,21 @@ int process() { vc_dispmanx_rect_set(&rect1, 0, 0, vinfo.xres, vinfo.yres); + long long lastPrint = tick(); + long long frames = 0; while (1) { ret = vc_dispmanx_snapshot(display, screen_resource, 0); vc_dispmanx_resource_read_data(screen_resource, &rect1, fbp, vinfo.xres * vinfo.bits_per_pixel / 8); usleep(25 * 1000); + long long timeNow = tick(); + ++frames; + long long duration = timeNow - lastPrint; + if (duration >= 1000000LL) + { + lastPrint = timeNow; + printf("fps: %f\n", frames * 1000000.0 / duration); + frames = 0; + } } munmap(fbp, finfo.smem_len);
Your video is definitely much more smooth than what I was ever able to get out of the rpi-fbcp driver (even with the usleep removed). Adafruit has fork of the repository that omits a top- and bottommost parts of unchanged pixels from the display update, which improved performance a little. I am running the display at 32MHz (SPI clock divider = 8, so 256MHz/8=32MHz), and I could not get clock divider 4 (64MHz) working on my display. This weekend I will hopefully get access to a logic analyzer to be able to take a peek at what's going on the line, to see if there are any more optimization opportunities available.
-
@juj thanks, that was my first real build, just playin with the zero. I have just fine tuned the settings really. fbtft is limited to 20fps by default unless you specify otherwise, and i have been messing with the speed settings and seeing how far i can push it.
The actual speed on the spi bus is linked to the core frequency, so if you up that, you can also get faster spi. you are of course limited by the screen. go too far and you get rainbowsnow
-
Had some time to do a few updates to the code, and created a new video to illustrate the driver program. This can be found at
Correcting two things from my previous comment - it turns out that CDIV=4 and CDIV=8 are not the only options, but CDIV=6 is also possible. Also, on the Pi 3, the BCM2835 chip runs at 400MHz instead of 250MHz, so CDIV=6 then corresponds to 400/6=66.667MHz.
Had access to logic analyzer, and also found out what other sources have documented, that sending each byte (8 bits) has an extra 1 bit idle time overhead on the bus when DMA is not used (which is not possible to be used in this update method), meaning that overall throughput is then a factor of 8/9 less, translating to theoretical maximum of 59.26Mbit/sec. In practice I find that the maximum I'm able to achieve is around 50Mbit/sec. The difference seems to be caused by that whenever a new display command is sent, there's an around one byte long stall to wait for the SPI FIFO to flush. Not too bad though, simpler games run well at 60fps progressive, and in the more complex ones the worst case performance was in Sonic the Hedgehog, which updated at 74fps interlaced at worst, i.e. the content updates at 60fps, where ~14 frames per second are progressive, and ~46 frames per second revert to interlaced.
-
@juj this new video does look pretty slick, not even a sign of shearing or tearing. My go-to test is super Mario world for the SNES. The speed of the feet in the intro video is a good sign of high fps
-
Hi Juj
I tried your driver's last night for raspberry pi 3. I am getting stuck on the step where it tries to apply resolution ratio between the HDMI and spi screen. The spi screen boots up with white colour nothing else but I can't type anything on the command prompt. If I force shutdown and restart spi screen doesn't even have white screen. Would you be able to help me with that? Thanks -
Hi EmulatedBen,
I suppose the above question predates the GitHub discussion on fbcp-ili9341 bug tracker, and you were able to get it working?
In any case, the code has been updated quite a bit since a month, and it now also works on Pi Zero and a number of other display controllers besides ILI9341, so may be worth rechecking if there still were some unresolved issues from before. Here is a recent video of the controller ported over to the dreaded 480x320 ILI9486 WaveShare 3.5" screen that is regarded to be really slow (it kind of is, Adafruit's HX8357D 480x320 display is about 70% faster than this WaveShare 3.5" 480x320, though some games run still great on it)
-
Just want to say thanks for this had a spare 2.8 inch screen doing nothing so decided to look into this and it runs great also i can confirm this works on pi 2's aswell as i replaced the driver on that one with this now im getting smooth framerates on that display thanks :D
on a side note does anyone know how to clear the display after shutdown as it stands the last thing displayed remains onscreen even after shutting down ie the console itd be nice to know how to blank the screen to know its safe to completly power off the device
-
Thanks, great to hear it works well! And also on a Pi 2.
I should be able to make the driver clear the screen once it is quitting, although that might not be enough from Linux perspective, because in addition it will require that fbcp-ili9341 is the last thing to shut down before the system shutdown operation itself finishes. Not sure how feasible that is to guarantee on Linux. I'm traveling this week, but I'll put this on a list to try out.
-
Updated fbcp-ili9341 today to clear the screen when it is quitting, and turn the backlight off as well if backlight control is enabled. Now if the fbcp-ili9341 process is killed e.g. with "sudo pkill fbcp-ili9341", it will turn off the display before going away. It should theoretically work to develop a shutdown script to kill the process manually at shutdown, which would blank the screen when the Pi is shutting off, though I did not test this far.
-
good work ill test this out once i have the time to sit down with my pi
-
I want to inform you guys that adjusting the screen brightness on this screens is very easy:
Connect LCD --> GPIO18
sudo apt-get purge wiringpi
sudo apt-get install wiringpi
gpio -g mode 18 pwm
gpio -g pwm 18 valuewhere value can be anything between 0 and 255 but you can also try higher values.
This is perfect for hooking up a poti or some buttons and let a python script run wich changes the brightness accordingly
You can also hook up your arduino to the LCD pin and useanalogWrite(LcdPin, value); // value can be 0-255
You will get a brighter screen using the Arduino, since the Pi only delivers 3,3V at PWM while the Arduino does 5V (I measured 4.6V and the image is slighty darker compared to using the 5V pin of the Pi)
Not sure if this will work on any pcb. I have exaclty the same one as in the video (
-
Hi.
Nice work @juj !!!Considering that this is my display datasheet ( http://www.lcdwiki.com/2.4inch_RPi_Display ), which options would you recommend to compile the script for a RPi Zero W?
-
May I request a more in-depth assistance in order to install this driver correctly since the installation guide on the linked GitHub page is super complex for a beginner builder like myself.
:((( I would love to get this up and running for my handheld Retropie Console project
Contributions to the project are always appreciated, so if you would like to support us with a donation you can do so here.
Hosting provided by Mythic-Beasts. See the Hosting Information page for more information.