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

Slow LCD refresh may affect printing #1928

Closed
wavexx opened this issue Jun 17, 2019 · 5 comments
Closed

Slow LCD refresh may affect printing #1928

wavexx opened this issue Jun 17, 2019 · 5 comments

Comments

@wavexx
Copy link
Collaborator

wavexx commented Jun 17, 2019

Every 30 seconds we fully refresh the LCD. When running some complex GCODE (a good example would be a large area with >30% gyroid infill), the full lcd refresh is an operation that may delay enough to starve the planner.

I have found some reports in slic3r that mention this.
One example is this: prusa3d/PrusaSlicer#2065

Note that while the resolution of gyroid is high, it's not actually too high. You can easily reach the same level of complexity with some lattices, so I wouldn't "tune-down" gyroid.

If I manually disable the lcd refresh then I cannot easily manage to stop the planner anymore (gyroid keeps flowing without hiccups). I didn't look deeply into why the full lcd refresh is slow. Speeding it up, if possible, would be a good idea.

However a good interim solution would be to check for queued blocks before attempting to refresh the lcd. If the queue is less than half-full, skip the full refresh for a better time.

@leptun
Copy link
Collaborator

leptun commented Jun 20, 2019

Hi,

Can you please post a gcode / the settings which cause this behavior for testing purposes. Maybe even a video so I can be sure I know what I'm seeing.

So far I began rewriting some of the parts of the lcd library and maybe managed to make it faster. One problem I stumbled upon is what frequency the lcd chip is running at. In firmware is set to the slowest speed with extra safety delays. If prusa can confirm what frequency all the lcds run at, maybe we can make the timing tighter without breaking compatibility with slower lcds.

I also made changes so that when a command is sent to the lcd, it doesn't wait for the command to complete and continues to run the code, than if another lcd command is to be sent, it just waits till the previous command finishes processing and sends the next one and the cycle continues.

As for preventing the buffer from emptying, I made it so that if the ring buffer is at least half filled it reloads the lcd, but if it is not it just retries next update cycle. An exception to this is when the buffer is empty. If it weren't for that, then no lcd reset would happen and when not printing static electricity might kill the display.

I will post the changes when I come back (~2 weeks) and test them on my printer as there is a high chance I broke something in the lcd library.
As for code reduction, the code has gone from 234396 to 234184; 212 bytes saved, if you are curious.

One more thing I want to know: does the code use VT100 escape codes? If not, these could be removed to save flash space.

@wavexx
Copy link
Collaborator Author

wavexx commented Jun 20, 2019

The part that affects the planner while printing is lcd_refresh() and lcd_refresh_noclear(). lcd calls are slow in general, but lcd_refresh* call lcd_begin() internally which is the real killer.

Did you manage to improve this as well?

If you enable 7x7 mesh leveling, you will notice that it pauses briefly even with a simple G28 when the lcd is refreshed.

Yesterday after writing this I did some tests in order to avoid lcd_refresh using queued blocks as a metric, but it isn't sufficient. It seems that while printing gyroid a single lcd_refresh() call is enough to drain the entire queue from a full condition.

Using queued millimeters works better, but it has some corner cases I'd like to avoid.
I'm now attempting to calculate a rough estimate of the time queued instead.

@leptun
Copy link
Collaborator

leptun commented Jun 20, 2019

Both lcd refresh commands take a lot. In the moddified version I made the refresh quicker by not having unneeded delays. One big example is the 50ms delay at the begining of begin. That should be in init only as the lcd is never unpowered. Also changed to using defines instead of variables for 8bit/4bit interfaces as to reduce number of variables. As for the delay queuer, I don’t think it brings much improvement in speed, but is certainly better than using delays and blocking the code.

One more thing I changed that might make it faster is using fastio on all lcd pins. This way you have no arduino digitalWrite and pinMode in there.
Also removed RW pin support as there is no reason to have it on any printer.

I also noticed the 7x7 bed leveling stuttering sometimes, but thought it was because of something else.

How did using number of blocks queued work for you? And why are you trying to avoid using it? It is clear that the lcd refresh functions need to be made faster, but did you see any improvement with the queued blocks method?

Tou can test my changes right now if you want. The branch is MK3_Fast_LCD

@wavexx
Copy link
Collaborator Author

wavexx commented Jun 21, 2019

I had a look at the Fast_LCD branch, but I didn't try it yet. I'm finishing a large print now, but I love what I see.

I didn't see any change for lcd_begin, so I still went on to try to avoid calling lcd_refresh entirely. I think botch changes are orthogonal and go hand-in-hand.

Just skipping if the queue is full wasn't sufficient: if you had a lot of short segments the planner might only be able to run for a few milliseconds, causing noticeable stutter.

Calculating the total queued length ahead worked better, but it wasn't perfect either. To avoid pauses during gyroid infill I had to crank the minimum length to >5mm, which avoided refreshes on most moderately-complex models if you also use a complex infill (gyroid, but also hilbert/concentric/etc).

What I do now is calculate a very rough time estimate of the planner queue (just length / average speed) and skip the refresh if we have less than 250ms of queued moves. This approach works perfectly: it avoid refreshes during most moves planned by the FW (such as leveling), during overly-detailed sections and moves the refresh generally during outer perimeters, infill or long travels. I've been watching a complex print with 40% gyroid for several hours now and I cannot see the stalls I had before, but the lcd is still refreshed at least once per minute.

@wavexx
Copy link
Collaborator Author

wavexx commented Oct 20, 2019

Closing, see #1940

@wavexx wavexx closed this as completed Oct 20, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants