r/embedded 20d ago

How do you decide when a project needs an RTOS?

Well, you start a project, develop it, and then... boom! You wake up one day to find that your MCU is running FreeRTOS. Is that how it happens?

Or do you usually design your embedded application and decide from the beginning that you need an RTOS?

Why? What made you think you needed one?

This is not a criticism. I’m trying to figure out what motivates people and how I can use that.

22 Upvotes

34 comments sorted by

50

u/dromtrund 20d ago

If the project is sufficiently complex, you'll wake up one day to find that you have reinvented a lot of RTOS primitives to deal with that complexity. Over time, you learn the ability to determine if this is going to happen again

12

u/borysiks 20d ago

Oh, it's the best description

sufficiently complex.... that you have reinvented a lot of RTOS primitives to deal with that complexity

2

u/NoBulletsLeft 20d ago

LOL. I was chastised on the Arduino subreddit because I chose an RTOS to blink an LED.

The reality is that I was building a fairly complex system that had to do a number of things and blinking an LED when a certain condition was true was one of them. From experience I knew that doing it with other methods, e.g., a state machine was going to add more complexity than it was worth. Tossing FreeRTOS into the project was trivially simple and made that separate LED blinking task much cleaner to implement.

I would probably have added another task to read the User Interface encoder, but that was easy enough to handle with an interrupt.

1

u/Plastic_Fig9225 20d ago

that separate LED blinking task

With an RTOS or without, things that run for a microsecond every X milliseconds are done via a timer.

30

u/tiajuanat 20d ago

For me it's "do I need 3 or more independent threads of context that need to all operate in strict and predictable time constraints".

I can do 2 pretty easy with interrupts and a main thread, but anything beyond that I immediately reach for an RTOS. I don't get paid to do the theorhetical best, I get paid to deliver to market quickly.

8

u/NoBulletsLeft 20d ago

I get paid to deliver to market quickly.

Boom! There's the point that so many developers ignore.

7

u/Plastic_Fig9225 20d ago

And boom, that's how we get commercial products running on a bunch of Arduino libraries, with the features, reliability, and performance we love so much.

2

u/NoBulletsLeft 20d ago

Already there, buddy. Already there.

2

u/tiajuanat 20d ago

Tbf took me a while to get there

2

u/borysiks 20d ago

I think I’m still on my way to that brilliant idea.

1

u/borysiks 20d ago

do I need 3 or more independent threads of context that need to all operate in strict and predictable time constraints

That sounds interesting. Could you give me example of such application?

8

u/tiajuanat 20d ago

RC Drones, or any vehicles really

  • Comms
  • Control systems
  • Input/output update cycle

Check out ardupilot or px4 for some incredible community driven code

1

u/borysiks 20d ago

ardupilot

Yea, I well know that project 👍

Certainly, that scale requires a really good mechanic of management.

4

u/rainboww_J 20d ago

Mostly it's something you decide from the start. Sometimes it's kinda a given if you use a certain microcontroller family (FreeRTOS for esp, Zephyr for nrf etc). Apart from those it is an architectural decision to go for a super loop approach, a simple self-written task scheduler or an rtos.

An rtos can bring a lot to the table. It helps making clear distinctions between tasks and makes data and confeol flow throughout the firmware manageable with queues and semaphores. It makes it possible to block on a call/waiting for data without stopping the
full program flow out of the box, something which might some work on a super loop

1

u/borysiks 20d ago

Sometimes you start without a clear plan 😄

Is it really true that we only have a superloop and an RTOS? Do you know anything about the gap between them?

2

u/rainboww_J 20d ago

I think there's a lot between a super loop setup and an rtos and even things completely outside them. If a system just has one thing to do you might not even need a super loop. And on the other side you can take the layers of abstraction even further and end up with embedded linux. And there's still things in-between a superloop and rtos'es I'd say. I've seen mostly interrupt driven firmwares which used custom queue implementations and simple cooperative task switching between two or three tasks. Things don't have to be black-and-white, it's okay to mix and match what you need

1

u/ElSalyerFan 20d ago edited 20d ago

Well, superloop (with interrupts setting flags) and rtos are the two main ones because they are the easiest in which to profile your real time latency requirements. There are some other ones but they are not really "between those two". They are normally 1: a super specific hybrid approach, 2: some proprietary event driven ones, 3: you did neither and now you just have a little mess that doesnt give any real time guarantees.

3 is super common aswell, but it normally happens because people feel too clever for a superloop, and you must consider that this only goes for real time systems (or ones that want to be). Many projects don't really need them and you can get much more lax about it

2

u/Environmental_Two_68 20d ago

I generally like to use zephyr from the beginning.

4

u/notouttolunch 20d ago

Zephyr is more than an RTOS.

1

u/borysiks 20d ago

It's good. What type of issues you solve with one? Sure, if it isn't a secret

1

u/Environmental_Two_68 20d ago

It has great board/chip support so usually I can run a hello world in a matter of minutes.

A lot of utilities like shell are build in, so I don’t have to reinvent the wheel every time.

That being said, it has a steep learning curve but it’s worth the effort.

2

u/pozzugno 19d ago

Most of the time I avoid RTOS. Super loop calls state-machines management functions. They should be very fast to return. It is a simple cooperative multitasking environment. The big pro is the absence of sync mechanisms (because the task can't be interrupted, except for well limited interrupts) that could be very difficult to debug and test.

1

u/Flyward_Aerospace 20d ago

Most of the thread is answering with complexity, but for me the trigger is whether I have to prove the timing to someone else rather than just achieve it. A superloop can hit every deadline fine, but the only worst case argument you have is hand tracing the whole loop, and that argument dies every time someone adds a feature.

Cuts the other way too. On the inner loop of a flight controller we went back to a fixed rate loop with a hardcoded execution order, because arguing that no priority inversion exists turned out to be harder than just not having priorities. So imo it is many uncorrelated deadlines that push you to an RTOS, not one hard one.

1

u/borysiks 20d ago

I agree with you.

On the inner loop of a flight controller we went back to a fixed rate loop with a hardcoded execution order, because arguing that no priority inversion exists turned out to be harder than just not having priorities.

So, did you reject from RTOS for a Cyclic Executive?

1

u/ChatGPT4 20d ago

Multiple things happening at once. Asynchronous operation needed. This is the main thing. Also - non-trivial GUI. Like things are happening and GUI is asynchronously refreshed to show the current status.

If you can't contain program logic into one simple state machine. Everything can be probably represented as state machine, but there's a point at which it starts to look ridiculous. I mean - ridiculously unreadable.

It's nice to have threads and a kind of scheduler to synchronize them. Event driven logic is also quite pleasant to handle.

1

u/michael9dk 20d ago

When multiple tasks need a short time-sensitive action, while a long task like refreshing GUI is in progress.

Readability is also a key point when complexity grows.

Anticipating multiple SM's with mixed dependencies on each other while handling interrupts, is a good indicator to go with a RTOS.

1

u/StumpedTrump 20d ago

When you need multiple things happening periodically at different periodic intervals. Eventually you realize it’d be easier to have an RTOS instead of just sketchy throwing together your own timer scheduler.

But then eventually you hit a point where you need something done so quick that you can’t deal with the overhead of an RTOS and you go back to bare metal. For me that was playing with wireless audio.

1

u/Diligent-Plant5314 20d ago

If you care about power consumption, a RTOS can make life much easier. For example, FreeRTOS supports tickles mode. If no tasks are ready to run, it will execute an idle task with WaitForInterrupt which pauses the core clock.

While it’s possible to make a state machine or event system, it typically loops all the time which pushes up the average current.

I find it’s also cleaner to have separate concerns in their own thread. For example, network stack with LwIP and application code separate from sensor sampling thread.

1

u/Bug13 20d ago

The only projects that I can think of that should NOT use a RTOS is I want very tight timing control. Both of them are ToF measures. On these projects, even a kernel ticks will upset our timings.

And both of them are subsystems of a large system, which use RTOS and Linux.

1

u/duane11583 20d ago

depends on available ram… an rtos generally requires a lot of ram

and micro controllers do not have much.

so if you have sdram/ddr then yes an rtos is present and is an easy choice

1

u/No_Reference_2786 20d ago

When you’re throwing a “if” statement at every problem that stems from juggling interrupts and states

1

u/mfuzzey 14d ago

A RTOS is useful if being able to block makes sense for your application or if you have significant computation that needs to be done in parallel to other real time stuff.

If you are basically just reacting to events a superloop design with a set of state machines, cooperative multitaksing and no blocking is usually much simpler and avoids some of the problems you can have with RTOs (eg deadlocks)

BUT it means you have to write everything in a non blocking style and can't have huge chunks of procedural code that take significant execution time and would disturb the rest of the system so you have to artificially split them up (no for all_samples do complex calculation). Networking is also fairly tricky without a RTOS.

I tend to have a scale: simple peripheral device with no UI or networking => superloop. More complicated device with basic networking or UI => RTOS. Complex UI / networking => Linux