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

Screen stays white #3

Closed
MohammadMubin opened this Issue Feb 25, 2018 · 47 comments

Comments

Projects
None yet
4 participants
@MohammadMubin
Copy link

MohammadMubin commented Feb 25, 2018

Hello! i came across this page and i am wondering why my display is not working (ILI9341)
i have connected the D/C pin to 22 and rest to 3.3v
after running sudo ./fbcp-ili9341 my screen stays white ;-; but with FBTFT it works any help would be great :D

Thanks,
M.Mubin

@EmulatedBen

This comment has been minimized.

Copy link

EmulatedBen commented Apr 16, 2018

Hi mubin were you able to fix this issue?

@juj

This comment has been minimized.

Copy link
Owner

juj commented Apr 21, 2018

If you still have the hardware to play around with, it is possible that after 3a98d0d the issue might be fixed. I noticed that my PiTFT display was actually ignoring the chip select line, and always unconditionally communicated on the SPI bus independent of whether its CS was enabled or disabled. Recently I ported this to another display, which honors CS properly, and it too stayed white until the CS was applied to it.

@EmulatedBen

This comment has been minimized.

Copy link

EmulatedBen commented Apr 24, 2018

Juj I have manged to fix all the issues including auto start after reboot. it works perfectly. I cant thank you enough. I will do a video tutorial on your menthod to help others out, if you dont mind. A BIG THANK YOU!!!

@juj

This comment has been minimized.

Copy link
Owner

juj commented Apr 25, 2018

@EmulatedBen: Sweet, so great to hear!

I would love to see a video and the setup you are running with, that would be amazing. :) One thing to mention for possible users is the increased power consumption that the driver currently incurs, as something to keep an eye on as a drawback. I don't know how much more the Pi will consume energy with fbcp-ili9341 vs the original fbcp driver. It may be a negligible difference or a big one, but definitely something to measure if that is a big item in the project in question. It may be possible to reduce power consumption in the future with DMA transfers, but I have not yet been able to pull it off without sacrificing throughput performance (too much).

@MohammadMubin : I am fairly sure that this code block fixes the white screen problem, since this code was wrong (it configured SPI peripheral to take control the CS line, but in the SPI peripheral registers, we don't actually want to let it do that, but always keep CS enabled for the display).

I'll close this issue assuming it's resolved. If this still does not work for you, one thing that might be the cause is if there is a reset line on your display that needs to be enabled. Fore example my pitft 2.8 does not need such code, but a waveshare32b I've been running with recently does. It uses the following code: 3a98d0d#diff-eccee615a2b3ab684f0a041466726930R77 . If your display has a custom reset line that needs to be enabled, then you may need to adapt the above code for your purposes.

What I generally do to debug is connect to the Pi via SSH and run watch -n 0.1 gpio -g readall to observe what the IN/OUT and HIGH/LOW status of each GPIO register is, and cross reference the schematics of the display to see if the reset line is as needed.

@juj juj closed this Apr 25, 2018

@dotmick

This comment has been minimized.

Copy link

dotmick commented Apr 25, 2018

Hi,

I've got the same issue (white screen) using my lcd (NeoSec 2.8 inch TFT ili9341). I've tried freeplaytech_waveshare32b as well as pitft_28r_ili9341 with no luck :/

Thanks

@juj

This comment has been minimized.

Copy link
Owner

juj commented Apr 25, 2018

You will probably need to port the driver to customize for that display. Pinout diagram from http://www.neosecsolutions.com/products.php?78&cPath=20 suggests setting https://github.com/juj/fbcp-ili9341/blob/master/freeplaytech_waveshare32b.h#L8 to 24 or 23 (not sure what RS vs RST there is), and likely https://github.com/juj/fbcp-ili9341/blob/master/ili9341.cpp#L74 will need to be ported to tailor for that display.

@dotmick

This comment has been minimized.

Copy link

dotmick commented Apr 26, 2018

Hi @juj,

Thanks! I'll see if I can write it myself 😃

At the moment, I've found out that using RecalBox for my project (instead of RetroPie) with their own implementation of fbcp gives me the best results for now. I am still unhappy about the responsiveness of the screen: there's a tiny delay (<1s) from when I press a button to the actual screen update. But I don't know what else I can do...

I'll keep you updated about the driver.

@juj

This comment has been minimized.

Copy link
Owner

juj commented Apr 26, 2018

Interesting - did not know RecalBox had their own version. Digging out, looks like this is the optimization they did over to the original: ian57/rpi-fbcp@c1d05f8.

(not sure what RS vs RST there is)

It looks like RS is Register Select. That is what this driver call Data/Control pin, so that one corresponds to https://github.com/juj/fbcp-ili9341/blob/master/freeplaytech_waveshare32b.h#L6. RST is then Reset, or https://github.com/juj/fbcp-ili9341/blob/master/freeplaytech_waveshare32b.h#L8. So perhaps the needed change is

#define GPIO_TFT_DATA_CONTROL 24
#define GPIO_TFT_RESET_PIN 23

for NeoSec display. You also likely want to set all these to 0 as well: https://github.com/juj/fbcp-ili9341/blob/master/freeplaytech_waveshare32b.h#L16.

After that it is then a question of what the needed initialization sequence is.

@dotmick

This comment has been minimized.

Copy link

dotmick commented Apr 26, 2018

Gotcha, I'll try that.

About the sequence, is it not this one https://github.com/notro/fbtft/blob/master/fb_ili9341.c ? (which looks similar to https://github.com/juj/fbcp-ili9341/blob/master/ili9341.cpp#L74 no?)

@MohammadMubin

This comment has been minimized.

Copy link

MohammadMubin commented Apr 26, 2018

@juj @dotmick @EmulatedBen Hi! so sorry for not being active.I have broken both of my ili9341 displays so no i haven't been able to fix this :P I have ordered the ILI9488 SPI and wondering if that will work its 3.5" and perfect for my project.

@juj

This comment has been minimized.

Copy link
Owner

juj commented Apr 26, 2018

About the sequence, is it not this one

It is somehow peculiar that even with all these vendors coming up with "ili9341" displays, it looks like they are not all equal, but each display vendor still has their own, and sometimes undocumented, set of device initialization commands that need to be sent to the display. For example, the two ILI9341 displays I have that fbcp-ili9341 now supports are Adafruit's PiTFT 2.8" ILI9341 display and Waveshare's 3.2" ILI9341 display, but still in order to get them working, they need different initialization commands, as shown in here for Adafruit's one, and here for the Waveshare one. Browsing notro's fbtft repository, other ili9341 displays there have different initialization commands as well.

I have documented there the commands that are described in the ILI9341 Datasheet, but oddly, Waveshare needs some undocumented extra commands that I have no idea what they do. Those were taken from notro's fbtft repository, and they are not documented as part of the ILI9341 spec, or in fbtft - someone just contributed them there - possibly the original device manufacturer(?). Other displays that advertise being ILI9341 often also need custom initialization commands, so it seems that there is not one "pure" ILI9341 spec, but it seems that the hardware market is fragmented a bit there.

Although there is an off chance that these undocumented initialization commands are just garbage and don't really do anything and someone was misguided adding them into notro's fbtft repository (that's a bit doubtful though), I think I did not actually try deleting the undocumented ones from Waveshare32b initialization routine after I got the display working - might give that a try later.

After getting the initialization successfully over though, I have not seen discrepancies between the devices at runtime, but they all use the same documented ILI9341 pixel commands in SPI mode to send image data over.

@juj

This comment has been minimized.

Copy link
Owner

juj commented Apr 26, 2018

@MohammadMubin : no worries. Getting ILI9488 to work is definitely going to need some code changes. When you get the device, try cross-referencing between ILI9341 Datasheet and ILI9488 Datasheet to figure out what the differences are. Looking at the Table of Contents of both, many of the commands seem to be identical, so there is a chance that it might work with only small changes needed. DISPLAY_WIDTH and DISPLAY_HEIGHT at https://github.com/juj/fbcp-ili9341/blob/master/freeplaytech_waveshare32b.h#L10 will definitely need to be changed to 320x480 at least.

@juj

This comment has been minimized.

Copy link
Owner

juj commented Apr 26, 2018

I have documented there the commands that are described in the ILI9341 Datasheet, but oddly, Waveshare needs some undocumented extra commands that I have no idea what they do. Those were taken from notro's fbtft repository, and they are not documented as part of the ILI9341 spec, or in fbtft - someone just contributed them there - possibly the original device manufacturer(?). Other displays that advertise being ILI9341 often also need custom initialization commands, so it seems that there is not one "pure" ILI9341 spec, but it seems that the hardware market is fragmented a bit there.

Digging a bit further, I found a newer version v1.11 of the ILI9341 spec sheet at crystalfontz.com from 2011/06/10, whereas the earlier one I had was v1.02 downloaded from Adafruit servers. The newer spec sheet documents these missing initialization commands, but I have no idea whether this is about a different hardware revision, or if the newer spec sheet is just an updated documentation about also possibly earlier hardware (I hope so). Assuming the latter, the initialization routines between my two ILI9341 displays are now unified: c3db8e5.

@MohammadMubin

This comment has been minimized.

Copy link

MohammadMubin commented Apr 26, 2018

@juj i have altered the ardunio SPI Ili9341 parameters to ILI9488 before (but never got proper colour/color) .i hope to use these parameters of the program for the pi once the new display arrives.

@dotmick

This comment has been minimized.

Copy link

dotmick commented Apr 26, 2018

@juj nice one! Do I just need to create a .h file for the neosec lcd then?

@juj

This comment has been minimized.

Copy link
Owner

juj commented Apr 27, 2018

Yeah, you can go that route. Try first with either of the existing -DADAFRUIT_ILI9341_PITFT=ON or -DFREEPLAYTECH_WAVESHARE32B=ON build configurations as a basis, and see if you can get away with just overriding the GPIO pins to use, and if there are more things to customize e.g. in the init sequence, you can try creating a new #ifdef for that specific display.

@EmulatedBen

This comment has been minimized.

Copy link

EmulatedBen commented Apr 28, 2018

HI Juj
the video is live.
thanks again
https://www.youtube.com/watch?v=r1J0Hd-abVA&t=368s

@juj

This comment has been minimized.

Copy link
Owner

juj commented May 1, 2018

Very nice! Clear instructions and also great to see some games running on the display I haven't tried. Happy to see that the program works on other devices than Adafruit/Waveshare as well.

@dotmick

This comment has been minimized.

Copy link

dotmick commented May 1, 2018

Alright, so I've tried the following:

cmake -DCMAKE_BUILD_TYPE=Release -DILI9341=ON -DFREEPLAYTECH_WAVESHARE32B=ON -DGPIO_TFT_DATA_CONTROL=24 -DGPIO_TFT_RESET_PIN=23 ..

giving me this output:

Initializing display
Creating SPI task thread
InitSPI done
Relevant source display area size with overscan cropped away: 966x646.
Source GPU display is 1024x768. Output SPI display is 320x240 with a drawable area of 302x202. Applying scaling factor 0.31x, xOffset: 18, yOffset: 9, scaledWidth: 302, scaledHeight: 202
Creating dispmanX resource of size 320x240 (aspect ratio=1.333333).
GPU grab rectangle is offset x=9,y=19, size w=302xh=202, aspect ratio=1.495050

But the screen remains white :/

@dotmick

This comment has been minimized.

Copy link

dotmick commented May 1, 2018

And same result with:

cmake -DCMAKE_BUILD_TYPE=Release -DILI9341=ON -DADAFRUIT_ILI9341_PITFT=ON -DGPIO_TFT_DATA_CONTROL=24 -DGPIO_TFT_RESET_PIN=23 ..

@juj

This comment has been minimized.

Copy link
Owner

juj commented May 1, 2018

Hmm, sorry to hear, not quite sure what would be off. The second CMake line based on Adafruit display looks good, tough to say what would be wrong. The original notro/fbtft + dtoverlay -based method works ok? If so, then a way to debug may be to use

watch -n 0.1 gpio -g readall

to observe the communication on the GPIO pins when fbtft + original fbcp is running, to try to find which pins are carrying communication there, to double check the pins to rule out if the issue would lie there. The GPIO_TFT_DATA_CONTROL pin should be observed to semi-infrequently toggle state in the fbtft driver, and the GPIO_TFT_RESET_PIN should be HIGH at all times. Both pins should be in OUT state (they will boot up in IN state, and possibly LOW).

Another method may be to start out with the fbtft dtoverlay active in /boot/config.txt, and then sudo pkill fbcp after boot to kill the original fbcp driver, and then comment out the initialization sequence code in fbcp-ili9341, and run it without it doing initialization to see if it manages to work then. If that works, i.e. fbtft initializing + fbcp-ili9341 running on top of it, then it would suggest that the issue is somewhere in fbcp-ili9341s attempted initialization. If that doesn't work even then, it suggests some of the pins are probably wrong.

Also, it may be worth trying a slower bus speed setting at https://github.com/juj/fbcp-ili9341/blob/master/config.h#L60, such as 8 or even 10 to see if that has any issues. I don't know if all displays are able to run at speed 6, although my both Waveshare and Adafruit displays are able to. (smaller number means higher bus speed here)

@dotmick

This comment has been minimized.

Copy link

dotmick commented May 1, 2018

@juj thanks for your detailed answer!

Got some news. I've tried your second method (using fbtft initialization, commenting the init function in ili9341.cpp and starting fbcp-ili9341) and it does work!

Is there anything you'd like me to do to help understanding what the init sequence should be?

Note: this is the command I've used to initialize the screen:

sudo modprobe fbtft_device custom name=fb_ili9341 gpios=reset:25,dc:24,led:18 speed=16000000 bgr=1

@juj

This comment has been minimized.

Copy link
Owner

juj commented May 1, 2018

Ooh, that's cool progress!

That then confirms that the Data/Control pin must be correct, since it would not work to update the display if that was off. It is then likely that either the Reset sequence is giving trouble, or something in the initialization sequence itself is not quite right.

Double-checking the code out, I did notice ili9341.cpp was not sending 0x01 Display Reset and 0x28 Display OFF commands in the beginning of the initialization sequence. Added those at 80d2e67 as well as a print to make sure the GPIO reset sequence is actually being performed. Try out if that might have an effect.

If not, then try cross referencing with the existing ILI9341 initialization sequences in fbtft or ILI9341 application notes to see if you can spot a difference that might be relevant, and try adapting the ili9341.cpp sequences to pinpoint what would be needed. Different resources on the web have subtly different values for the initialization commands, so it's hard to know which exactly might be the important ones.

@dotmick

This comment has been minimized.

Copy link

dotmick commented May 1, 2018

I'll try your updated version thanks!

In the meantime, I've found this in main.c that was attached to an email I've received with my order:

void TFT_Initialize(void)
{
//TFT_RST=1;
//delay(100);
TFT_RST=0;
delay(500);
TFT_RST=1;
delay(250);
//************* Start Initial Sequence **********//
write_comm_data(0x0001, 0x0100); // set SS and SM bit
write_comm_data(0x0002, 0x0700); // set 1 line inversion
//write_comm_data(0x0003, 0x1030); // set GRAM write direction and BGR=1
#ifdef vertical
write_comm_data(0x0003, 0x1030); //1018
#else
write_comm_data(0x0003, 0x1018 );
#endif
write_comm_data(0x0004, 0x0000); // Resize register
write_comm_data(0x0008, 0x0202); // set the back porch and front porch
write_comm_data(0x0009, 0x0000); // set non-display area refresh cycle ISC[3:0]
write_comm_data(0x000A, 0x0000); // FMARK function disable
write_comm_data(0x000C, 0x0000); // RGB interface setting
write_comm_data(0x000D, 0x0000); // Frame marker Position
write_comm_data(0x000F, 0x0000); // RGB interface polarity
delay(100); // Delay 10 ms
//*************Power On sequence ****************//
write_comm_data(0x0010, 0x0000); // SAP, BT[3:0], AP, DSTB, SLP, STB
write_comm_data(0x0011, 0x0007); // DC1[2:0], DC0[2:0], VC[2:0]
write_comm_data(0x0012, 0x0000); // VREG1OUT voltage
write_comm_data(0x0013, 0x0000); // VDV[4:0] for VCOM amplitude
write_comm_data(0x0007, 0x0001);
write_comm_data(0x0007, 0x0020);
delay(200); // Dis-charge capacitor power voltage
write_comm_data(0x0010, 0x1490); // SAP, BT[3:0], AP, DSTB, SLP, STB
write_comm_data(0x0011, 0x0117); // Set DC1[2:0], DC0[2:0], VC[2:0]
delay(500); // Delay 50ms
write_comm_data(0x0012, 0x008E); // Internal reference voltage
delay(10); // Delay 10ms
write_comm_data(0x0013, 0x1900); // VDV[4:0] for VCOM amplitude
write_comm_data(0x0029, 0x0023); // VCM[5:0] for VCOMH
write_comm_data(0x002B, 0x000C); // Set Frame Rate
delay(500); // Delay 50ms
write_comm_data(0x0020, 0x0000); // GRAM horizontal Address
write_comm_data(0x0021, 0x0000); // GRAM Vertical Address
// ----------- Adjust the Gamma Curve ----------//
write_comm_data(0x0030, 0x0000);
write_comm_data(0x0031, 0x0406);
write_comm_data(0x0032, 0x0004);
write_comm_data(0x0035, 0x0405);
write_comm_data(0x0036, 0x0200);
write_comm_data(0x0037, 0x0407);
write_comm_data(0x0038, 0x0103);
write_comm_data(0x0039, 0x0707);
write_comm_data(0x003C, 0x0504);
write_comm_data(0x003D, 0x0000);
//------------------ Set GRAM area ---------------//
write_comm_data(0x0050, 0x0000); // Horizontal GRAM Start Address
write_comm_data(0x0051, 0x00EF); // Horizontal GRAM End Address
write_comm_data(0x0052, 0x0000); // Vertical GRAM Start Address
write_comm_data(0x0053, 0x013F); // Vertical GRAM Start Address
write_comm_data(0x0060, 0xA700); // Gate Scan Line
write_comm_data(0x0061, 0x0001); // NDL,VLE, REV
write_comm_data(0x006A, 0x0000); // set scrolling line
//-------------- Panel Control -------------------//
write_comm_data(0x0090, 0x0010);
write_comm_data(0x0092, 0x0000);
delay(100); // Delay 10ms
write_comm_data(0x0007, 0x0133); // 262K color and display ON
}

@dotmick

This comment has been minimized.

Copy link

dotmick commented May 1, 2018

@juj tried your last version but still doesn't work.

@juj

This comment has been minimized.

Copy link
Owner

juj commented May 2, 2018

Darn :/

That code you posted looks something very different from any ILI9341 initialization sequence I've seen. The lines in write_comm_data() read like the first value is the command byte, and the second one is a data byte for that command. However the data bytes here are 16-bit values, but the SPI protocol in ILI9341 is a 8-bit wide protocol, so either the above initialization is for a 16-bit wide SPI, or the 16-bit values are split to two parts.

Also, the comments refer to something completely different. For example,

write_comm_data(0x0001, 0x0100); // set SS and SM bit

suggests a command 0x01, but in ILI9341 spec sheet, command 0x01 is Software Reset. Likewise, the next commands 0x02 and 0x03 are not defined in ILI9341 spec. The comment on command 0x03 says "set GRAM write direction and BGR=1", which is an activity that does exist for ILI9341; the BGR vs RGB order and write direction are set via Memory Access Control command that is command 0x36, so I'm not sure how to interpret that initialization sequence in the context of ILI9341.

@juj

This comment has been minimized.

Copy link
Owner

juj commented May 2, 2018

Google search for some of the comments in the above initialization sequence find https://github.com/notro/fbtft/blob/master/fb_ili9325.c#L120, i.e. ILI9325 controller instead. I wonder if the above code does not actually apply to your ILI9341 display and they posted the wrong code, or if the display might actually be a ILI9325 after all, instead of ILI9341? ILI9325 has a register width of 16 bits, that is something I'm not familiar with, and may need bigger changes to port to.

If you do conclude that it is actually a ILI9325 display, then it looks like Adafruit has a spec pdf online for that display, so you could try cross referencing that against ILI9341 spec sheet to find how to port to ILI9325.

@dotmick

This comment has been minimized.

Copy link

dotmick commented May 2, 2018

Good catch.

My gut feeling says they sent me the wrong sample code. The screen is perfectly initialized with the fb_ili9341 from the fbtft drivers.

I will not have access to my screen before next week but I'll try to analyse the initializing sequence from the fbtft and compare it with yours.

@dotmick

This comment has been minimized.

Copy link

dotmick commented May 8, 2018

Got some update!

I've changed the line from:

cmake -DCMAKE_BUILD_TYPE=Release -DILI9341=ON -DFREEPLAYTECH_WAVESHARE32B=ON -DGPIO_TFT_DATA_CONTROL=24 -DGPIO_TFT_RESET_PIN=23 ..

to:

cmake -DCMAKE_BUILD_TYPE=Release -DILI9341=ON -DFREEPLAYTECH_WAVESHARE32B=ON -DGPIO_TFT_DATA_CONTROL=24 -DGPIO_TFT_RESET_PIN=25 ..

and now it works! (well, the screen needs a 180deg rotation)

I need to optimise it now.

@juj

This comment has been minimized.

Copy link
Owner

juj commented May 8, 2018

Really nice!

A special thing about -DFREEPLAYTECH_WAVESHARE32B=ON configuration is that it targets the FreePlayTech CM3/Zero devices specifically, which I got a couple to play with recently. Those devices use a 3.2" 320x240 display, but parts of the display extend under the edges of the visible screen display glass, and the practical usable resolution is about 302x202 pixels. When -DFREEPLAYTECH_WAVESHARE32B=ON is passed, the display resolution is reduced to 302x202, which probably is not what you are looking for. To skip this property, you can try instead of

cmake -DCMAKE_BUILD_TYPE=Release -DILI9341=ON -DFREEPLAYTECH_WAVESHARE32B=ON -DGPIO_TFT_DATA_CONTROL=24 -DGPIO_TFT_RESET_PIN=25 ..

to build with

cmake -DCMAKE_BUILD_TYPE=Release -DILI9341=ON -DADAFRUIT_ILI9341_PITFT=ON -DGPIO_TFT_DATA_CONTROL=24 -DGPIO_TFT_RESET_PIN=25 ..

which does not shrink the visible display size to a smaller rectangle. I think they should behave identically otherwise.

To apply a 180deg rotation, you can uncomment this line, i.e. change to

#define DISPLAY_ROTATE_180_DEGREES

and rebuild. That should make the display initialize with 180 degrees rotation.

Out of the box, performance should be the "fastest possible" when -DCMAKE_BUILD_TYPE=Release is used, so it should be expected that e.g. in Quake or another fast paced moving content, the driver should get up to about 50-60mbps peak transfer speed as shown in the statistics bar up top.

@dotmick

This comment has been minimized.

Copy link

dotmick commented May 8, 2018

Indeed, it works better with -DADAFRUIT_ILI9341_PITFT=ON, I do not have a black border at the bottom. The rotation is now done too.

Performance wise, I'm most of the time under 1mbps (peak at 2-3, low at 100kbps) running Retroarch (snes9x core) with Super Mario World :/

@juj

This comment has been minimized.

Copy link
Owner

juj commented May 8, 2018

Super Mario World and other NES and SNES emulator games don't have much moving content on the screen, so there you should be seeing 50fps PAL / 60fps if on NTSC, even if the on-screen display is showing low mbps transfer numbers. If there are no moving content on screen, then the FPS display will also go down, since dispmanx cannot distinguish new frames that did not change with respect to previous ones.

Try cross referencing against the YouTube demo video perhaps, to see how close performance is on some of the games shown in the detailed demo video. Also, you can try disabling DMA with -DUSE_DMA_TRANSFERS=OFF to CMake. That is very recent feature I added only a couple of nights ago, so not much tested yet.

@dotmick

This comment has been minimized.

Copy link

dotmick commented May 8, 2018

Thanks @juj, I'll check the DMA flag tomorrow.

After watching the video, there's definitely something wrong. I know you made the tests with a RPi B and that I have a Zero but I'm too far off your numbers/stats... I'll see what I can do.

@juj

This comment has been minimized.

Copy link
Owner

juj commented May 9, 2018

Oh, you are on a Zero? That will unfortunately not work, Zero has one core only, but fbcp-ili9341 utilizes a multiple threads that need to run concurrently, it is not currently feasible otherwise. (9926321)

@dotmick

This comment has been minimized.

Copy link

dotmick commented May 9, 2018

Makes sense. I'll stick with https://github.com/ian57/rpi-fbcp/ for now, that's the one which gave me the best results so far.

How DMA can improve performances on single threaded Pis? Could the use of interrupts help too?

@juj

This comment has been minimized.

Copy link
Owner

juj commented May 9, 2018

With DMA, the DMA controller does the communication with the display, rather than a thread on the main CPU. If enough work can be fed to the DMA chip at a time, then the main CPU is freed to do other actual tasks. Current master branch does utilize DMA, but it does not yet use enough of it (too small work slices). I have been working in https://github.com/juj/fbcp-ili9341/tree/dma_hacks branch to make the work slices longer so that the main CPU can be put to sleep, but not quite working yet.

Using interrupts can also help, but it's tricky. There does exist an interrupts based version in https://github.com/juj/fbcp-ili9341/blob/master/kernel/bcm2835_spi_display.c, but it does also need DMA, or otherwise the number of interrupts that fire is too large and the constant IRQ pre-emptions starve the main CPU from having time to do any real computation. After DMA is working, then it may make sense to also add interrupts to DMA.

@dotmick

This comment has been minimized.

Copy link

dotmick commented May 9, 2018

Thanks @juj

I'll keep an eye anyway and will make more tests when DMA will be working :)

@dotmick

This comment has been minimized.

Copy link

dotmick commented May 30, 2018

Hey @juj, I saw that you've made some work on the DMA, nice! If you need me to test anything give me a shout.

@juj

This comment has been minimized.

Copy link
Owner

juj commented May 30, 2018

Yeah, DMA, and also DMA task chaining are now implemented and enabled by default, and as result the driver also works on Pi Zero. NES emulated games are running at 60fps, although unfortunately due to raspberrypi/userland#440 there can be some amount of microstuttering that does not occur on Pi 3B. There is an option #define SELF_SYNCHRONIZE_TO_GPU_VSYNC_PRODUCED_NEW_FRAMES in config.h that you can try testing to find a middle ground with CPU usage and stuttering on the Pi Zero, although it feels a bit subjective as to what currently works best.

If you do have a Pi Zero setup at hand, it'd be great to hear how well the latest code works out for you!

@MohammadMubin

This comment has been minimized.

Copy link

MohammadMubin commented May 30, 2018

@juj

This comment has been minimized.

Copy link
Owner

juj commented May 30, 2018

I recommend you try it out yourself to see how much of an issue stuttering is. You can certainly remove the stuttering on Pi Zero with SELF_SYNCHRONIZE_TO_GPU_VSYNC_PRODUCED_NEW_FRAMES, but then CPU usage will be higher. Not so high that NES games for example still are unaffected, but e.g. noticed that SNES games started to slow down.

@dotmick

This comment has been minimized.

Copy link

dotmick commented Jun 7, 2018

Alright so a couple of tests on my RPi Zero. No optimization yet (no overclocking, no fbcp-ili9341 modifications,...). The only change is a lower HDMI resolution.

Super Mario
Super Mario
https://youtu.be/BqbzSgr1n_4

Sailor Moon
Super Mario
https://youtu.be/xEiDQl_rwHI

@juj

This comment has been minimized.

Copy link
Owner

juj commented Jun 7, 2018

Very nice!

To tune further, some things you can try:

For Pi Zero, interlacing can be a bit hurtful, so it's only good to use on the slower screens. I notice I disable interlacing on Zero by default only when CDIV=4 or better at https://github.com/juj/fbcp-ili9341/blob/master/config.h#L59, and I see you're running with CDIV=6, so that did not kick in automatically.

The second option reduces CPU usage on the Pi Zero at the expense of submitting more pixels. It can be a bit subjective as to which way is better, but certainly something to consider.

@juj

This comment has been minimized.

Copy link
Owner

juj commented Jun 7, 2018

To get a bit better bandwidth, you can try underclocking core_freq down from 400 to e.g. 300, and set CDIV=4 to get SPI bus speed of 300/6=75MHz, which should be enough to allow full 60fps (320x240x16x60=73.728MHz needed). If you run with SPI bus speed of 75MHz or better, then it's expected that #define UPDATE_FRAMES_IN_SINGLE_RECTANGULAR_DIFF would have no tradeoffs and is good to be enabled.

@dotmick

This comment has been minimized.

Copy link

dotmick commented Jun 8, 2018

So I've made a few tests based on your feedback.

First test

#define NO_INTERLACING and #define UPDATE_FRAMES_IN_SINGLE_RECTANGULAR_DIFF enabled.
Amazing performances. A few slowdowns but the best result so far.

Second test

(built on First test)

I've underclocked from 400 to 300 with #define UPDATE_FRAMES_IN_SINGLE_RECTANGULAR_DIFF enabled. Way slower than the previous test.

@dotmick

This comment has been minimized.

Copy link

dotmick commented Jun 8, 2018

Apologies, for Second test I've forgot to change CDIV to 4. Now it's done.

This is better that Second test (with CDIV=6) but still, not as good as First test.

@juj

This comment has been minimized.

Copy link
Owner

juj commented Jun 8, 2018

Good info!

Curious to hear that 400/6=66.67MHz worked better than 300/4=75MHz. Probably the performance in the applications you are running is Pi Zero CPU bound and even if there's more SPI bandwidth, underclocking hurts Pi Zero performance itself which then slows down the application so the extra SPI bandwidth does not help. You could try going the other way, i.e. overclock the core, although I do recall that if I tried to clock the core up even a bit from 400MHz to e.g. 401MHz, for some reason I was getting visual artifacts on the display, so that may or may not work well.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment