On a Pico W, EInkPIO may not be usable in a loop #10
-
There appears to be a known issue with the Pico W where some PIO instruction memory is not released; apparently for reasons relating to the wifi system. Calling the StateMachine() constructor repeatedly will result in an ENOMEM after a certain number of iterations. These issues address a manifestation of the problem: micropython/micropython#9003 and I'm using your library in a remote temperature/humidity display; it checks the sensor every few minutes and if it needs to, redraws the screen. After a a given redraw it calls .sleep(). The EInkPIO object is constructed locally to this function and so is GC'd afterward. To reinitialize the screen after a sleep it appears to be necessary to instantiate a EInkPIO object again, which constructs its ._sm StateMachine member in _pio_setup(). After a fairly small number of refreshes, the program dies with an OSError 12 on that line. For my use case I can get around this by simply using the Eink class instead. (I'm using generated images so the speed/memory difference when rotated isn't a problem; I can just use rotated images instead.) But without a way to restart the display after a .sleep() without instantiating a leaky-on-the-PicoW StateMachine, there doesn't seem to be a way to use EInkPIO in a loop on the W. |
Beta Was this translation helpful? Give feedback.
Replies: 3 comments 11 replies
-
Can you instantiate the EinkPIO object only once, outside of any functions and use it as a 'global' object (or pass it as an argument to the function)? That would fix the problem. Other possibility is to manually release the PIO program memory at the end of the function to make sure there's space for the next run. The issues you've linked to don't really apply here as you're not doing a soft reset between the function calls. Without the soft reset even if the StateMachine object gets deleted and collected, the program that it started still runs and takes instruction space. |
Beta Was this translation helpful? Give feedback.
-
I've tried your first suggestion, but after a sleep the EInkPIO object doesn't seem to be usable for drawing again; it just hangs when you try. Waveshare's docs says that to start using the display again after a sleep (assuming you're both referring to the same "sleep" mode) it must be reinitialized. Your lib doesn't have a public reinitialization function other than the constructor. (I may have spoken too soon anyway -- I'm now getting a MemoryError a few iterations in [sometimes!] while using EInk, so the OSError 12 (ENOMEM) on EInkPIO instantiation failure may simply have been a symptom of running out of memory some other way) Even more strangely it's difficult to reproduce. Trying to chase it down now but the inconsistency is bothering me: this is not a complicated program at all, and one really doesn't expect memory leaks in Python in the ordinary case anyway. I'll update when I know more) |
Beta Was this translation helpful? Give feedback.
-
Thanks again. Another question -- of the "just picking your brain" sort -- when/if you have a moment. Right now I've got it set to do a full screen refresh (non-partial write) every 24 partial writes. This is a fairly high multiple of what Waveshare suggests. But to be honest I'm really not clear on what problem one is trying to prevent by periodically doing a full rewrite every X writes. There is some suggestion of stuck pixels or something, but no real explanation of what the mechanism is or when and why it's a concern. At minimum I really only need to clobber the whole screen when the day changes (see the photo above for the application). I'm strongly tempted to eliminate the other periodic full screen rewrites entirely, as I really don't know what problem it's solving. |
Beta Was this translation helpful? Give feedback.
Yes, you're right about reinitialisation. I've updated the library to include a public reinit() method. After putting the screen to sleep make sure to call reinit() before next call to show().
As for the error when using EInk class it might be caused by memory fragmentation. The screen requires relatively large framebuffers, so recreating the EInk object several times and running other code in between might not leave enough contiguous memory for the buffers.