Re: When exactly do you choose to use a RTOS (instead of a non-OS approach)?

Mainly it's a question of complexity. If you need complex services, say networking, threading, UI, storage, there a lot to be said for an RTOS - getting those right is a ton of work, and you probably have better things to do. If you have a simple device, that needs only basic functionality, say there's only a limited amount of ROM based code, a couple of interrupts to handle, and mainly just interaction with whatever you're controlling, do without. There is, of course, a huge grey area between those two, and RTOS come in a number of levels of complexity as well.

Reply to
Robert Wessel
Loading thread data ...

In the past I worked with networking (lwip), UI (emwin) and storage (fatfs) without an RTOS, even if one at a time. All of them can be used with and without a RTOS. The "infinite loop" method worked well for these.

Maybe the only serious drawback I noticed is that MCU is continuously polling something. This isn't efficient if you need low power consumption.

Good point. Multi-threading is a good thing... but it's not simple to move from a "bare-metal" model to a "multi-threading" approach. You have to face unseen problems, like sharing resources among different threads.

Reply to
pozz

On Monday, December 11, 2017 at 8:19:31 AM UTC-5, pozz wrote: []

Both Mike and Robert made good points. You need to examine your requirements.

Was this in your loop application?

An RTOS may have features for low power that would be difficult to create in a simple loop implementation.

Yes it can be a little more work, but the Grand Do All Loop can have the other problem: Each routine in the given state is called whether it needs to execute or not. So you still may be delayed in getting to that one function that has to run NOW.

My point is, the design planning needed for multi-threaded RTOS is more complex, but how often have you coded a bare metal multi-threaded system. If you want the benefits of threading, there is a cost to pay. Overall, the system can be more efficient with a multithreaded RTOS.

One last comment: some folks gravitate automatically to the Do All loop. Don't choose that just because you think an RTOS is too much overhead (e.g. task swapping). In many cases, the overhead of an RTOS is a lot lower than you might think. and the brain power needed to program in an RTOS environment can be lower too.

I remember working on one system that you had to count the number of instructions you were executing between checkpoints because the Do All loop was trying to maintain a clock. A real pain to make changes!

So the pain can go both ways.

HTH, ed

Reply to
Ed Prochak

It can get fiddly ( especially with respect to shared resources between ISRs and "app space" ) but you can always divide things into control blocks and have one "thread" per control block. Each control block contains almost all the state for one "thread". "Almost" - you'll still need stuff to talk to ISRs.

This will work in or outside of an RTOS. If an RTOS offers a killer service - something that would be too expensive to recreate ( I'm thinking of power management ) - then you can migrate to an RTOS with a minimum of fuss. I'd suggest making the RTOS non-preemptive in that case.

And since you now have stuff partitioned into control blocks, might as well make it state machines. That way you can put code in to hedge race conditions and make it all truly event-driven.

Plus, out of hardware timers? Write a hardware timer-queue mux with callbacks.

And if you're careful with C++ compilers, the actual code looks suspiciously the same - the local state per thread is all class members rather than control_block[curblock]..

The main thing is how allocation is managed - what's the ctors()/dtors() story?

--
Les Cargill
Reply to
Les Cargill

I don't see how it's "unforseen". It's not much different than sharing resources among different interrupt routines and the foreground process in a "bare-metal" approach.

--
Grant
Reply to
Grant Edwards

An RTOS can be quite primitive.

Just allocate a private stack for each task and a small control block. The simplest system just used a 3 byte control bytes for each task, 2 bytes for the saved stack pointer and a single byte for the task state (mainly runnable/non-runnable bit).

After each interupt or system call, just scan the task status bytes in a fixed priority order to find the first task in runnable state, load that stack pointer and perform return from interrupt and off you go with the new task :-) .

A more elaborate design would check if the same task is going to continue after a system call and continue without doing a (software)interrupt register save/restore each time.

Reply to
upsidedown

It is if you have a good solid theoretical background with tools that implement the theory.

Start by having a single core dedicated to each I/O device, with many cores, and with a programming paradigm that lets all the cores communicate with each other.

Previous embodiment was the Transputer and Occam, current embodiment is the XMOS xCORE processors and xC. See DigiKey for pricing and pointers to the 30,000ft architectural overviews.

Effectively the RTOS is cast in silicon.

No interrupts; each core sleeps until there is something for it to do, e.g. input, output, or messages to other cores.

Add no caches and the min/max execution times can defined by the IDE examining the optimised object code.

All in all it is a surprisingly pleasant and mature system.

Reply to
Tom Gardner

I don't see a requirement for FSM's in any of those. ATM's (I assume you mean cash dispensers) just seem like they'd run normal business code. Cruise control sounds like a normal PID-like controller. I've written tons of comms code without FSM's. On the other hand, maybe your comm protocol involves checksums or error correcting codes. Doing those with FSMs would be straightforward in theory but ridiculous in practice.

Reply to
Paul Rubin

You appear to have a very limited definition of what constitutes an FSM. "Business code" often /is/ an FSM, even if it doesn't use some specific implementation techniques.

See, for example,

formatting link

Modes, dear boy, modes. Speed maintenance using a PID occurs in only one mode. You enter/exit that mode when different events occur, e.g. pressing buttons or brake pedals etc.

See, for example,

formatting link

It depends on what you mean by "comms code".

But any comms _protocols_ will have many states (e.g. connected, disconnected, idle, active, throttled, retransmission etc) and transitions between states will occur when defined things occur. That's an FSM however you code it.

Strawman argument; nobody has suggested that.

Reply to
Tom Gardner

Why would it be ridiculous to process the protocol frame with a state machine ? How do you process the frame in the ISR without a state machine ?

Especially in systems with user/kernel modes, processing the protocol frame in user mode byte by byte requires a large number of user/kernel/user mode changes for each byte, causing a lot of overhead.

By completely processing the protocol frame in ISR state machine, there will be only one user/kernel/user mode change for a full protocol frame.

Reply to
upsidedown

You'd need a ridiculous number of states to validate the checksum.

Reply to
Paul Rubin

Is 16 million states a ridiculous number ?

It fits nicely into 24 bits (3 bytes) state variable.

It is easier to visualize the situation by dividing these 24 bits into three separate byte variables, one is the actual state (such as Read_header, Read_data, Read_checksum, Done), the second byte is the remaining byte count and the third byte is the is partial checksum.

Stay in Read_data state as long as remaining byte count is greater than zero. For each byte received, store character into result buffer, add character to partial checksum and decrement the remaining byte count and if it drops to zero, change main state to Read_checksum.

When checksum byte arrives, check if it is the same as the (same/inverted/negated) partial checksum and set the main state to Done.

This also works for CRC calculations as well as delimited data without byte count. In principle the remaining bytes is then superfluous, but it is good to have it to check for too long message frames.

It might be a good idea to pack these three bytes into a 32 bit DWord, if it is visible outside the state machine to have atomic updates visible to the external world.

Reply to
upsidedown

It is ridiculous for people who think of state machines as a table of current state, event, action and next state (whether by case statement, table with function pointers, or whatever). It is /not/ ridiculous for people who think of state machines more generally and are happy to handle a whole set of states (like all values for your current checksum) in common code.

Reply to
David Brown

That's as stupid and unhelpful as suggesting that a TCP sequence counter should be implemented as an FSM!

It is unbalanced to insist on using a single implementation technique for all designs.

It is sane (and good practice) to select the implementation technique that most clearly expresses the design.

"Doctor, doctor, my head hurts when I bang it against the number of states" "Well don't do that then"

Reply to
Tom Gardner

The term "state machine" stops having any meaning, once generalized to include basically every possible program that doesn't allocate potentially unbounded amounts of dynamic memory during operation. I do believe we were discussing them in terms of state tables.

Reply to
Paul Rubin

To me and given the history of this subthread, coming from you that seems a bizarre and incomprehensible response.

I really don't understand what position you are trying to advocate.

Reply to
Tom Gardner

There are many problems like communications protocols that people in this thread have advocated solving with state machines, using a concept of state machines in which all the states and transitions are written out explicitly. My position is that while it might be *possible* to do those things with state machines, other methods are often preferable.

Reply to
Paul Rubin

/I/ believe the arguments going on in this thread are based on people having different but very fixed ideas about what a "finite state machine" actually /is/. Different people use the term in different ways

- there is no single correct definition. Some people think of them in terms of pure theory - you have a finite number of states, you have a finite number of events, and an event causes the machine to move from one state to another (usually in a purely deterministic way). Other people think of them in terms of implementation - whatever their particular favourite method might be (switch statements, tables with function pointers, etc.). With such a viewpoint, it is common to have some ill-defined limit of "practical size".

Once you realise that these (and many other) ways to define a "state machine" are valid, people in this thread can stop arguing and insulting each other and realise that you actually agree on many things. (Of course, that might spoil the fun!)

For my own viewpoint, I usually consider code to represent a "state machine" if there is one or more "state" variables of an enumerated type. These state variables will not hold the full state of the system

- there are usually other variables too. So a state machine for a protocol handler might have states for "idle", "getting header", "getting data", "getting checksum" and additional state information such as a counter of the bytes so far and a running checksum. Trying to store all the state in a table would be impractical - but it is still a finite state machine by the flexible definitions I use.

Reply to
David Brown

I thought the saying was that software is never truly finished until the last user is dead ;-).

I've started to look at some, thanks. He writes mostly about critical real-time systems, a niche area which is of course of special interest to c.a.e. (and to me). I can accept that some of those programs must have zero bugs, and accomplishing that requires special, ultra-rigorous methods and tools. But, I'd also say, that puts an upper limit on the complexity of the things that the software can attempt to do.

Other types of software must deal more directly with the real world, which requires accomodating the unbounded complexity of the real world, which in turn puts more complexity into the software than a pure formal approach can handle. That may prevent the software from getting the last epsilon of reliability, but that's ok, the real world isn't 100% reliable either.

Joe Armstrong likes to say that any non-distributed system is inherently unreliable, because the power cord is a single point of failure. Most of the programs that most of us write run on computers with a single power cord, so they can also withstand software practices that wouldn't suffice for critical realtime systems, but that can handle more types of real-world requirements.

Reply to
Paul Rubin

Ah. A strawman argument.

No more needs to be said.

Reply to
Tom Gardner

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.