Skip to content
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

Display refresh performance worse during first minute after device boots up #10176

Closed
FoamyGuy opened this issue Mar 24, 2025 · 11 comments
Closed

Comments

@FoamyGuy
Copy link
Collaborator

CircuitPython version and board name

Adafruit CircuitPython 9.2.6 on 2025-03-23; Adafruit Fruit Jam with rp2350b

Code/REPL

from displayio import Group
import supervisor

print("hello world")

main_group = Group()
display = supervisor.runtime.display

display.root_group = main_group

while True:
    pass

Behavior

As I'm working on the Fruit Jam animation (https://github.com/FoamyGuy/Adafruit_CircuitPython_FruitJam_Animation) I'm noticing that when the Fruit Jam boots up with with animation in code.py the rendering performance is noticeably worse than if I put the "blank screen" script above in code.py, wait for it to launch press ctrl-C to break to REPL, change the contents of code.py to the animation code, save it, then press ctrl-D to run it.

Description

No response

Additional information

This is when the rendering performs worse:

slow0_silent.mp4

And this is when it performs better:

fast0_silent.mp4
@FoamyGuy FoamyGuy added the bug label Mar 24, 2025
@eightycc
Copy link
Collaborator

eightycc commented Mar 24, 2025

Some of your memory allocations may be spilling into PSRAM for the slow case. Perhaps try building CP with PSRAM disabled? Commenting out this line in ports/raspberrypi/boards/adafruit_fruit_jam/mpconfigboard.h will disable PSRAM:

#define CIRCUITPY_PSRAM_CHIP_SELECT (&pin_GPIO47)

PSRAM accesses that miss in the XIP cache will be 10x slower than SRAM.

See #10125 for background on what's going on with memory management.

@FoamyGuy
Copy link
Collaborator Author

I tried this out, unfortunately the animation code runs out of RAM when I use a build with PSRAM disabled.

There is one version that loads the spritesheets into RAM and it runs out during the load of those sheets:

Traceback (most recent call last):
  File "code.py", line 217, in <module>
  File "adafruit_imageload/__init__.py", line 75, in load
  File "adafruit_imageload/bmp/__init__.py", line 96, in load
  File "adafruit_imageload/bmp/indexed.py", line 85, in load
MemoryError: memory allocation failed, allocating 215712 bytes

And another version that uses OnDiskBitmap instead which makes the animations run a little less smooth, but not as bad as depicted in the videos here. The OnDiskBitmap version makes it further, but does still run out of RAM while allocating alternate palettes to change the colors of the sprites.

code.py output:
Traceback (most recent call last):
  File "code.py", line 449, in <module>
  File "code.py", line 16, in make_alternate_platte
MemoryError: memory allocation failed, allocating 3520 bytes

So I think both versions must end up using at least some PSRAM. It does sound like a good theory that in the slow case something more "important" to displayio or the animated TileGrids is ending up in the slower PSRAM than in the fast case.

@dhalbert dhalbert added this to the 9.x.x milestone Mar 25, 2025
@FoamyGuy
Copy link
Collaborator Author

The latest version of the animation is pushed to https://github.com/FoamyGuy/Adafruit_CircuitPython_FruitJam_Animation

This version uses new sprites with a reduced color palette which has lowered the overall RAM usage. This does seem to have had a positive impact, but hasn't resolved it entirely.

With this version the behavior I see now is: With the animation saved as code.py, the device boots up and runs the animation with the slow / choppy graphics for about 1 minute, and then the next loop of the animation has smooth graphics which seem to continue smoothly indefinitely.

Once the smooth graphics have started if I do ctrl-C / ctrl-D the code will restart and the graphics are smooth from the beginning of that run.

If I press the reset button the board reboots and the ~1 minute of slower graphics run before getting back to smooth playback.

This 90 second recording starts just after the board boots up and runs through the minute of slower graphics and 2 loops of the smoother graphics at the end starting right around the 60 second mark.

slow_then_fast_silent.mp4

@dhalbert dhalbert modified the milestones: 9.x.x, 10.0.0 Mar 27, 2025
@FoamyGuy
Copy link
Collaborator Author

I am now able to test with the recomended #define CIRCUITPY_PSRAM_CHIP_SELECT (&pin_GPIO47) commented out to disable PSRAM with the newer sprites that are smaller than the previous ones. I confirmed with this that it worked:

>>> import gc
>>> gc.mem_free()
138448

I do still see the slower rendering for the first minute or so after a boot up with this build so I think perhaps this rules out the issue being related to storing assets in PSRAM.

@eightycc
Copy link
Collaborator

Agree, it's not PSRAM.

@FoamyGuy
Copy link
Collaborator Author

If I add time.sleep(60) before the main loop then the first time the animation runs it renders smoothly. I'm not sure what if anything that means, but I had the idea to try it.

@FoamyGuy
Copy link
Collaborator Author

I tested this with the EYESPI connector and a ili9341 instead of HDMI and I see the same behavior, 1 minute of slower choppy rendering, then smooth from that point onward until press reset button.

@FoamyGuy
Copy link
Collaborator Author

This is possibly not a core issue at all, or is something related to time keeping if so I believe.

It seems in the first few test runs at least that using:

time.monotonic()

instead of

adafruit_ticks.ticks_ms() / 1000

In the animation code makes this issue go away.

The rest of the code was written using seconds units so it was dividing the ticks_ms() value from adafruit_ticks to get to seconds. Maybe the division slows it down for the first minute for some reason? Or maybe there is something else going on with adafruit_ticks in the first minute. Theoretically the code could be re-worked to use ms instead of seconds and then it could be tested with ticks_ms() removing the division as a factor. If anyone believes that would be a worthwhile test I could try it but otherwise I'll probably just switch the code to use time.monotonic().

I'm going to test it out some more, and go back to the HDMI display to ensure that it's good there as well on boot up. If it is, then I pretty much consider this issue case closed. If anyone believes this behavior does actually point to a deeper issue within the core or adafruit_ticks, we can open a new issue or at least re-title this one.

@Neradoc
Copy link

Neradoc commented Mar 28, 2025

What do you use ticks for ? Ticks should only be compared to each other with ticks_diff/ticks_less etc.
You shouldn't divide ticks, only a ticks difference computed with ticks_diff.
They start with a high value so that it wraps around to 0 at the 65th second.

@FoamyGuy
Copy link
Collaborator Author

It was used to compare to each other, but not with ticks_diff and ticks_less. For example:

get timestamp:
https://github.com/FoamyGuy/Adafruit_CircuitPython_FruitJam_Animation/blob/main/code.py#L148

use it to get elapsed time and progress:
https://github.com/FoamyGuy/Adafruit_CircuitPython_FruitJam_Animation/blob/6ff0ca103be5dde37df80325045901a25e2a213d/code.py#L162-L163

which then go on to control where stuff moves to, or when it other things will occur.

@FoamyGuy
Copy link
Collaborator Author

I tested several more times on HDMI with 9.2.6, main, and 9.2.x UF2s from the S3 page, and all have run well and rendered smoothly.

It sounds like I was just misusing ticks_ms(). It wrapping around at the 65th second meant that my mis-use was more problematic during that window of time than after it wrapped. time.monotonic() seems to work fine so I'll stick with that for now.

@FoamyGuy FoamyGuy changed the title Fruit Jam display refresh performance worse depending on which code.py runs first Display refresh performance worse during first minute after device boots up Mar 28, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants