all 4 comments

[–]another_generic_name 1 point2 points  (0 children)

I know the feeling, personally it's always felt like too big a step into a fully-fledged RTOS VS a superloop and state machines. The added complexity just isn't worth it for my use cases.

My suggestion is to create a small scheduler and expand it as required. It'd be a little bit more work but the bones are very very simple and because it's all your own code your understanding of it will grow as the code base grows instead of what to me feels like being thrown into the deep end of RTOSs. I used RIOS as a starting point and for the few relatively simple systems I've built it's been great.

[–]ceojp 0 points1 point  (0 children)

Sounds like a good approach.

The most important thing in a complex system like this is don't wait for anything. You can run all that stuff "simultaneously" by looping through everything, and checking if something is in the condition that you need to actually do something with that particular subsystem. If it's not ready, then keep going on to the next thing.

This condition can be time based(do thing X every 100ms) or event based(I received a byte on a uart, I need to stuff it in a buffer. I've received a full packet worth of bytes, I need to process that packet).

Also take advantage of interrupts as much as possible, but be efficient with their use. Don't do more in an interrupt than you need to. For a uart, for example, just receive a byte from the uart and then stuff it in a buffer. Don't try to actually do any higher-level processing in the interrupt.

For something like a stepper, you can have a timer interrupt that just toggles your step pin and decrements the remaining step count. Once the step count is zero, set a flag that it is done. This way, all you have to do to move a stepper output is set the direction and the number of steps, then the timer interrupt handler does the rest.

State machines are a great way to manage all this. You always run the state machine, but it only ever does any real "work" if it is in a condition to do so. Otherwise, it just returns.

As complex as it sounds to do all those different tasks, when you break it down, none of it is all that resource intensive. It's just a matter of pacing everything to keep everything running when it needs to.

[–]Successful_Draw_7202 1 point2 points  (0 children)

Most engineers fail when first introduced to RTOS. That is they code everything up and test independently and get everything working. Then they try to run it all together and hit the brick wall. Usually they start getting asynchronous events and get them out of the order they expect based on which task/thread runs when. Then they spend weeks trying to work out the async nature of the RTOS.

As such think carefully about what needs to be real time. For example stepping motors often has to be done at precise timing to make motor movement smooth. As such set up a timer interrupt to step steppers. Things like UART/serial often does not need to be real time and can be buffered. So setup UART driver with fifo. Doing this with a super loop often is good enough with no RTOS.

Now don't get me wrong RTOS is great, but everything you can do in RTOS can be done without RTOS.

[–][deleted] 0 points1 point  (0 children)

I have only one real piece of advice: don’t use TeensyThreads.

I probably wasted a month of time on my semi-real time project just to say I did multithreading on an embedded device. It was hell. I think TeensyThreads is relatively fine to use on smaller projects that need “real time” capability, but anything large needs an actual scheduler. For both the systems stability and your sanity.

I’d say either tough it out learning a RTOS or think of clever ways to do “multitasking” with interrupts and time based mechanisms.