A true RTOS "owns" the CPU and hardware and interrupts, etc. So it's not like an optional library for your app. "RTOS", in this context, means something like FreeRTOS (popular freeware) that has its preemptive scheduler enabled. Each task in such an RTOS has its own MCU stack (RAM). Devices that interrupt must have drivers that are RTOS compatible. Etc.
FreeRTOS has a non-preemptive scheduler option (cooperative scheduler). Much simpler because the running task will not be preempted by another task and so mutual exclusion is not needed between tasks.
Most any other true RTOS has at least preemptive scheduling. A novice not aware of RTOS stack-per-task/preemptive scheduler should read, study, and not just dive in uneducated.
Some use the term RTOS for things that aren't either of the above. Beware.
Personally, I never do an overall design that relies upon task preemption. I've done so for 20 years of embedded work on MCUs. But I learned these principles of RTOSes on "minicomputers" (in a rack).
Instead of RTOSes, I've learned to design using finite state machines (FSMs). Very simple code. Very easy to desk-check design and code as correct (verify). A "superloop" calls each FSM in turn. If the FSM has no work to do, based on flags set in ISRs and elapsed time, etc., the FSM just returns. Otherwise the FSM does some brief work and changes its state variable so that next time it's called, it behaves differently.
FSMs are elegantly simple.
So my advice to small MCU users like Teensy and the like, is to avoid RTOSes whenever possible, after an educated decision is made on "do I really need the complexity and the risk-to-reliability of an RTOS?".
There are some cases where an RTOS is prudent, for sure. Usually in quite complex systems and preemption is essential for, e.g., low latency in processing that must be done after an interrupt but is too lengthy to do in the ISR.
Well, okay, yes. I understand a true RTOS basically covers up direct hardware access, and everything must communicate through it.
I am using FreeRTOS (specifically the arduino port of it by Richard Berry), probably should've specified that.
If I'm reading that correctly: You have a loop that checks if there's work to do, and if it does, it does that work. Instead of having a list, though, you had FSMs that all had their own jobs (which sounds like a cluster, but in one machine, to me.). This is essentially what I was originally implementing. Except instead of individual "blocks", I just had a list of numbers that were read off, and sent out as functions. Once their job was done, they were wiped off the list. If they had more work than can be done in one cycle, it would put itself back up onto the list with different arguments to let it know where it left off.
so it was actually 2 lists: one to be done THIS cycle, and one to be done next cycle. There's probably a better way to do it, but that's how I learned it in ASM.
If there was no work to be done, it would end nearly instantly.
However, this had the disadvantage of... I wasn't being reckless? It really had no downside other than I had to code everything with the idea of this overlooking stack that ultimately made most functions have to have a case statement of some sort in them. Also it would take up more memory for anything that needed more than a number 0-255 for its additional information. It was kinda cumbersome to work with, and was producing some awfully long code for straightforward functions (stuff that was supposed to just find 2 x-coords, and given a y-coord draw a line filling down the grid, waiting about 100ms between each y-coord, then again in reverse) were taking about 75 lines - while the version that just locked up the CPU would take 30 lines. Granted, I probably wasn't streamlining it as much as I could've.
Granted: I definitely don't need the power of a full RTOS, seeing how everything that I need to happen "simultaneously" is all my own functions, so I could probably clean up everything that I have, and build my stack system quite a bit cleaner. Probably to the point that I could use it over FreeRTOS, seeing how I likely won't be leveraging the whole power of it. However: it's also something I've never done before (I usually just program without thinking about the OS at all. The OS handles everything silently), and I'd like to try. I 100% started getting into microcontrollers simply because it was something new that I wanted to try.
I am a very optimistic person when it comes to my programming projects
Just getting an RTOS set up correctly to juggle multiple tasks at once is optimistic. Especially if timing is important.
Timing isn't SUPER important. just has to be within ~30ms if I were to run it super tight, but honestly, 250 of play will be common. The processor will be waiting a lot.
-which is good, because in my preliminary tests, the arduino FreeRTOS tends to give me about 20ms of drift, which is even within my tight standards.
In relation to your other post:
Long term storage always tends to be the slowest part of any process. It's a shame, but it's what we must live with for now.
Multi-core would be awesome for this, but I would need a minimum of 4 cores, and I would have to have them constantly communicating. Not a good idea for threaded work. Sadly not really a possibility. I probably will end up having a second microcontroller reading inputs, simply because I need a ton of inputs for this. Thinking my knockoff arduino mega would be perfect. So many pins to mess with. and hardware serial. and very cheap.
Tight timing issues like that are always going to be a problem. Back when cpu speeds and instruction times were completely predictable, you could easily pad out extra time. Now speeds fluctuate, and you tend to have an interpreter between you and the CPU, so getting really precise timings is difficult.
I recognise I'm taking on a HUGE learning curve, but it's not anything that needs to be done really any time soon (I'm aiming for early december for the entire project. code'll be made as needed), and that's basically how I program: I throw myself at it until it works, even if I have almost no clue how I'll actually do it. Maybe not the best way (okay, definitely not the best way), but it's the way I like to do it. There's really no risk in a personal project, and in a professional project I wouldn't be so unsure of the exact specs. I would know how everything was going to work and which libraries I would be using before I wrote a line of code. However: this is personal work, so it's a great time to learn new things.
Things I've discovered:
FreeRTOS is an SRAM hog. needed to clean up a lot of memory to get it to run without crashing. which is fine. It'll be running with a lot more SRAM than an UNO when I'm done. The UNO is just great for a quick test. Also one of the biggest SRAM hogs previously was my stack of stuff that needed to be done.
It takes up quite a bit of flash memory (~20% of an arduino uno = ~8,500bytes?), but I wasn't running into any problems with that. Still below 60% total usage
It makes my timings a bit more fuzzy (~10-20ms, perfectly fine for my usage. typically late, sometimes 1-2 early)
It actually needs a bunch of libraries to run properly (not really a problem as long as the compiler is smart enough to strip out unneeded items. I know, I'm a lazy programmer that relies on smart compilers nowadays so I don't have to remember that for(;
is more efficient than while(1) because the compiler compiles them exactly the same nowadays. again: professional projects I would care. Personal projects I don't.)
It doesn't impact the startup time at all (It gets into my code in the first ms - supposedly. I know millis() can't be trusted too much, but that's the time it gave to me) - although it DOES make the delay longer after that first loop, about 30-40ms -again, still acceptable for me
I know it seems like I'm completely disregarding everybody's advice, but I really am listening to all your criticisms. I understand it'll be difficult, I understand it's COMPLETELY overkill for what I want, I know I'll run into a ton of problems. However: I'm not doing this to make immaculate code. I'm throwing myself into this to learn some new things, do some problem solving, but ultimately to have some fun. Restrictions aren't fun unless they lead to interesting workarounds. As Cave Johnson said: "I'll be honest - we're throwing science at the wall here to see what sticks. No idea what it'll do. Probably nothing." and that is fine by me.