[HN Gopher] Introducing multitasking to Arduino
___________________________________________________________________
Introducing multitasking to Arduino
Author : pyprism
Score : 122 points
Date : 2022-08-02 16:22 UTC (6 hours ago)
(HTM) web link (blog.arduino.cc)
(TXT) w3m dump (blog.arduino.cc)
| dariosalvi78 wrote:
| I like the simplicity of setTimeout and setIntetval of
| JavaScript. Maybe something similar plus some mutex primitive
| (which JS doesn't need)?
| oconnor663 wrote:
| 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.
| xkcd-sucks wrote:
| I'm crappy at embedded development but isn't it pretty normal to
| handle "multitasking" with interrupts instead of using an event
| loop?
| gmiller123456 wrote:
| Not really, the processor has to be designed to support it that
| way to make it practical. With interrupts, execution can be
| interrupted at any point, and you have to be able to restore
| the registers to the correct state before letting the process
| continue from that point. It's technically doable, but with a
| chip that has only 128 bytes of RAM, you'll be pretty limited
| in how many processes you can run. Even Windows, prior to
| Win95, used the event loop style for multitasking.
| AnonymousPlanet wrote:
| > Even Windows, prior to Win95, used the event loop style for
| multitasking.
|
| Even? That's nearly the lowest bar regarding multitasking,
| compared to other OSes of the time.
| roland35 wrote:
| Interrupts work up to a point, but the correct way to do it is
| with an RTOS. Looking at the GitHub discussion it seems they
| are looking at mbed, FreeRTOS, or some other varieties too.
| sophacles wrote:
| Embedded can be a tiny little msp430 with RAM measured in
| bytes, or it can be the latest and greatest intel flagship -
| it's a description of how the chip is used more than the chip
| type.
|
| As CPUs get more powerful in general, so too do the little
| development boards. I can spend $10 on a board with multiple
| cores and megabytes of ram to drive my blinky lights and do
| wifi - that's enough power to run a full unix.
| baremetal wrote:
| where? where can i get one?
| dvh wrote:
| Esp32 boards has 2 cores and cost $5, works fine in
| Arduino. Try AliExpress.
| dvh wrote:
| I forgot to mention, blinky demo compilation take 60s on
| my PC, that's the only downside but maybe there are some
| workarounds.
| ge96 wrote:
| Showing some Teensy love, crazy the 4.0 has 600MHz base
| speed.
| Teknoman117 wrote:
| Is that a Cortex-M7 or something?
| ge96 wrote:
| Yeah that's what it says. I like it because it has so
| many connection pins eg. i2c/can be lazy.
|
| I have STM32 and Beaglebone too but have not used them
| yet.
| fermuch wrote:
| And can use up to 8mb of psram and 16mb of flash
| sophacles wrote:
| Well, there's a "hardware" link at the top of the linked
| article for starters.
|
| Or google "esp-32" to find store selling a very popular
| one.
|
| Or check out what's available on sparkfun or adafruit.
| Zardoz84 wrote:
| And/or using a RTOS. I remember using a RTOS on a PIC16/18
| family chip like ten years ago.
|
| But the most usual thing was knowing the precise timings that
| takes instructions and the peripherals to allow do multiple
| things at same time.
| qbasic_forever wrote:
| They're looking at this from a higher level for defining the
| API and programming model people will use to write event-based
| code. An implementation might run using interrupts and a timer
| to drive an event loop on a single core, or it might scale
| itself out to run on multiple cores where available like they
| mention.
| petsfed wrote:
| That's exactly what's described.
|
| Arduino's framework divides main() into two functions: Setup()
| and loop(), but they're essentially the same as whatever comes
| before the while loop, and the while loop itself, in a standard
| embedded c main function.
|
| Then you just have interrupts setting states, and the loop
| responds to the change in state.
| skybrian wrote:
| It's not quite the same as a while loop, because when you
| return from the loop() function, how long it takes before it
| gets called again isn't defined. Using arduino-pico, for
| example, it does some USB I/O handling (when using TinyUSB).
| If you write an actual while loop and don't return from the
| loop function often enough, you might starve the USB port
| implementation.
|
| This adds enough of a delay that I moved some code to the
| other core on the Pico to get precise timing.
| petsfed wrote:
| That's a fair point. I admit, I moved away from the Arduino
| framework pretty rapidly after embedded development became
| my job, well before I had to contend with everything else
| under the hood.
|
| I never ran into an issue of quasi-hidden behaviors like
| that, because I never pushed the thing that hard. It feels
| a little bit like the Arduino toolset (that is pre IDE 2.0)
| was designed to discourage people from pushing things that
| hard.
| skybrian wrote:
| Well, it's behavior specific to one board, and perhaps to
| TinyUSB. But it looks like Arduino has a yield function
| [1] that you can use to run periodic tasks if you write
| your own loop. And Teensy calls yield() between calls to
| loop(). [2]
|
| Since switching to VSCode and PlatformIO, I read the
| source more. (Arduino 1.x discouraged this due to not
| having easy ways to navigate between callers and
| callees.)
|
| [1] https://www.arduino.cc/reference/en/libraries/schedul
| er/yiel... [2] https://github.com/PaulStoffregen/cores/bl
| ob/master/teensy4/...
| OlaCh wrote:
| Energia IDE was a good example of multitasking for MCU. Here is
| an example:
| https://energia.nu/guide/foundations/programming_technique/m...
| ramary wrote:
| 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.
|
| 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.
|
| 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.
|
| 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.
| qbasic_forever wrote:
| This is the direction a lot of RTOSs go, for example Zephyr (ht
| tps://docs.zephyrproject.org/3.0.0/guides/portability/posi...)
| and FreeRTOS (https://www.freertos.org/FreeRTOS-
| Plus/FreeRTOS_Plus_POSIX/i...).
| ramary wrote:
| Thanks for sharing! I hope the Arduino teams heads in this
| direction as well.
| Tajnymag wrote:
| Threads are already supported by esp-idf on esp32
|
| source: https://docs.espressif.com/projects/esp-
| idf/en/latest/esp32/...
| Teknoman117 wrote:
| Do you know how the core scheduling works? Does it migrate
| tasks between cores? Is there any notable core to core
| migration penalty?
| ramary wrote:
| That's great, thanks for sharing!
| ge96 wrote:
| Sounds good. I was working on a project where I could not receive
| websocket info until I was done running servo commands.
|
| I know you can have multiple boards but yeah.
| andrewstuart wrote:
| async/await does not result in bloated code that is hard to
| maintain and debug.
|
| 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.
|
| 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.
| primitivesuave wrote:
| 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: int time = 0;
| int max_period = 10000; void loop() { if
| (time % 100 == 0) { everyTenthSecond(); }
| if (time % 1000 == 0) { everySecond(); }
| // ... time = (time + 1) % max_period; }
|
| 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.
|
| 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`.
| _whiteCaps_ wrote:
| http://www.calgaryfieros.com/OSGdocs/ECM-hacking.html
|
| The GM engineers used a similar approach:
|
| > The ECM hardware generates a periodic interrupt at 160 Hz.
| (Where have we seen that number before?) The entire ECM program
| operates off of this one interrupt. Except for some
| initialization code, there is no non-interrupt level code. In
| fact, the interrupt service routine never returns, it simply
| cleans the return address off the stack and waits for the next
| interrupt. There are no other interrupts in the ECM. This means
| that fully autonomous hardware generates all the high speed
| signals like the fuel injector and ignition pulses.
|
| > At each tick of the 160 Hz, various tasks are performed. Some
| are done every tick. Others only on just odd or just even
| ticks. There are also 16 tasks, one of which is performed each
| tick. Every tenth of a second, all 16 tasks will have been
| completed. In general, this means that the ECM cannot adjust
| engine performance faster than 10 times a second. Perhaps this
| explains the engine surging at low rpm that many list members
| have complained about.
| joezydeco wrote:
| That is spiritually what their Scheduler library is doing, as
| mentioned in the article. Which works for a lot of things just
| fine until one task begins to overrun its time slice or just
| hangs. And then you're looking into preemption.
|
| But if you're overruning an AVR micro maybe it's time to take
| the training wheels off and move up to a larger system.
| HeyLaughingBoy wrote:
| > move up to a larger system
|
| I'll take this one step further and suggest that beginners
| not start with the AVR, but instead with a Blue/Black pill
| (STM32) or ESP32. Leave the AVR for the more advanced people
| who are trying to squeeze every penny out of a project (even
| there, in many cases STM32 will cost less!!!).
|
| I visit the arduino.cc forums at least once every day and the
| things that beginners want to do these days is far more
| advanced than what they would have attempted even 10 years
| ago. It gets very difficult trying to explain how to do
| things on an AVR that would be much easier on a processor
| with far more resources. String vs char* is one of those.
|
| Hell, I don't know why we're even telling beginners to code
| in C++ in 2022.
|
| My downvoted comment that boils down to "just use an ESP32
| and get FreeRTOS along for the ride" is in this vein. The
| reality is that beginners have a _lot_ of trouble wrapping
| their heads around writing nonblocking code using timers and
| something like a FreeRTOS thread is a much simpler concept to
| explain.
|
| Rant over :-)
| botdan wrote:
| I'm a casual embedded-electronics user at best, most of my
| projects haven't advanced much past turn a simple servo,
| light some LEDs, maybe read a sensor and POST to an
| endpoint. For these tasks, Arduino has been pretty good for
| me and removed a lot of the complexity. The `setup()` and
| `loop()` model makes a lot of intuitive sense. That being
| said, I've spent no small amount of time on `String` vs
| `char*` (as an inexperienced C/C++ developer) and found the
| guardrails of the Arduino ecosystem to be very frustrating.
|
| Do you have any recommended resources or additional search
| terms to explore to learn more about hobbyist-level
| embedded electronics outside of the Arduino ecosystem?
| FreeRTOS looks interesting but it seems to add a lot of
| overhead versus something simple like Arduino. Similarly,
| I've looked at STM32 programming before but my searches
| were very generic and the STM ecosystem is massive.
| Specifically, I was trying to figure out if I could
| reprogram some old drone flight controllers (equipped an
| STM32F103CBT6 with a bunch of useful embedded sensors,
| running old versions of "betaflight") for personal projects
| but the entrypoint to STM programming (STM32Cube?) and the
| setup code was considerable.
| joezydeco wrote:
| I hear ya, I think we're just in a different era now. Users
| can wrap their head around a precooked framework that's
| ready to go and only needs a few API calls to make
| something happen. Beyond that? That's homework and homework
| _sucks_.
|
| FreeRTOS really isn't that large of a leap forward, in fact
| when it's done right on your target platform it's just a
| few API calls as well. But it means wrapping your head
| around a lot of detailed concepts (stack size? semaphores?)
| when all you want to do is light up that string of RGB
| LEDs.
| RealityVoid wrote:
| Stack size is a thing on Arduino as well.
| Teknoman117 wrote:
| It's funny - I stepped away from electronics when I started
| college and in the first few years out of it just due to
| not having enough free time. About a 10 year period.
|
| I come back and now AVR is old and slow and ARM is hot
| stuff. All it took was the tooling becoming nearly free. No
| more $500 ISP programmers, just USB DFU boot.
| sitzkrieg wrote:
| yea, usb dfu, better tooling and the price is nearly
| interchangeable. heck, small PDIPs are sometimes more
| expensive and less stocked
| Teknoman117 wrote:
| I remember the first ARM board I got back in like 2008
| required some Keil IDE which was >$1k for hobbyists and
| only had a 30 day evaluation included in the kit. Made by
| a company called Luminary Micro iirc. Builtin programmer
| was locked to only work with that specific chip. Never
| seriously considered ARM for a long while after that.
| dekhn wrote:
| I agree- I think just about everybody should start with an
| ESP32 instead of an Arduino. I still use the Arduino API
| when programming the ESP32 (due to the large amount of
| compatible drivers) but I've also installed FreeRTOS and
| ported zork. I am embarassed to say I also got C++ STL
| working on an AVR with 8k of ram- enough to allocate a
| std::vector<int> of length 2.
| gnramires wrote:
| I wonder if it's possible to just interleave statements from k
| different (loop) functions? Then it would seem mostly
| equivalent to an arduino at 1/k Clock speed.
|
| I think it's not possible to interleave instructions per se
| (because of registers?), but a compiler should be able to
| figure out the correct instructions of statement interleaving.
|
| This should eliminate problems with blocking.
| Teknoman117 wrote:
| Anyone know if a barrel-processor microcontroller exists?
| Propeller is sort of that way at least regarding main memory
| access.
| mikewarot wrote:
| I see an opening for a very good set of tutorials on how to avoid
| all the pitfalls.
|
| [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
| _change the laws of physics_ of the code.
| nyanpasu64 wrote:
| I find that Rust-like rules (&T across threads and &mut T
| within a thread, restricting cross-thread mutation to &Mutex<T>
| and &AtomicT, global variables are treated as shared) are the
| best approach I've seen so far to general multithreading (as
| opposed to structured subsets like message passing or
| structured concurrency, which I haven't explored as much).
| However I'm unsure if mutexes are incompatible or unnecessary
| with the majority of single-core Arduinos with cooperative
| multitasking, and treating global data as shared is a pain on
| embedded and binding them to a specific thread is not a problem
| Rust has solved yet (you'll have to find your own solution).
| HeyLaughingBoy wrote:
| Nice, but pointless addition to an old processor. ESP32's are
| cheap and readily accessible and they come with FreeRTOS running
| already.
|
| 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!
| sophacles wrote:
| In 2022 Arduino has several baords, many of which are NOT using
| atmega 328. Some of them have multi-core Arm chips, some of
| them have risc-v (not sure if they have any of those as multi-
| core though).
|
| There are already people running FreeRTOS on those.
|
| Not sure why you would dismiss multitasking on those as
| "useless".
| kevin_thibedeau wrote:
| Even on an AVR, you can implement lightweight cooperative
| scheduling with low resource consumption. That gives you many
| of the benefits of an RTOS with less risk of creating
| heisenbugs. Arduino should have broken free of its main-loop
| architecture long ago.
| francisduvivier wrote:
| Don't forget that a lot of people are using Arduino framework
| code on ESP32, it works pretty well.
|
| So this development is also relevant for those other boards,
| maybe even more so.
| HeyLaughingBoy wrote:
| Yup, and it's running FreeRTOS out of the box.
| atoav wrote:
| Yeah, the art students with miniscule coding experience who
| just want to get stuff done are probably going to be _thrilled_
| to work with FreeRTOS.
|
| The truth is, that Arduino always has put in a lot of work _to
| do things that could already be done_ only to make them more
| accessible, easier to use and thus more widely available.
|
| If you think this is pointless you should consider this might
| say more about how far you have come in your own journey than
| about the usefulness of that new feature.
| fmakunbound wrote:
| Forths such as FlashForth https://www.flashforth.com/index.html
| on the Arduino support multiple tasks .. in addition to including
| a compiler and interactive REPL
___________________________________________________________________
(page generated 2022-08-02 23:00 UTC)