A couple years ago, I managed a summer/afterschool program that introduced thousands of kids (age 8-18) to the Arduino. When we would set up a software abstraction to simplify multitasking (something that came up often with more advanced students), we set up something like this:<p><pre><code> int time = 0;
int max_period = 10000;
void loop() {
if (time % 100 == 0) {
everyTenthSecond();
}
if (time % 1000 == 0) {
everySecond();
}
// ...
time = (time + 1) % max_period;
}
</code></pre>
This `loop` assumes functions are perfectly non-blocking, which obviously is not always true, but works well for 99% of actual use cases. If keeping accurate time is required, the student would compare `time` with the elapsed millisecond time since the last loop invocation, adjust accordingly, and check for any periodic functions that weren't executed in that period. It gets tedious quite fast.<p>If I had to imagine a solution, it would be to simply have an easy way to enter parameters to the JS-equivalent of `setTimeout` and `setInterval`.
I'm crappy at embedded development but isn't it pretty normal to handle "multitasking" with interrupts instead of using an event loop?
In Rust there is <a href="https://embassy.dev" rel="nofollow">https://embassy.dev</a> which is an async Rust framework for embedded. It has been shipping in products for years. Can be made real-time (for some definitions of it).<p>There is also RTIC <a href="https://rtic.rs" rel="nofollow">https://rtic.rs</a> which is a concurrency framework for real-time systems using interrupts. IIRC the car industry is interested in it.
Forths such as FlashForth <a href="https://www.flashforth.com/index.html" rel="nofollow">https://www.flashforth.com/index.html</a> on the Arduino support multiple tasks .. in addition to including a compiler and interactive REPL
We've done quite a bit of experimentation with adding preemptive multitasking support to non-hard real time software running on MCUs at my current company.<p>After a lot of head banging and dead ends, I've come to the conclusion personally that the embedded community could really use an implementation of the POSIX threading APIs or some meaningful subset thereof for various platforms. They're already standardized, well understood/used, and aren't that hard to implement on an MCU.<p>Of course, there would probably be some semantics that wouldn't make sense to or may not be possible to implement on MCUs, and there would be work required to support different cores, but these tradeoffs seem better to me than reinventing the wheel and probably needing to make the same tradeoffs at some point down the line with a ground up new API.<p>For Arduino, exposing POSIX APIs wouldn't be very user-friendly. But wrapping something more user-friendly around them seems like a maintainable and extensible path for the project and community.
Energia IDE was a good example of multitasking for MCU.
Here is an example: <a href="https://energia.nu/guide/foundations/programming_technique/multitasking/" rel="nofollow">https://energia.nu/guide/foundations/programming_technique/m...</a>
ITT: Arduino people re-implement FreeRTOS badly.<p>Seriously, there are SO MANY mature, well-understood RTOS implementations for MCUs out there already, they really, really should just use one.
Synchronous programming is also a good choice IMHO to handle multiple concurrent activities in a simple way on an embedded system.<p><a href="https://github.com/frameworklabs/proto_activities" rel="nofollow">https://github.com/frameworklabs/proto_activities</a>
Sounds good. I was working on a project where I could not receive websocket info until I was done running servo commands.<p>I know you can have multiple boards but yeah.
async/await does not result in bloated code that is hard to maintain and debug.<p>It's a strange thing to say - async/await is now built in to most major programming languages - strange that Arduino would dismiss it so easily.<p>They are correct in that async/await does not solve multicore utilisation, but it's the most important and easiest way to implement parallelism on a single core.
I see an opening for a very good set of tutorials on how to avoid all the pitfalls.<p>[edit] - Actually... they have some good points, I just worry about someone thinking they can just "sprinkle threading" into their code, and failing to understand that in doing so they <i>change the laws of physics</i> of the code.
I wonder if async Rust would be a good fit for this use case? It doesn't solve the accidental blocking problem (although async-std did experiment with blocking detection at one point), but you can get transparent support for multiple cores and a lot of thread safety.
Nice, but pointless addition to an old processor. ESP32's are cheap and readily accessible and they come with FreeRTOS running already.<p>If I absolutely need to multitask on a Mega328 Arduino, I use the protothreads library. But really, for anything heavy, I'll turn to an ESP32 or an STM32. Use the right tool for the job!