Time-slicing/stepping the MicroPython interpreter #19161
Replies: 3 comments
-
|
This capability would also be useful for pew-playdate, where I currently have to rely on a somewhat hackish implementation of coroutines because both the Playdate OS and my user-provided Python code assume they get to run the main loop. (The coroutines themselves work fine, but the solution is not ideal because 1. some OS functions exhibit weird bugs when called from outside the main thread stack, and 2. the Python thread is slow (probably) because its stack lies in slow external RAM and there is no clean way to get it in the same fast internal RAM as the main thread’s one.) If all you need is a periodic call to a function you control, that can be done within the VM, without having to have it in (user) Python code, using |
Beta Was this translation helpful? Give feedback.
-
|
Unfortunately a periodic function call doesn’t seem to be sufficient to get the eldritch magic in JavaScript workers to do its thing. I was hoping the “scheduler.yield()” would fix that, but it doesn’t seem to work how I’d expect. |
Beta Was this translation helpful? Give feedback.
-
|
Going back to the MicroPython side of the equation, it looks like the answer is to add a new kind of reentrancy to I can accomplish this by:
This requires cooperation from the caller, making Hacks so far: |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
At Pimoroni we've been having trouble with the Web Assembly port of MicroPython, since there is - insofar as I can tell - no means to yield from the MicroPython interpreter to allow sundry Javascript tasks to run (such as transporting offscreen canvas data and messages between a worker thread and the main thread).
In our case we want to let users loose on our web-based Badgeware simulator (https://github.com/pimoroni/badgeware-web/), which might involve code that blocks the thread, eg:
time.sleep()orwhile True. Currently if we control our code and call out from Javascript into a Python-definedupdatefunction we can get away with it and do things like inline code examples in our docs, running on a MicroPython interpreter (so the examples update/auto-regenerate as the docs change and can be interactive): https://badgewa.re/docs/api/algorithm.mdWe use
requestAnimationFrameto call a Python update function:https://github.com/pimoroni/badgeware-web/blob/e5c4131b42a762545c5e9b7df0d6d28b0c26938d/simulator/micropython.worker.js#L73-L82
And this function may or may not update the canvas via:
https://github.com/pimoroni/badgeware-web/blob/e5c4131b42a762545c5e9b7df0d6d28b0c26938d/simulator/micropython.worker.js#L60-L71
Another common way around this is to rely heavily on async-only code, which is great if you control the codebase in its entirety, or if your audience is developers, but antithetical to our synchronous, beginner-friendly badge API.
I've looked at Javascript's
scheduler.yield(), but I've had no success making it work how I want it to (perhaps because it fundamentally doesn't).What we think we want (albeit I'd love to be proven wrong) is some means to step the MicroPython interpreter by a certain amount of time, or cycles, or instructions, preserve the state and return. This way we could load our code, and pump the MicroPython interpreter in time slices, giving Javascript time to do its thing. Is this feasible? Am I missing an easier way to accomplish this?
(Note: On the real hardware we switched from calling an
updatefunction to letting users structure their apps how they prefer. Currently we preempt apps and return to the main menu by installing an interrupt on the Home button that hard reboots the device. Running multiple isolated interpreters and time slicing between them would give us the ability to run both system firmware and user code simultaneously, and interrupt the latter whenever we need. Again I knowasynceffectively does this, but it pretty much nails shut the door for beginners.)Beta Was this translation helpful? Give feedback.
All reactions