GregDMeyer / IT8951

Driver for the IT8951 e-paper controller on Raspberry Pi
MIT License
151 stars 55 forks source link

No response from pins when using sleep/run functions #26

Open anders999 opened 3 years ago

anders999 commented 3 years ago

I have an application where I run a Raspberry Pi Zero with driver HAT for the 10.3" e-paper from Waveshare. The whole thing is powered by a battery. Naturally I want the battery to last as long as possible, so I thought it would be a good idea to use the sleep/run functions. However, after a while (can be minutes or hours) the program freezes and I realize it's stuck in the wait_ready() function in spi.pyx waiting for a response from the driver. I tried running the program not using the sleep/run functions at all, but that also leads to a freeze eventually.

As a work-around I added a timeout in the while loop in wait_ready(), so I have the possibility to detect the freeze and restart the program. It doesn't solve the actual problem, though.

I would appreciate your thoughts on this! Thanks!

GregDMeyer commented 3 years ago

ah, I see! To be honest, I ported that functionality from the waveshare code, and haven't used it really, so I don't have much input to give. This might be helpful, though: if I have long-running applications (like I have a weather display that I update every hour), I usually don't keep the Python script running between updates. Instead, I have a one-off script that does the update, and then use another utility like e.g. cron to run that python script every hour. Obviously, I don't know if this is practical for your application, but maybe its helpful!

Let me know if you have any more insight into what is happening!

SirDagen commented 3 years ago

Hi anders

I run an https://www.waveshare.com/wiki/9.7inch_e-Paper_HAT on a Raspberry Pi 3 Model A+ and it runs for months without any problem. This is my code.

from time import sleep
from PIL import Image,ImageDraw,ImageFont,ImageOps
from PIL import ImageFile

from IT8951.display import AutoEPDDisplay
from IT8951 import constants
display = AutoEPDDisplay(vcom=-2.06)
epd = display.epd 
CONF_SCREEN=[epd.height, epd.width]

while True:
    escreen = Image.new('L', (CONF_SCREEN[0], CONF_SCREEN[1]), 255) 
    # output img
    display.frame_buf.paste(escreen.rotate(90, expand=True))
    display.draw_full(constants.DisplayModes.GC16)             
    epd.sleep()

    # sleep
    time.sleep(900)
    epd.run() # run again, after sleep

Are you sure the battery has enough power for the peak loads?

anders999 commented 3 years ago

Thanks for your input!

Yes I've tried using cron instead but since my program is a bit heavy it takes some seconds for it to start. I want to update the time each minute so it's not ideal. But I guess I could make a lighter script that only updates the time. The other part is a calendar where I check for updates more seldom, that would work just fine with a cron job.

The battery can deliver 5V/2.4A, that would be enough, besides the program freezes even though I have the Raspberry Pi powered by an ordinary power supply.

I ran the same script on another Raspberry Pi I have that is connected an e-paper like the one you have @SirDagen and there the script works fine. The difference is that I use an older version of the IT8951 code there. There the wait_ready() function is:

    def wait_ready(self):
        '''
        Wait for the device's ready pin to be set
        '''
        # TODO: should we sleep just a tiny bit here?
        while not bcm2835_gpio_lev(HRDY):
            pass

where as in the latest code:

    def wait_ready(self):
        '''
        Wait for the device's ready pin to be set
        '''
        while not GPIO.input(Pins.HRDY):
            sleep(0.001)

It's the same pin that is checked right? bcm2835 side or Raspberry Pi side right?

SirDagen commented 3 years ago

Mmmm. I ran all different versions of the code on my machine, never had any problems (only slight inconveniences with the early sudo necessity). Currently I run the latest without any problems so far.

GregDMeyer commented 3 years ago

Just wanted to check on this issue---did you end up getting it working, or figure out what the problem was?

anders999 commented 3 years ago

I don't know why, but for some reason the display freezes when I use the RPi Zero but not on a RPi 4. I tried both your older code as well as the newest. I haven't looked into it more than that. I have an acceptable solution now where I use cron to run a script periodically.

GregDMeyer commented 3 years ago

Ah---in fact, I may have an idea what is happening. I have found that sometimes the display gets stuck in wait_ready if there is a problem with communication with the device. For example, if the device is waiting to receive data that never comes, it will never signal that it is ready.

I suspect that it might have to do with the processor speed on the RPi Zero vs the 4---if the communication is too fast for the Zero to handle, it might not be able to keep up.

As a first try, could you perhaps decrease the SPI communication frequency. It can be set via a keyword argument for most of the communication functions; look for the spi_hz flag for AutoEPDDisplay (defined in display.py) or, if you're using the lower level interface, the cmd_hz and data_hz flags (defined in spi.pyx; you can pass them to the EPD class if you're using that). I would think that setting the frequency to 1000000 would certainly be low enough that the Zero should be able to handle it; if that doesn't work then I am probably wrong about the source of the problem.

Decreasing the frequency will make the display updates slower; if you get it working at 1000000 you can try then increasing it slowly to find the fastest value that works.

Let me know how it goes!! Thanks!

anders999 commented 3 years ago

Thank you for the input! I will try this when I get the chance and write here how it goes.