waveshare / IT8951

57 stars 36 forks source link

Question about time to write Data to IT8951 Framebuffer. #2

Open tobiasaska opened 5 years ago

tobiasaska commented 5 years ago

Hello, I am working with Raspberry Pi 3 and the 10.3" Epaper Display from Waveshare. The refresh rate is very fast but the time to write the data from host frame buffer to IT8951 Frame Buffer is about 10 seconds. This is way to long for my application. Is there any way to make this process faster? Or can write multible images to different Frame Buffers on the IT8951? Has this to do with SPI interface?

JorgosCoenen commented 5 years ago

From my experiences, the size and detail of the image seems to make a difference. Converting the image to a C-file before or using the IT8951 bmp-conversion function doesn't seem to make too much of a difference. Experimenting with partial updates where you only have to push a select buffer size can also help.

For now, designing for e-ink screens still seems to require thinking around the limited refresh rate.

But curious if waveshare has any suggestions too!

tobiasaska commented 5 years ago

From my experiences, the size and detail of the image seems to make a difference. Converting the image to a C-file before or using the IT8951 bmp-conversion function doesn't seem to make too much of a difference. Experimenting with partial updates where you only have to push a select buffer size can also help.

For now, designing for e-ink screens still seems to require thinking around the limited refresh rate.

But curious if waveshare has any suggestions too!

Thank you for your reply. The problem does not seem to be the actual refresh rate which is around 450ms. The problem is the time to write the image from host frame buffer to IT8951 frame buffer. This takes 10 seconds using your demo code running on raspberry pi 3. For example when I use the demo program for windows providet by waveshare it doesnt take that long. How can I display a new image every 450ms or at least every second ?

JorgosCoenen commented 5 years ago

I'm not part of waveshare, so I'm not sure... We've also noticed that the Windows application seems faster. Are you pushing full resolution bmp's? Don't small images or graphics from the other demo functions go faster?

naluhh commented 5 years ago

I made it ~10 times faster by not using LCDWriteData but writing my own function that internally send all the data in one call. I also switched to 4BPP instead of 8 and made it again 2x faster. @tobiasaska

JorgosCoenen commented 5 years ago

That sounds amazing @naluhh! Any plans to share your changes? Would love to try them out!

naluhh commented 5 years ago

I made a quick test yesterday. I'm trying to make it even faster by extracting the picture directly into a 4bpp texture. I'm only planning on doing full screen updates. I'll share some code this week

tobiasaska commented 5 years ago

I made it ~10 times faster by not using LCDWriteData but writing my own function that internally send all the data in one call. I also switched to 4BPP instead of 8 and made it again 2x faster. @tobiasaska

@naluhh Thank you very much for this piece of information. Thats exacly what i was looking for. I am pretty new to coding. Would you mind sharing your code with me/us?

naluhh commented 5 years ago

https://github.com/waveshare/IT8951/pull/3

It's a work in progress. But you can try like this:

make
sudo ./IT8951 path_to_image.bmp
tobiasaska commented 5 years ago

3

It's a work in progress. But you can try like this:

make
sudo ./IT8951 path_to_image.bmp

Thank you! I will try this 👍

JorgosCoenen commented 5 years ago

Tried it just now. Very noticeable speed boost! Awesome! Thank you! I think you also managed to move to 4bpp? Anyway to also include 8bpp as an option? Or would that reduce the performance boost significantly? You mentioned that even with 8bpp your changes were much faster. My application has some images that require the higher resolution...

naluhh commented 5 years ago

@JorgosCoenen 4BPP is the maximum these screens can do anyway. Right now it's decoding the BMP in 8bpp and I then translate it to 4bpp. It would be much faster (less allocation, smaller file etc) to have a 4bpp image (png support it). I'm sure other optimizations could be done.

JorgosCoenen commented 5 years ago

Aha! What could than be causing the loss of image quality, if it's always 4bpp anyway? It kind if looks like anti-aliasing or interlacing. Just trying to understand :)

Here are some images: original, and update.

naluhh commented 5 years ago

Could you try to replace this line:

stLdImgInfo.usEndianType     = IT8951_LDIMG_B_ENDIAN;

by

stLdImgInfo.usEndianType     = IT8951_LDIMG_L_ENDIAN;
JorgosCoenen commented 5 years ago

Sure! Seems this makes the "interlacing" more pronounced. An image.

naluhh commented 5 years ago

What's the resolution of your screen?

JorgosCoenen commented 5 years ago

Ah, I'm using the 9.7" screen, so 1200x825. My images or also this resolution. I now notice that this repository only seems to refer to the 6" display... There doesn't seem to be one for the 9.7"🤨

naluhh commented 5 years ago

I'm using the 10.3" one. Odd number of pixels (y axis) might be the problem with your screen. Without access to the hardware it'll be hard for me to fix it. It was working well for me, probably an alignment thing. Meanwhile you can go back to 8BPP. (You'll need to comment the loop, remove the / 2 on buffer size, and switch 4BPP to 8BPP)

JorgosCoenen commented 5 years ago

Oh wow, hadn't seen that one, looks pretty great. Alright, looks back to normal (had to keep your "B_ENDIAN") and definitely still faster.

naluhh commented 5 years ago

A good chunk of the time goes into turning on the screen, and decoding the bmp image. Both of them could be reduced. Pre-uploading image you want might help too. (the buffer is big enough to store several images)

JorgosCoenen commented 5 years ago

Yeah, I keep the screen turned on in my application (added freeing the buffer to the bmp-function, instead of always using the cancel-function).

Does the library include anything to upload multiple images and switch between them? Would definitely also be an interesting hack.

naluhh commented 5 years ago

the library doesn't support that. Be carefull, don't leave it on too long, you might reduce the lifespan of your screen/controller

JorgosCoenen commented 5 years ago

Thanks for the heads-up! We have had them running for some long periods without noticeable impact so far. The only thing I've noticed is that sometimes the frame we built behind the screen become visible on the display if it's powered off (especially when in sun light). As if it's shining through.

naluhh commented 5 years ago

No doubt that you'll reduce your screen lifespan and greatly increase the consumption by doing so

naluhh commented 5 years ago

By decoding the image directly into the buffer, allocating only what's needed and optimizing and merging a few spi calls I was able to increase the speed even further. Depending on the raspberry pi you are using you might be even able to change the clock rate doing a 2x or 4x on the upload speed.

JorgosCoenen commented 5 years ago

Impressive! We've been using both Pi zero's and 3B+'s, depending on the processing/battery required. On the zero's this is probably not possible?

tobiasaska commented 5 years ago

@naluhh

Wow! You are solving all my problems I had working with the IT8951. You must have a lot of experience on this field. Thank you for sharing your improvements with us!

naluhh commented 5 years ago

Can you try to replace BCM2835_SPI_CLOCK_DIVIDER_32 by BCM2835_SPI_CLOCK_DIVIDER_16 then BCM2835_SPI_CLOCK_DIVIDER_8, BCM2835_SPI_CLOCK_DIVIDER_4(in the init func). (Keep going down until it stop working basically). Stay on the commit of my branch you were.

JorgosCoenen commented 5 years ago

Anything below 16 doesn't work on my Pi Zero (just a flicker in the top left corner). Slightly faster compared to at 32, yes! Don't have a 3B+ at hand right now, but I could try with that too.

Edit: this is still with the loop commented out and the 8bpp

naluhh commented 5 years ago

I'm curious about the result on the 3B+. Could you give me back the results you get?

naluhh commented 5 years ago

Also, if you don't care about accuracy, you could switch to 1 bpp buffer, which would divide the transfer duration by ~8 in your case

JorgosCoenen commented 5 years ago

Ok, did manage to test on a 3B+. Getting the same result as on the Zero, only a flickering rectangle in the top left corner with clock_divider below 16. This rectangle flickers and goes away , the previous image stays on screen. But again, definitely a speed bump with 16 instead of 32 and I'm not noticing any quality loss. Full resolution (1200x825) bmp images are pushed in ~1 second (excl. init time).

naluhh commented 5 years ago

You could also remove the line

EPD_Clear(0xff);

if you don't plan on showing partials image

JorgosCoenen commented 5 years ago

Yeah, thanks so much, this has been really helpful!

Do you think having the images converted into arrays and using the EPD_DrawMatrix() function would be faster than the Show_bmp() function? I didn't see much of an improvement when we did this on the original code, but maybe with your changes?

naluhh commented 5 years ago

I don't know, I personally switched to 4bpp png for performance/size reasons. (You can see the tip of my branch with libpng)

naluhh commented 4 years ago

I optimized the maximum I could. I think someone with more knowledge on the subject could go even further. For my resolution (1872*1404) I'm able to reach 0.9 sec / image. For 1200x825 I reached 0.63 sec / image. The buffer upload takes 60% of the time, so if you are able to pre-upload your images, or upload severals images at the same time you could reach higher speed (the other part, IT8951LoadImgStart, takes 40% of the time but I don't have any clue on how to increase it's speed).

JorgosCoenen commented 4 years ago

Really terrific results! Thanks again!

Could you say a little more about using png's instead of bmp's? I want to keep the same image quality (8bpp I guess), but using png's would really help our workflow and performance (I'm generating images in d3.js and having to convert them to bmp's in JS is not trivial for me and takes some time/processing power).

naluhh commented 4 years ago

As I said, 4bpp is the maximum quality you'll get. If I had access to your screen, I could certainly fix it. The tip of my branch works with 4bpp png as input. Here is a video with a loop decoding png + uploading to the buffer + updating the screen

test-video-gif-fdp

JorgosCoenen commented 4 years ago

Do you mean that the display will not go above 4bpp, or the input image png has to be 4bpp?

I'm trying your branch now.

I don't understand why, but one of my Pi Zero will not go below 32 for the BCM2835_SPI_CLOCK_DIVIDER. It messes up the initialisation at least. I noticed it before too, when I wasn't using your latest branch with the png, but was just trying the lower values.

sudo ./IT8941 test-4bpp.png "** IT8951 ** Panel(W,H) = (1784,829) Image Buffer Address = 19F1F0 FW Version = {8?;?9~ LUT Version = o<>9"

When I put it at 32, it initialized correctly, but still crashes afterwards (whole Pi becomes stuck): sudo ./IT8941 test-4bpp.png "init start ** IT8951 ** Panel(W,H) = (1200,825) Image Buffer Address = 11A1E0 FW Version = SWv_0.2.1T LUT Version = M841"

naluhh commented 4 years ago

I hardcoded my screen size, that's why (and also require a 4bpp png as input). The display is 4 bpp, therefore having an image higher than that is pure waste.

pshkvsky commented 4 years ago

@naluhh how do you create 4bpp png? could you please add some examples of files and the process. Thank you!

naluhh commented 4 years ago

I made a repo @pshkvsky https://github.com/naluhh/4bpp-converter/

nest000 commented 4 years ago

hey @naluhh .. you implementation regarding the socket stuff looks very promising, but i cant get it run. Can you provide a working example?

I could get the socketserver working and got also client connection messages, when i did:

nc localhost 8888 < ~/test-out.png

i got always the message that the file is not valid. i tried also to supply the filename only, but without success.

nc localhost 8888 < <(echo ~/test-out.png)

what do i wrong here? ;)

May thanks in advance!

naluhh commented 4 years ago

it's expecting a local path: ||Ufilename.png|| will make the client look for filename.png (4bpp png) and update it to the screen. If it doesn't have the file, it'll request it by sending a ||Dfilename.png|| to the server and expecting it to send it as png. It'll then cache it locally. I don't provide support for it, sorry

flashspys commented 4 years ago

You can convert any image to a 4bpp via imagemagicks's convert a.png -depth 4 b.png. I'm running @naluhh 's server, it's working really great!

aditya111222 commented 3 years ago

1) Can i Store the Multiple image Buffer into IT8951 2) Can i load the one image half half buffer into IT8951 and then after Display